Java vulnerabilities of the week: 9 to 15 October 2026
Every CVE arrives with a number and a severity, and if that is all you read you have learned nothing you can act on. What I want from a vulnerability is the mechanism: the field that was trusted, the lookup that ran twice, the check that was skipped. That is the part I can go and search for in code I maintain, and it is worth far more then the number beside it. It is why I write this up every week, and the reasoning behind the series is in the CVE stigma post.
This is the seven days to 15 October 2026, and one shape runs through most of it. A lot of this week’s bugs are a security check that looked carefully at one thing and then let the code act on a different thing. Apache CXF cached a “this token is valid” decision under a 32-bit hash and trusted the hash. Apache Fesod checked the address an image URL resolved to, then opened a connection that resolved it again. A CXF transport validated a TLS certificate chain and never looked at the hostname on it. In each one the gap is between what was validated and what was used. The two I pull apart below are the clearest examples.
The week in five
-
Apache CXF, eleven CVEs, disclosed 9 October 2026, fixed in 3.6.13, 4.1.9 and 4.2.4. CXF is the Apache web services framework: JAX-WS, JAX-RS, WS-Security, and the OAuth and OIDC pieces built on top. The batch falls into two groups. On the identity side,
CVE-2026-97468(important) is an authentication bypass where the STS token validator cached validated tokens under a 32-bithashCodeand treated a cache hit as proof the token had already been checked, so a crafted token with a colliding hash was accepted (first deep dive).CVE-2026-97791(moderate) let theSTSTokenValidatorshare validation state between requests, so one request’s result could leak into another.CVE-2026-71575is an OIDCmax_agefreshness check that did not take effect,CVE-2026-73179a non-atomic authorization-code consume,CVE-2026-79650an OIDC relying-party open redirect. On the XML and parsing side,CVE-2026-100227(moderate) is XML signature wrapping in the JAX-RS XML security interceptors, which did not confirm that the XML handed to the application was the part the signature actually covered.CVE-2026-107938(important) is the Netty HTTP client transport skipping TLS hostname verification: it validated the certificate chain against the trust store but never checked that the certificate named the host it was calling, and the defaultdisableCNCheck=falsedid not change that.CVE-2026-78384is a DEFLATE decompression bomb in JOSE/JWE and SAML processing, now capped at 10 MiB.CVE-2026-107937andCVE-2026-108039add limits on attachment headers and XML document size, andCVE-2026-86463is a FIQL query parser denial of service. Affected ranges are 4.2.0 before 4.2.4, 4.0.0 before 4.1.9, and anything before 3.6.13. -
Apache Camel Karavan,
CVE-2026-103412andCVE-2026-103413, both High, disclosed 9 October 2026, fixed in 4.22.1. Karavan is the low-code designer and runtime toolkit for Apache Camel, part of the Camel family I work in.CVE-2026-103412(CVSS 8.8) is a path traversal: when a project is committed to Git, the submitted file name was used verbatim as a path segment, so../in a name let any logged-in user write files outside the project directory, including settings or classpath files, which is code execution inside the Karavan container.CVE-2026-103413is improper input validation on deployment: Karavan applied every resource in a project’skubernetes.yamlto the cluster with no limit on resource kind, no fixed namespace and no rejection of risky pod settings, so any authenticated user could create privileged pods (host networking,hostPathmounts, privileged mode) within the service account’s reach. 4.22.1 restricts the committed path, limits applied kinds to an allowlist (Deployment, Service, ConfigMap, Secret, Ingress), forces each resource into Karavan’s own namespace, and rejects the risky pod specs. Reported by CyberLeo and MopMonk-AI, fix by Marat Gubaidullin. -
Apache Fesod (incubating),
CVE-2026-107460, moderate, disclosed 13 October 2026, fixed in 2.1.0-incubating. Fesod is the Apache spreadsheet library that succeeds EasyExcel and FastExcel. ItsUrlImageConverterfetches images from URLs an application accepts, which can be attacker influenced. A June SSRF,CVE-2026-49328, was fixed in 2.0.2 by resolving the hostname and checking the resulting address. The check and the connection each perform their own DNS lookup, so an attacker who controls the DNS answer can return an allowed address for the check and a restricted one for the connection: the SSRF protection is bypassed through DNS rebinding. 2.1.0 turns remote image fetching off by default and requires an exact-host allowlist. Only 2.0.2-incubating is affected. Second deep dive. -
async-http-client (AHC), around ten CVEs, CVE records published 7 to 12 October 2026, GitHub advisories 8 October, fixed across 2.16.1 on the 2.x line and 3.0.12 to 3.0.14 on 3.x. AHC is the Netty-based Java HTTP client. Most of the batch is cookie handling in the default
ThreadSafeCookieStore.CVE-2026-107226(medium, CVE record 12 October) did not record whether aSet-Cookiehad arrived over a secure transport, so it acceptedSecurecookies received over plain HTTP and let insecure cookies overlay or delete secure ones.CVE-2026-107228(medium) had the enabled-by-default store replace aCookieheader set explicitly throughsetHeaderoraddHeaderwhenever it held any cookie for the origin, so in a shared client the stored value could override what the caller passed.CVE-2026-107283(low) generated the HTTP Digest client nonce withThreadLocalRandomrather then a cryptographically secure source. The secure-cookie record is 12 October, inside the window; the GitHub advisories and the other records fall a day or two before it. -
lz4-java (
at.yawk.lz4:lz4-java), five CVEs, CVE records 6 October 2026, GitHub Advisory Database 7 October, fixed in 1.11.4. This is a widely transitive LZ4 compression library, the kind you inherit without declaring.CVE-2026-106451(high, 7.3) is a local temporary-file flaw:Native.load()created an exclusive temporary.lckfile, derived the native-library path by stripping the suffix, then opened that predictable path with aFileOutputStreamwithout exclusive creation, so another local user could win the race and plant the library that gets loaded.CVE-2026-106449(low) is a stack exhaustion:LZ4BlockInputStreamwithstopOnEmptyBlockfalse recursed throughrefill()for every empty block, so a long run of empty blocks overflowed the decoding thread’s stack. Three more are in the same batch. These were disclosed just before this window and reached the databases on 7 October.
Honourable mention for the RabbitMQ Java client (com.rabbitmq:amqp-client), CVE-2026-106121, CVE-2026-106122 and CVE-2026-106123, CVE records 6 October 2026, fixed across 5.35.0, 5.36.0 and 5.37.0. A JSON reader that did not stop at end of input looped forever on an unterminated string or comment, a short-string decoder turned malformed UTF-8 into replacement characters that could re-encode past the AMQP shortstr limit, and a failed AMQP URI parse put the raw URI, which can carry a username and password, into the wrapped exception and the logs. One dating note while you are triaging: Hazelcast CVE-2026-107725 and CVE-2026-107726 reached the GitHub Advisory Database on 8 October, but the repository advisory is dated 4 August, so that one is older than the listing date suggests.
Apache CXF: a cache hit is not proof of validation
CXF can sit in front of a Security Token Service, the WS-Trust component that issues and validates SAML tokens for a set of services. Validating a token is not cheap: a signature check, a trust decision on the issuer, sometimes a round trip to the STS itself. Doing that on every request when the same token keeps coming back is wasteful, so STSTokenValidator and the STS kept a cache of tokens they had already validated.
The cache was keyed on a hash of the token. The hash was a 32-bit value from Java’s ordinary hashCode machinery, Arrays.hashCode and hashCode(), with no cryptographic properties. And the code treated a hit in that cache as proof that the presented token had already passed validation. So the check became: compute the 32-bit hash of the incoming token, and if a token with that hash is in the cache, accept it.
A 32-bit hash has about four billion possible values, and hashCode is designed to spread entries across buckets, not to resist anyone trying to land on a particular value. An attacker who can get one legitimate validated token into the cache, or who knows one is there, can build their own token whose hashCode collides with it. The advisory gives two shapes: a UsernameToken, or a SAML assertion the attacker signed themselves. That crafted token hits the cache, and because a hit stands in for the real check, it is accepted with no password verification, no trust decision on its signature, and no contact with the STS. From there the attacker is authenticated as whoever the colliding entry belongs to, and by calling the STS validate and renew operations they can get tokens the STS signs for that identity.
The fixed releases are 4.2.4, 4.1.9 and 3.6.13. The advisory points you to the upgrade and does not publish the code of the change, so I will not guess at the new key beyond that.
Why I find it interesting
The class is improper authentication, CWE-287, reached through a security decision that relied on a value an attacker can forge, which is the territory of CWE-807. Two lessons come out of it.
The first is narrow and worth saying plainly: hashCode() is a bucket selector. It returns a 32-bit int, it makes no promise about collisions, and for many types an attacker can influence it. It is not an identity and it is not a token. A cache that records “this credential was validated” has to be keyed on the credential itself, or on a cryptographic digest of it, so that a hit means the same bytes and not merely the same 32-bit number.
The second is the general one, and it is the theme of the week. A cache placed in front of a security check becomes part of the security boundary. If a cache hit lets you skip the check, then producing a cache hit is exactly as powerful as passing the check, and the key has to be as hard to forge as the check is to pass. Here the check was “is this token genuinely valid” and the thing actually tested was “does this token’s 32-bit hash match an entry”, and those are not the same thing. When you cache the result of an expensive validation, the question to ask in review is whether the cache key is the thing you validated, or a cheaper stand-in that someone else can choose.
Apache Fesod: the address you check is not the address you connect to
Fesod reads and writes spreadsheets, and one of its features embeds images that a spreadsheet references by URL. UrlImageConverter takes a URL, fetches it, and drops the bytes into the sheet. If any part of that URL comes from data your application did not fully control, the fetch is a server-side request you did not mean to make, which is SSRF: the classic targets are cloud metadata endpoints like 169.254.169.254 and internal services on 127.0.0.1 or the private ranges.
That was reported in June as CVE-2026-49328 and fixed in 2.0.2. The fix resolved the URL’s hostname and checked the address it pointed at before allowing the fetch. The problem this week, CVE-2026-107460, is that the validation and the connection are two separate acts, and each resolves DNS on its own. The converter resolves the hostname, inspects the address, and decides it is allowed. Then it hands the original hostname to the HTTP client, which resolves it again to open the socket. Between those two lookups the answer can change, because the attacker owns the name and can serve a different record to the second query: a public, allowed address for the validation, and 169.254.169.254 for the connection. This is DNS rebinding, and it is a time-of-check to time-of-use gap (CWE-367) wrapped around an SSRF (CWE-918).
The fix in 2.1.0-incubating changes the posture rather than pinning the lookup. Remote image fetching is now off by default: an empty allowlist means the converter makes no network call at all. When an application does want it, it has to pass an explicit allowlist of hosts through allowedHosts(...), matched exactly, with no implicit trust of subdomains, wildcards rejected, and the allowlist validated before any DNS lookup, with each redirect hop checked again. Private-host and private-range checks remain. If your code uses UrlImageConverter with remote URLs, upgrading will stop the fetches until you opt back in, so its worth finding those call sites before you bump the version.
Why I find it interesting
DNS rebinding is one of those bugs that reads as obvious once you see it and is easy to ship anyway, because the validate step and the use step are written as separate lines and a hostname looks like a stable thing. It is not. A name is a question you ask DNS, and you can ask it twice and get two answers. So resolving a hostname to validate it, and then connecting by the same hostname, validates nothing about the connection: you checked one answer and you are using another.
The robust version of this fix resolves the name once and connects to that exact address, or checks the address of the socket after it is established, so the thing you validated and the thing you talk to are the same object. Fesod’s allowlist does something different and still useful: it shrinks the set of hosts that can be aimed at the converter down to names you listed on purpose. It narrows who can target the bug rather than closing the two-lookup window, and the residual advice follows from that, which is to allowlist only hosts whose DNS and endpoints you actually trust. Its the same shape as the CXF cache, seen from the other side. There the thing checked, a 32-bit hash, was not the thing that mattered, the token. Here the thing checked, an IP address, was not the thing used, the connection. Any check-then-use pattern has this trap in it, and the only safe form checks and uses the same handle.
What I take away from this week
First, who actually applies these. CXF, async-http-client, lz4-java and the RabbitMQ client are libraries you declare or inherit transitively, and no framework BOM will move them for you, so start from mvn dependency:tree: CXF 4.2.4, 4.1.9 or 3.6.13, async-http-client 3.0.14 on the 3.x line or 2.16.1 on 2.x, at.yawk.lz4:lz4-java 1.11.4, com.rabbitmq:amqp-client 5.37.0. Camel Karavan is an application you run, so upgrade the install to 4.22.1. Fesod is young and incubating, 2.1.0-incubating, and because its image fetching is now off by default the upgrade changes behaviour: anything relying on remote images has to opt back in with an allowlist. I checked each of these against Maven Central and the fixed versions are all published and downloadable.
Second, the thread that ties the week together: the distance between what a check looked at and what the code then trusted. A resolved address against the connected socket in Fesod. A 32-bit hash against the actual token in the CXF STS. A certificate chain against the unchecked hostname in the CXF Netty transport. A signed element against the processed element in the XML signature wrapping bug. The transport a cookie says it needs against the transport it arrived on in AHC. When you review your own code for this, the question is simple to state: is the thing I validated the exact thing I then act on, or a cheaper proxy for it that someone else gets to vary between the two moments?
Third, AI-assisted discovery keeps turning up in the credits. The CXF authentication bypass and the Karavan Kubernetes issue are credited to MopMonk-AI, and the CXF XML signature wrapping and Netty transport advisories name Claude agents used to study the security of open source projects, with a human finder, Guanping Zhang, named on the signature wrapping one as well. That continues the pattern I wrote about in is there really a human in the loop. For someone reading advisories to protect their own code the practical effect is the same as it was last week: the mechanism is the part you act on, whoever or whatever found it.
References
- oss-security daily index for 9 October 2026 - Openwall oss-security
- Apache CXF security advisories - Apache CXF
- CVE-2026-97468, CXF authentication bypass via weak cache keys - Apache CXF
- CVE-2026-97468 record - CVE.org
- oss-security: CXF CVE-2026-100227, XML signature wrapping - Openwall oss-security
- oss-security: CXF CVE-2026-107938, Netty client TLS hostname verification - Openwall oss-security
- oss-security: CXF CVE-2026-78384, DEFLATE decompression bomb - Openwall oss-security
- oss-security: Apache Camel Karavan CVE-2026-103412 - Openwall oss-security
- Apache Camel security advisory CVE-2026-103412 - Apache Camel
- Apache Camel security advisory CVE-2026-103413 - Apache Camel
- Camel Karavan: validate Kubernetes resources before applying - apache/camel-karavan on GitHub
- oss-security: Apache Fesod CVE-2026-107460 - Openwall oss-security
- CVE-2026-107460 record - CVE.org
- Fesod PR #1035, require an allowlist for remote URL images - apache/fesod on GitHub
- Fesod 2.1.0-incubating release - apache/fesod on GitHub
- GHSA-vqc2-c9jh-3jjv, earlier Fesod SSRF CVE-2026-49328 - GitHub Advisory Database
- CVE-2026-107226, async-http-client secure cookie handling - CVE.org
- GHSA-p2jm-6hj6-9rjg, async-http-client cookie header override - GitHub Advisory Database
- GitHub Advisory Database, Maven ecosystem - GitHub Advisory Database
- GHSA-mcr4-qmvw-px4g, lz4-java temporary file race CVE-2026-106451 - GitHub Advisory Database
- GHSA-cqgh-8p3p-mx4m, RabbitMQ Java client CVE-2026-106121 - GitHub Advisory Database
- GHSA-6v25-8wq6-xq4j, Hazelcast CVE-2026-107726 - GitHub Advisory Database
- Is there really a human in the loop? - oscerd.github.io
- The CVE stigma, we need a new security culture - oscerd.github.io