Athena's second wave
- View all articles
Jackie Porter
Senior Director, Product Management
Chainguard
- View all articles
Cecelia Sanborn
Manager, Product Operations and Data
Chainguard
Jackie Porter Senior Director, Product Management + 1 other
In September, we disclosed the first 14 silent vulnerabilities to come through Athena. We said at the time that the point of starting with already-fixed bugs was to run the whole process end to end and find out what breaks before the volume arrives. Today, the second batch goes out through the same pipes.
We're disclosing 12 more silent vulnerabilities, all in Java, across 9 libraries: Apache Kerby, MockServer, WireMock, Javassist, SAAJ, jjwt, java-jwt, libphonenumber, and Apache Qpid Broker-J. Two are critical, both authentication bypasses. The rest are high, medium, and low. Like the first batch, every one of these was fixed upstream, in some cases years ago, and none of them ever got a CVE, a GHSA, or any kind of security note. The full list is in the public patch repository. If you're a Chainguard Libraries customer, remediated versions are in Chainguard Repository as of today.
We have also worked with 5 shield partners including Akamai, Cloudflare, Cloudsmith, Palo Alto Networks, and Zafran to implement non-patch mitigations, so while you are working to roll out the patches you can have confidence that there is some protection in place.
For example, Palo Alto Networks is providing virtual patching coverage for multiple network-exploitable vulnerabilities, with additional coverage to follow as more network-facing vectors become available. With the new vaulted coverage, Palo Alto Networks was able to ship pre-disclosure. The protections are delivered as threat prevention signatures through Frontier Virtual Patching in Advanced Threat Prevention Plus. They block exploit attempts inline at the network layer, so every workload whose traffic passes through the firewall is shielded, including instances customers haven't yet inventoried or patched. Customers need no downtime, restarts, or manual policy changes. This is a mitigation layer that helps security leaders move from reacting to each disclosure to staying ahead of it. Patching remains the ultimate cure. So, upgrading is still the safest recommended next step.
Akamai and Zafran have also applied protections such as WAF rules and EDR policies to prevent vulnerabilities from being exploited in their customers’ environments. Cloudsmith enabled these types of policies for its Athena member customers during the embargo and has now extended this protection to all of its customers.
While the first batch was mostly about security fixes that rode along inside unrelated changes, this batch focuses on deletions rather than repairs. Several landed on a new major version or a new Maven coordinate and never came back to the line most people actually depend on. A couple are only partly fixed at HEAD. We’ll walk through seven below. Each one shows a different way a fix can exist and still not reach you.
How disclosure works
A quick recap for anyone who missed our disclosures from September. Every finding enters Athena the same way: submitting members point frontier models at sandboxed applications and share what they find through Athena's secure portal.
If the bug still exists at the latest version, it's a zero-day, disclosure runs through the Linux Foundation's Akrites initiative, and the maintainers ship the fix. If the bug is already fixed at HEAD and nobody said so, Chainguard drives the disclosure.
All 12 today are on the second path. In most of these cases, there is nobody upstream who can accept a fix for the affected versions, because the project has moved on, the module layout changed, or the vulnerable code was deleted. With these vulnerabilities, we took the same actions as we did back in September.
We publish the patch. Plain patch files for every affected version, in the public GitHub repository, are available under the project's original license. You can read them and apply them to your own build.
We publish the advisory. Each finding gets a CGP identifier and goes into Chainguard's free, public VEX feed with affected versions enumerated. Shield partners use that to issue non-patch mitigations, and surface partners use it to tell you an affected dependency is in your stack.
We ship the fix. Every artifact in this batch has a remediated version in Chainguard Repository, published at the same time as the advisory. It keeps the package coordinates your application already uses and adds a Chainguard version qualifier (-0cgr.n for Java packages), so adopting it is a lockfile change and a rebuild. If a maintainer later takes a backport we wrote, we deprecate ours and point at upstream.
Where the fixes went
Most of what we disclosed in September was a security fix hiding inside something else: a JWE feature branch, a changelog line about CSRF support, an unrelated refactor. While the commit was public and the diff publicly available, nobody had marked these issues as security fixes. This batch has a few of those too, but it also has fixes that went missing for other reasons.
Some of these fixes were deletions. Javassist had an embedded HTTP server with an arbitrary file read in it. Apache Qpid Broker-J had authentication providers with a timing side channel. In both cases the maintainers removed the code rather than repairing it, which is a perfectly good fix for anyone who upgrades. But the commits say "refactoring" and "remove deprecated providers," and nobody reads either of those as a reason to move off an older version.
Some fixes landed somewhere your build never looks. WireMock's path traversal fix went into 3.x and a new standalone artifact; the old com.github.tomakehurst:wiremock-standalone coordinate stopped at 2.27.2. SAAJ's XXE fix went into 3.0.0 and never came back to the Java EE 8 or Jakarta EE 9 lines. jjwt's fixes are in 0.12.0 of the split-module coordinates, while the original monolithic io.jsonwebtoken:jjwt is frozen at 0.9.1. If your dependency manager says you're on the latest version of one of those, it's telling the truth about the coordinate and not about the code.
And one fix isn't finished. MockServer closed part of its XXE problem in 6.0.0, and part of it is still reachable in 9.1.0, the current release.
In every one of these cases the maintainers did the hard part. They found the bug or were told about it, and they fixed it. The industry's patching model assumes that the next step, saying so publicly, happens on its own. Across these nine projects, it didn't happen once.
The second 12
All 12 are in the patch repository. Here are the two criticals, and then five more that show each of the patterns above.
Apache Kerby: An unsigned JWT over HTTPS gets a real ticket.
CGP-3x2p-3qw2-2ghh is a critical authentication bypass in Apache Kerby, affecting versions before 2.1.0. Kerby is a Java implementation of a Kerberos Key Distribution Center, which is the thing a network asks when it wants to know who someone is. Kerby can take a JWT as proof of identity and hand back a Kerberos ticket, so the JWT signature check is the entire front door.
In the affected versions, that check sits behind two conditions joined with &&. The code needed ||. Because both conditions had to be true before verification ran, a request that came in over HTTPS skipped the signature check completely. An attacker who can reach the KDC over TLS writes a JWT with no signature that names an administrator, sends it, and gets back a real ticket-granting ticket for that administrator. Everything else in the realm trusts the ticket.
The fix shipped in Kerby 2.1.0, and it was one line: the faulty condition was deleted. There's no security language anywhere in the pull request. If you weren't reading Kerby's diffs, nothing told you that a 2.0.x KDC would issue tickets to anyone who asked nicely over TLS.
MockServer: The control API will fetch local files and cloud credentials.
CGP-pqgh-898g-975x is a critical XXE and SSRF in MockServer, affecting versions 5.5.4 and later. MockServer stands in for real HTTP services during integration tests, which is why it tends to run in CI and staging rather than on a laptop.
Starting in 5.5.4, MockServer's XML schema validator turned off the parser's default protections. It set the external-schema and DTD-resolution flags to all, which is the setting that lets a document pull in anything it names. MockServer's control API has no authentication by default, so an unauthenticated request can register a mock whose definition points at file:///etc/passwd, or at a cloud metadata address, and MockServer will go fetch it and return what it gets. Inside a CI runner, what it gets is usually the instance's role credentials.
Upstream addressed part of this in 6.0.0. The unconfined .xsd path lookups are still there in 9.1.0, the current release. There has never been an advisory for the original problem or the one that remains.
Javassist: The embedded HTTP server reads arbitrary files.
Javassist's main distribution used to ship with an embedded HTTP server in its tools package. The server had an arbitrary file read and leaked file descriptors. In 3.32.0-GA the maintainers moved the whole tools package out of the published jar, and the commit is labeled as a refactoring. For anyone on 3.32.0 or later that's the end of the story. For anyone pinned below it the server is still in the jar, and a commit titled "refactoring" is not something that shows up in a dependency review.
Qpid Broker-J: File-based authentication leaks credentials through timing.
Apache Qpid Broker-J's file-based authentication providers compared credentials in a way that took a measurably different amount of time depending on how much of the guess was right. That's enough to recover a plaintext credential one character at a time. In 10.0.0 the maintainers deleted the providers, which had already been marked deprecated. The release notes read as housekeeping. If you're on a 9.x broker with those providers configured, you have the vulnerable code and nothing has ever told you otherwise.
WireMock: The legacy standalone coordinate is vulnerable.
WireMock checked whether a requested file was inside its __files directory using startsWith, with no trailing separator. So /opt/wiremock/__files-archive passes the check for /opt/wiremock/__files, and a request can read or delete files in any directory whose name begins the same way. The fix went into 3.x and the newer wiremock-jre8-standalone artifact. The original com.github.tomakehurst:wiremock-standalone coordinate ends at 2.27.2 and will never get it.
SAAJ: The StAX parser was never hardened.
SAAJ (saaj-impl) hardened its main SAX parser against DOCTYPE declarations but left its alternative lazy StAX parser alone, so an XXE payload that goes through the StAX path still works. The fix landed in 3.0.0 under the heading "code cleanup." The Java EE 8 and Jakarta EE 9 lines, which is where most SAAJ deployments actually are, were not patched.
jjwt: The original coordinate still carries both bugs.
In September we disclosed CGP-xpq5-jm7p-884r, a jjwt signature bypass fixed in 0.12.0. Today adds a denial of service in the same library. Before 0.12.0, jjwt decompressed a token's payload into an unbounded buffer before checking the signature, so a small compressed token from an unauthenticated caller could exhaust the heap. Both fixes are in 0.12.0 of the modern split-module coordinates. The original io.jsonwebtoken:jjwt artifact is frozen at 0.9.1, still gets millions of downloads a month, and carries both bugs. Being on the latest version of that coordinate doesn't help.
None of these maintainers did anything wrong. Fixing the bug is the hard part, and they did it. But a fix with no identifier is one that only someone reading the commit history knows about, and a model can read the commit history of every project on Maven Central in an afternoon. As of today, defenders know about these too.
Test infrastructure is reachable infrastructure
Four of the 12 are in tools built for testing: MockServer, WireMock, and the Javassist embedded server. REST-assured in the first batch was the same kind of thing. It's easy to rate these as low exposure because nothing user-facing depends on them. That's not how they get deployed.
Mock servers don't stay on loopback. They run in CI runners and shared staging environments, and those environments usually have routes to internal services and to the cloud metadata endpoint. They also hold some of the most valuable credentials an organization has: source, signing keys, deploy tokens, cloud roles.
Because these tools are for testing, their management APIs are open by default. WireMock's admin API has no authentication and sends wildcard CORS headers. MockServer's control API is open. That's fine on a laptop. It is not fine for anything another machine can reach, and a mock server in CI should get the same network segmentation and access controls as any other service.
Given the network reachability, we continue to work with the Shield Partners from September to offer non-patch mitigations.
What to do about it
For the libraries that sit on your critical path, read the release diffs. It's slower than waiting for a CVE, and it's the only way to see a fix that nobody labeled. When a dependency update removes a class, a package, or a "deprecated" provider, ask what that code did before it went away. Both Javassist and Qpid hid real fixes behind that word.
Check which coordinates your build actually resolves. com.github.tomakehurst:wiremock-standalone, io.jsonwebtoken:jjwt, and the EE 8 and EE 9 SAAJ lines are all frozen. "Latest" on a frozen coordinate is a version that will never change again.
Keep mock servers and test harnesses on localhost or behind authentication and a firewall, including in CI. And when your own review turns up a security fix that nobody announced, file a GHSA or a CVE for it. The identifier is what makes the fix visible to everyone else's tooling, and it's the thing all 12 of these were missing.
Twenty-seven
Two batches in, that’s the count. The backlog of validated findings behind them is in the tens of thousands. We changed a few things in the process between September and now, mostly in how the advisory and the artifact get out the door together, and the second batch went through without anything getting stuck. What hasn’t changed is the gap we started with: models find these bugs faster than anyone patches them, and a disclosure is only useful if it arrives in a form you can act on that day.
If you're a Chainguard Libraries customer, the remediated artifacts are already in Chainguard Repository: update your lockfile, rebuild, and the finding closes. If you're not, the patches are in the public repo.
If you maintain one of the affected projects and would rather own the backport yourself write to cna@chainguard.dev and we'll hand it over. If you'd like a heads-up before future disclosures that touch your project, tell us there as well.
And if you're pointing a frontier model at open source, sitting in front of traffic, or carrying fixes into customer environments, there's a role for you in Athena. Join us at chainguard.dev/athena.
Share this article
Related articles
securitywfx-loot: Stolen GitHub tokens pushed a CI secret stealer into 60,000+ repositories (November 2026)
securityLiteLLM attacked again: Malicious 1.107.0 wheels on PyPI and Docker Hub (October 2026)
securityAnnouncing the Chainguard Compliance Dashboard
securityAthena's disclosures begin
securityThe flood is coming and the pipes were already full
securityAthena spotlight: Black Duck on the importance of flagging zero-days at scale