20 June 2026
I scanned real Maven Central packages for supply-chain anomalies. Here's what I found, and where I was wrong
I built Marshal to catch behavioral anomalies in Maven dependencies before they reach your build. Before calling the tool ready, I ran it against real Maven Central packages to see what it actually finds. This is the account: one real signal, two false positives that I cut from the demo rather than dress up as findings, and what the rules need to improve.
The real finding: javax.activation
javax.activation:activation is the old Sun/Oracle JAXB activation library, now mostly replaced by Jakarta EE equivalents. When I ran Marshal across the version history, the diff from 1.1-rev-1 to 1.1.1 scored ORANGE at 55/100, with two signals firing:
SIGNATURE_DROPPED— the earlier release carried a GPG signature; the later release does notMISSING_SIGNATURE— no signature present at all on1.1.1
No CVE scanner surfaces this. There is no CVE for it. The package is not malicious. But the behavioral signal is real: a previously signed artifact shipped without a signature, and Marshal caught it.
The most likely explanation is the Oracle/Sun acquisition timeline disrupting the signing infrastructure. Sun was acquired in 2010; this library sat in a grey zone for years before Oracle eventually migrated the Jakarta EE stack to the Eclipse Foundation. Key material from the original Sun signing setup did not survive that transition cleanly. The signature dropped, and no one filed a CVE because nothing was compromised.
That is exactly the kind of finding Marshal is built for. The signal is genuine even if the verdict is “probably not an attack.” A developer reviewing a dependency update on javax.activation in 2026 should know the signature history changed. The ORANGE score and the two-signal explanation give them the context to make that call in under a minute, rather than digging through Maven Central metadata by hand.

Where the tool embarrassed itself
I ran the same analysis across a broader set of well-known Apache packages. Two of them fired false positives that I cut from the demo.
log4j 1.2.16 to 1.2.17
org.apache.log4j:log4j from 1.2.16 to 1.2.17 triggered:
NEW_MAINTAINER— the signing key changed between releasesREPO_CHANGED— the repository metadata pointed to a different remote
Both signals are technically accurate. The key did change, and the repo metadata did shift. But the reason is mundane: the Apache Software Foundation rotated its code-signing keys between 2012 and 2014, and log4j 1.2.17 shipped in 2013 right in the middle of that rotation. The new key belongs to the same ASF infrastructure. The repo change is the ASF migrating from Apache SVN to Git.
Marshal does not know that apache.org GPG keys are all controlled by the same organization. It sees “key changed” and fires NEW_MAINTAINER because that is what the rule says. The rule is correct in the abstract, wrong in this specific case.
commons-collections 3.2.1 to 3.2.2
Same pattern. org.apache.commons:commons-collections from 3.2.1 to 3.2.2 fired NEW_MAINTAINER and REPO_CHANGED for the same reason: multi-year release gap (3.2.1 was 2008, 3.2.2 was 2015), ASF key rotation across that gap, repo migration from SVN to Git.
The gap between releases is seven years. Any organization’s signing infrastructure changes over seven years. The rules do not account for that.
What the rules need
Both false positives have the same root cause: Marshal treats a key change as a maintainer change without checking whether the new key is from the same organization or domain as the old one.
Two improvements the rules need:
Same-org key awareness. If the old key and the new key both have email addresses from the same domain (apache.org, oracle.com, etc.), the NEW_MAINTAINER signal should not fire, or should fire at much lower weight. The signal is meant to detect an unknown party taking over a package, not an organization rotating its own credentials.
Same-domain repo awareness. If the repository URL changes from svn.apache.org/... to github.com/apache/..., that is not a suspicious repo change. It is a hosting migration. The REPO_CHANGED rule needs to recognize same-organization domain moves.
Neither of these is implemented yet. They are on the list. Until they are, Marshal will produce false positives on any Apache package that had a long release gap across the 2012-2015 period. I documented this rather than hiding it because users running Marshal against legacy dependencies need to know.
What this means for the demo and for real use
I cut log4j and commons-collections from the early demo because showing known false positives as findings would have been dishonest. The javax.activation finding stayed because it is a real signal with a real explanation, even if the conclusion is “probably safe.”
If you run Marshal against your Maven dependencies today, you will get accurate results for anything signed recently with consistent key history. You will get false positives on old Apache packages with multi-year release gaps if the signing key changed during that window. The JSON output records which signals fired so you can filter and suppress by signal type.
The suppression system supports whitelisting specific packages with an audit trail. That is the pragmatic path until the same-org key awareness is built.
Marshal is open-source under Apache 2.0. If you want to look at the rule implementation or contribute the same-org key check, the repo is at github.com/marshal-hq/marshal.