<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Usman</title>
    <description>The latest articles on DEV Community by Usman (@usman18).</description>
    <link>https://dev.to/usman18</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3974860%2F802b8e0b-42e7-444f-a33f-5d3e41b78670.png</url>
      <title>DEV Community: Usman</title>
      <link>https://dev.to/usman18</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/usman18"/>
    <language>en</language>
    <item>
      <title>I scanned real Maven Central packages for supply-chain anomalies. Here's what I found, and where I was wrong</title>
      <dc:creator>Usman</dc:creator>
      <pubDate>Wed, 10 Jun 2026 06:00:00 +0000</pubDate>
      <link>https://dev.to/usman18/i-scanned-real-maven-central-packages-for-supply-chain-anomalies-heres-what-i-found-and-where-i-2lmp</link>
      <guid>https://dev.to/usman18/i-scanned-real-maven-central-packages-for-supply-chain-anomalies-heres-what-i-found-and-where-i-2lmp</guid>
      <description>&lt;p&gt;I'm building Marshal, a behavioral supply-chain scanner for JVM dependencies. Instead of waiting for a CVE, it watches how packages change. Maintainer swaps, signature drops, repo URL changes, new install hooks. Each update gets a score from 0 to 100. Risky ones get blocked at PR time.&lt;/p&gt;

&lt;p&gt;This week I ran it against real Maven Central packages for the first time. Here's what fired, what didn't, and where the tool embarrassed itself.&lt;/p&gt;




&lt;h2&gt;
  
  
  What fired
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;javax.activation:activation&lt;/code&gt; scored ORANGE at 55/100. Two signals:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;SIGNATURE_DROPPED&lt;/code&gt; (40 pts): version 1.1-rev-1 was signed with GPG key &lt;code&gt;2D6641C6AF88103E&lt;/code&gt;, a Sun Microsystems key. Version 1.1.1 has no &lt;code&gt;.asc&lt;/code&gt; file at all.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;MISSING_SIGNATURE&lt;/code&gt; (15 pts): current release is unsigned.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's a real finding. The prior version had cryptographic provenance. The new one has none. In an attack scenario, that's exactly what you'd see after an account takeover. The attacker doesn't have the original signing key, so the new release goes unsigned.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqeldt91oh8tyzox2oqjh.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqeldt91oh8tyzox2oqjh.webp" alt="Marshal CLI terminal output showing ORANGE risk finding on javax.activation:activation 1.1-rev-1 to 1.1.1, with SIGNATURE_DROPPED and MISSING_SIGNATURE signals scoring 55/100" width="800" height="715"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The actual explanation here is almost certainly Oracle's acquisition of Sun in 2010. Oracle inherited the Java EE components but not the signing infrastructure. It's a known pattern across &lt;code&gt;javax.*&lt;/code&gt; artifacts from that era. Not an attack. But the CVE database has nothing to say about this at all. The behavioral scanner at least surfaces the question.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where I was wrong
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;log4j:log4j&lt;/code&gt; scored ORANGE at 55/100 between 1.2.16 and 1.2.17. Two signals fired:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;NEW_MAINTAINER&lt;/code&gt;: signing key changed from &lt;code&gt;D3EC499070C9C3D0&lt;/code&gt; to &lt;code&gt;86E02C5A42196CA8&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;REPO_CHANGED&lt;/code&gt;: SCM URL changed from &lt;code&gt;.../tags/v1_2_16&lt;/code&gt; to &lt;code&gt;.../tags/v1_2_17_rc3&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both are false positives.&lt;/p&gt;

&lt;p&gt;The keys are both verifiable Apache Software Foundation keys. The two-year gap between those releases is when Apache rotated their signing infrastructure across many projects. The repo URL difference is just a tag name suffix. Same SVN domain, same Apache org.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;commons-collections&lt;/code&gt; fired the same way for the same reason. Seven-year gap between 3.2.1 and 3.2.2, Apache key rotation in between. Also a false positive.&lt;/p&gt;

&lt;p&gt;I cut both from the demo rather than pretend they were real findings.&lt;/p&gt;




&lt;h2&gt;
  
  
  What the rules need
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;NEW_MAINTAINER&lt;/code&gt; treats any signing key change as suspicious. That's too broad. The fix is checking whether both keys belong to the same organisation. Apache, Eclipse, Google, Spring all rotate keys on long-lived projects. If both fingerprints resolve to the same org, it's infrastructure maintenance, not an attacker.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;REPO_CHANGED&lt;/code&gt; needs same-domain awareness. A URL change within the same GitHub org or the same Apache SVN domain is not the same risk as a package suddenly pointing to &lt;code&gt;github.com/random-user/previously-org-owned-lib&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Both are on the v0.2 backlog now.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where things stand
&lt;/h2&gt;

&lt;p&gt;The CLI works. The GitHub Action posts PR comments. JSON output schema is stable. The replay test suite covers event-stream, ua-parser-js, node-ipc, PyTorch-nightly, and XZ Utils. ua-parser-js and node-ipc score RED. event-stream scores ORANGE. XZ Utils only partially fires — the initial maintainer handoff triggers the NEW_MAINTAINER signal, but the slow social engineering that preceded it is designed to evade automated detection. That limitation is documented and intentional.&lt;/p&gt;

&lt;p&gt;The repo goes public with the v0.1.0 launch. I'll post here when it ships.&lt;/p&gt;

&lt;p&gt;If you're running Renovate or Dependabot with auto-merge on a Java project, that's the use case this is built for. What would you want from a tool like this?&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I'm Usman, building Marshal in public from Tilburg. Follow along at &lt;a href="https://marshalhq.dev" rel="noopener noreferrer"&gt;marshalhq.dev&lt;/a&gt;, &lt;a href="https://x.com/marshal_hq" rel="noopener noreferrer"&gt;X&lt;/a&gt;, and &lt;a href="https://bsky.app/profile/marshalhq.bsky.social" rel="noopener noreferrer"&gt;Bluesky&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>security</category>
      <category>supplychain</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
