CVE-2025-63811
Description
An issue was discovered in dvsekhvalnov jose2go 1.5.0 thru 1.7.0 allowing an attacker to cause a Denial-of-Service (DoS) via crafted JSON Web Encryption (JWE) token with an exceptionally high compression ratio.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
JWE tokens with extremely high compression ratios can cause a denial of service via resource exhaustion in jose2go before 1.7.
Vulnerability
In dvsekhvalnov/jose2go versions 1.5.0 through 1.7.0, the decompression step for JSON Web Encryption (JWE) tokens does not place adequate limits on memory allocation. By crafting a JWE token with an exceptionally high compression ratio — a "deflate bomb" attack — an attacker can cause the server to allocate an excessive amount of memory and processing time during decoding [1][2][3].
Exploitation
To exploit this, an attacker must submit a specially formed JWE token to a server that uses the jose2go library to decrypt and decompress the payload. No additional authentication is required if the server accepts JWEs from untrusted sources. The Proof of Concept in the issue tracker shows that a compression ratio of orders of magnitude can be achieved, leading to extreme memory consumption [3].
Impact
Successful exploitation results in a Denial of Service (DoS), as the server becomes unresponsive or crashes due to memory exhaustion. This affects any application using the affected library versions that processes untrusted JWE tokens [1][2].
Mitigation
The fix is included in jose2go version 1.7.0, which introduces deflate decompression memory limits. Users should update immediately to version 1.7.0 or later. No workaround is provided other than upgrading [1][4].
AI Insight generated on May 19, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
github.com/dvsekhvalnov/jose2goGo | < 1.7.0 | 1.7.0 |
Affected products
1- dvsekhvalnov/jose2godescription
Patches
10a0673dd7f28Merge pull request #34 from dvsekhvalnov/issue-33-deflate-limit
5 files changed · +188 −17
deflate.go+47 −13 modified@@ -3,37 +3,71 @@ package jose import ( "bytes" "compress/flate" - "io/ioutil" + "errors" + "io" ) +var ErrSizeExceeded = errors.New("Deflate stream size exceeded limit.") + func init() { - RegisterJwc(new(Deflate)) + // 250Kb limited decompression buffer + RegisterJwc(NewDeflate(250 * 1024)) } // Deflate compression algorithm implementation -type Deflate struct {} +type Deflate struct { + maxBufferSizeBytes int64 +} + +func NewDeflate(maxBufferSizeBytes int64) JwcAlgorithm { + return &Deflate{ + maxBufferSizeBytes: maxBufferSizeBytes, + } +} func (alg *Deflate) Name() string { return DEF } func (alg *Deflate) Compress(plainText []byte) []byte { var buf bytes.Buffer - deflate,_ := flate.NewWriter(&buf, 8) //level=DEFLATED - + deflate, _ := flate.NewWriter(&buf, 8) //level=DEFLATED + deflate.Write(plainText) deflate.Close() - + return buf.Bytes() } -func (alg *Deflate) Decompress(compressedText []byte) []byte { - - enflated,_ := ioutil.ReadAll( - flate.NewReader( - bytes.NewReader(compressedText))) - - return enflated +func (alg *Deflate) Decompress(compressedText []byte) ([]byte, error) { + enflated, err := io.ReadAll( + newMaxBytesReader(alg.maxBufferSizeBytes, + flate.NewReader( + bytes.NewReader(compressedText)))) + + return enflated, err } +// Max bytes reader +type maxBytesReader struct { + reader io.Reader + limit int64 +} + +func newMaxBytesReader(limit int64, r io.Reader) io.Reader { + return &maxBytesReader{reader: r, limit: limit} +} +func (mbr *maxBytesReader) Read(p []byte) (n int, err error) { + if mbr.limit <= 0 { + return 0, ErrSizeExceeded + } + + if int64(len(p)) > mbr.limit { + p = p[0:mbr.limit] + } + + n, err = mbr.reader.Read(p) + mbr.limit -= int64(n) + return +}
.github/workflows/go.yml+32 −0 added@@ -0,0 +1,32 @@ +name: Build and test jose2go project + +on: + push: + branches: [ "master" ] + pull_request: + branches: [ "master" ] + +jobs: + + build-and-test: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [windows-latest, ubuntu-latest, macos-latest] + version: ['1.20', '1.21', '1.22'] + steps: + - name: Checkout library sources + uses: actions/checkout@v3 + + - name: Set up Go + uses: actions/setup-go@v4 + with: + go-version: ${{ matrix.version }} + + - name: Build + run: go build -v ./... + + - name: Test + run: go test ./... +
jose.go+4 −2 modified@@ -140,7 +140,7 @@ type JwsAlgorithm interface { // JwcAlgorithm is a contract for implementing compression algorithm type JwcAlgorithm interface { Compress(plainText []byte) []byte - Decompress(compressedText []byte) []byte + Decompress(compressedText []byte) ([]byte, error) Name() string } @@ -427,7 +427,9 @@ func decrypt(parts [][]byte, key interface{}) (plainText []byte, headers map[str return nil, nil, errors.New(fmt.Sprintf("jwt.decrypt(): Unknown compression algorithm '%v'", zip)) } - plainBytes = zipAlg.Decompress(plainBytes) + if plainBytes, err = zipAlg.Decompress(plainBytes); err != nil { + return nil, nil, err + } } return plainBytes, jwtHeader, nil
README.md+16 −0 modified@@ -15,6 +15,8 @@ Extensively unit tested and cross tested (100+ tests) for compatibility with [jo Used in production. GA ready. Current version is 1.6. ## Important +v1.7 introduced deflate decompression memory limits to avoid denial-of-service attacks aka 'deflate-bomb'. See [Customizing compression](#customizing-compression) section for details. + v1.6 security tuning options v1.5 bug fix release @@ -997,7 +999,21 @@ test, headers, err := Decode(token, func(headers map[string]interface{}, payload }) ``` +### Customizing compression +There were denial-of-service attacks reported on JWT libraries that supports deflate compression by constructing malicious payload that explodes in terms of RAM on decompression. See for details: [#33](https://github.com/dvsekhvalnov/jose2go/issues/33) + +As of v1.7.0 `jose2go` limits decompression buffer to 250Kb to limit memory consumption and additionaly provides a way to adjust the limit according to specific scenarios: + +```Go + // Override compression alg with new limits (10Kb example) + jose.RegisterJwc(RegisterJwc(NewDeflate(10240))) +``` + ## Changelog +### 1.7 +- 250Kb limit on decompression buffer +- ability to register deflate compressor with custom limits + ### 1.6 - ability to deregister specific algorithms - configurable min/max restrictions for PBES2-HS256+A128KW, PBES2-HS384+A192KW, PBES2-HS512+A256KW
sec_test/security_vulnerabilities_test.go+89 −2 modified@@ -2,12 +2,18 @@ package sec_test import ( "crypto/ecdsa" + "crypto/rsa" + "encoding/json" "fmt" - "github.com/dvsekhvalnov/jose2go" + "strings" + "testing" + "time" + + jose "github.com/dvsekhvalnov/jose2go" "github.com/dvsekhvalnov/jose2go/arrays" "github.com/dvsekhvalnov/jose2go/keys/ecc" + Rsa "github.com/dvsekhvalnov/jose2go/keys/rsa" . "gopkg.in/check.v1" - "testing" ) func Test(t *testing.T) { TestingT(t) } @@ -93,8 +99,89 @@ func (s *SecurityTestSuite) Test_AAD_IntegerOverflow(c *C) { c.Assert(test, IsNil) } +func (s *SecurityTestSuite) Test_DeflateBomb(c *C) { + strU := strings.Repeat("U", 400000000) + strUU := strings.Repeat("U", 100000000) + + payloadMap := map[string]string{ + "U": strU, + "UU": strUU, + } + + payloadBytes, _ := json.Marshal(payloadMap) + + fmt.Println("Uncompressed payload length", len(payloadBytes)) + test, _ := jose.Encrypt(string(payloadBytes), jose.RSA_OAEP, jose.A256GCM, PubKey(), jose.Zip(jose.DEF)) + fmt.Println("Encoded & Compressed token length", len(test)) + + start := time.Now() + payload, headers, err := jose.Decode(test, PrivKey()) + timeElapsed := time.Since(start) + fmt.Printf("The `decode` took %s\n", timeElapsed) + + c.Assert(payload, Equals, "") + c.Assert(headers, IsNil) + c.Assert(err, Equals, jose.ErrSizeExceeded) +} + func Ecc256() *ecdsa.PrivateKey { return ecc.NewPrivate([]byte{193, 227, 73, 203, 97, 236, 112, 36, 140, 232, 1, 3, 76, 56, 52, 225, 184, 142, 190, 17, 97, 203, 37, 175, 56, 116, 31, 120, 95, 207, 196, 196}, []byte{123, 201, 103, 8, 239, 128, 149, 43, 83, 248, 210, 85, 95, 231, 43, 132, 30, 208, 69, 136, 98, 139, 29, 55, 138, 89, 73, 57, 80, 14, 201, 201}, []byte{84, 73, 131, 102, 144, 215, 92, 175, 41, 240, 221, 2, 157, 219, 49, 179, 221, 184, 171, 169, 210, 213, 21, 197, 1, 36, 101, 232, 23, 212, 169, 220}) } + +func PubKey() *rsa.PublicKey { + key, _ := Rsa.ReadPublic([]byte(pubKey)) + return key +} + +func PrivKey() *rsa.PrivateKey { + key, _ := Rsa.ReadPrivate([]byte(privKey)) + return key +} + +var pubKey = `-----BEGIN CERTIFICATE----- +MIICnTCCAYUCBEReYeAwDQYJKoZIhvcNAQEFBQAwEzERMA8GA1UEAxMIand0LTIw +NDgwHhcNMTQwMTI0MTMwOTE2WhcNMzQwMjIzMjAwMDAwWjATMREwDwYDVQQDEwhq +d3QtMjA0ODCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKhWb9KXmv45 ++TKOKhFJkrboZbpbKPJ9Yp12xKLXf8060KfStEStIX+7dCuAYylYWoqiGpuLVVUL +5JmHgXmK9TJpzv9Dfe3TAc/+35r8r9IYB2gXUOZkebty05R6PLY0RO/hs2ZhrOoz +HMo+x216Gwz0CWaajcuiY5Yg1V8VvJ1iQ3rcRgZapk49RNX69kQrGS63gzj0gyHn +Rtbqc/Ua2kobCA83nnznCom3AGinnlSN65AFPP5jmri0l79+4ZZNIerErSW96mUF +8jlJFZI1yJIbzbv73tL+y4i0+BvzsWBs6TkHAp4pinaI8zT+hrVQ2jD4fkJEiRN9 +lAqLPUd8CNkCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAnqBw3UHOSSHtU7yMi1+H +E+9119tMh7X/fCpcpOnjYmhW8uy9SiPBZBl1z6vQYkMPcURnDMGHdA31kPKICZ6G +LWGkBLY3BfIQi064e8vWHW7zX6+2Wi1zFWdJlmgQzBhbr8pYh9xjZe6FjPwbSEuS +0uE8dWSWHJLdWsA4xNX9k3pr601R2vPVFCDKs3K1a8P/Xi59kYmKMjaX6vYT879y +gWt43yhtGTF48y85+eqLdFRFANTbBFSzdRlPQUYa5d9PZGxeBTcg7UBkK/G+d6D5 +sd78T2ymwlLYrNi+cSDYD6S4hwZaLeEK6h7p/OoG02RBNuT4VqFRu5DJ6Po+C6Jh +qQ== +-----END CERTIFICATE-----` + +var privKey = `-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAqFZv0pea/jn5Mo4qEUmStuhlulso8n1inXbEotd/zTrQp9K0 +RK0hf7t0K4BjKVhaiqIam4tVVQvkmYeBeYr1MmnO/0N97dMBz/7fmvyv0hgHaBdQ +5mR5u3LTlHo8tjRE7+GzZmGs6jMcyj7HbXobDPQJZpqNy6JjliDVXxW8nWJDetxG +BlqmTj1E1fr2RCsZLreDOPSDIedG1upz9RraShsIDzeefOcKibcAaKeeVI3rkAU8 +/mOauLSXv37hlk0h6sStJb3qZQXyOUkVkjXIkhvNu/ve0v7LiLT4G/OxYGzpOQcC +nimKdojzNP6GtVDaMPh+QkSJE32UCos9R3wI2QIDAQABAoIBAQCUmHBvSkqUHaK/ +IMU7q2FqOi0KWswDefEiJKQhRu9Wv5NOgW2FrfqDIXrDp7pg1dBezgeExHLX9v6d +FAOTwbj9/m6t3+r6k6fm7gp+ao3dfD6VgPd12L2oXQ0t5NVQ1UUBJ4/QUWps9h90 +3AP4vK/COG1P+CAw4DDeZi9TlwF/Pr7e492GXcLBAUJODA6538ED2nYw8xQcbzbA +wr+w07UjRNimObtOfA0HCIpsx/6LkIqe6iGChisQNgt4yDd/fZ4GWOUIU1hqgK1P +6avVl7Q5Mk0PTi9t8ui1X4EEq6Uils45J5WkobuAnFkea/uKfs8Tn9bNrEoVWgdb +fBHq/8bNAoGBANKmjpE9e+L0RtxP+u4FN5YDoKE+i96VR7ru8H6yBKMcnD2uf5mV +RueEoL0FKHxlGBBo0dJWr1AIwpcPbTs3Dgx1/EQMZLg57QBZ7QcYETPiMwMvEM3k +Zf3G4YFYwUwIQXMYPt1ckr+RncRcq0GiKPDsvzzyNS+BBSmR5onAXd7bAoGBAMyT +6ggyqmiR/UwBn87em+GjbfX6YqxHHaQBdWwnnRX0JlGTNCxt6zLTgCIYxF4AA7eR +gfGTStwUJfAScjJirOe6Cpm1XDgxEQrT6oxAl17MR/ms/Z88WrT73G+4phVvDpVr +JcK+CCESnRI8xGLOLMkCc+5NpLajqWCOf1H2J8NbAoGAKTWmTGmf092AA1euOmRQ +5IsfIIxQ5qGDn+FgsRh4acSOGE8L7WrTrTU4EOJyciuA0qz+50xIDbs4/j5pWx1B +JVTrnhBin9vNLrVo9mtR6jmFS0ko226kOUpwEVLgtdQjobWLjtiuaMW+/Iw4gKWN +ptxZ6T1lBD8UWHaPiEFW2+MCgYAmfSWoyS96YQ0QwbV5TDRzrTXA84yg8PhIpOWc +pY9OVBLpghJs0XlQpK4UvCglr0cDwGJ8OsP4x+mjUzUc+aeiKURZSt/Ayqp0KQ6V +uIlCEpjwBnXpAYfnSQNeGZVVrwFFZ1VBYFNTNZdLmRcxp6yRXN7G1ODKY9w4CFc3 +6mHsxQKBgQCxEA+KAmmXxL++x/XOElOscz3vFHC4HbpHpOb4nywpE9vunnHE2WY4 +EEW9aZbF22jx0ESU2XJ1JlqffvfIEvHNb5tmBWn4HZEpPUHdaFNhb9WjkMuFaLzh +cydwnEftq+3G0X3KSxp4p7R7afcnpNNqfneYODgoXxTQ4Q7ZyKo72A== +-----END RSA PRIVATE KEY-----`
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
4News mentions
0No linked articles in our index yet.