<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://blog.shivamsaraswat.com//feed.xml" rel="self" type="application/atom+xml" /><link href="https://blog.shivamsaraswat.com//" rel="alternate" type="text/html" /><updated>2026-07-01T06:28:47+00:00</updated><id>https://blog.shivamsaraswat.com//feed.xml</id><title type="html">Shivam’s Blog</title><subtitle>Cybersecurity Insights and Research</subtitle><entry><title type="html">Could SLSA Have Stopped the Recent npm Supply Chain Attacks?</title><link href="https://blog.shivamsaraswat.com//slsa-prevents-attacks/" rel="alternate" type="text/html" title="Could SLSA Have Stopped the Recent npm Supply Chain Attacks?" /><published>2026-07-01T00:00:00+00:00</published><updated>2026-07-01T00:00:00+00:00</updated><id>https://blog.shivamsaraswat.com//slsa-prevent-attacks</id><content type="html" xml:base="https://blog.shivamsaraswat.com//slsa-prevents-attacks/"><![CDATA[<p>In recent months, we saw a run of software supply chain attacks against the npm
ecosystem. Packages used by millions of projects were replaced with versions
that stole credentials, drained crypto wallets, or installed remote access
trojans. This post lists the main incidents, explains the SLSA framework, and
works through which attacks SLSA could have stopped and at which level.</p>

<!--more-->

<hr />

<h2 id="contents-">Contents <a name="top"></a></h2>
<ul id="markdown-toc">
  <li><a href="#a-short-list-of-recent-attacks" id="markdown-toc-a-short-list-of-recent-attacks">A short list of recent attacks</a>    <ul>
      <li><a href="#chalk-debug-and-18-other-packages-september-8-2025" id="markdown-toc-chalk-debug-and-18-other-packages-september-8-2025">chalk, debug, and 18 other packages (September 8, 2025)</a></li>
      <li><a href="#shai-hulud-worm-september-15-2025" id="markdown-toc-shai-hulud-worm-september-15-2025">Shai-Hulud worm (September 15, 2025)</a></li>
      <li><a href="#shai-hulud-20-november-2025" id="markdown-toc-shai-hulud-20-november-2025">Shai-Hulud 2.0 (November 2025)</a></li>
      <li><a href="#axios-march-31-2026" id="markdown-toc-axios-march-31-2026">axios (March 31, 2026)</a></li>
      <li><a href="#mini-shai-hulud--teampcp-may-2026" id="markdown-toc-mini-shai-hulud--teampcp-may-2026">Mini Shai-Hulud / TeamPCP (May 2026)</a></li>
    </ul>
  </li>
  <li><a href="#what-slsa-is" id="markdown-toc-what-slsa-is">What SLSA is</a></li>
  <li><a href="#could-slsa-have-prevented-these-attacks" id="markdown-toc-could-slsa-have-prevented-these-attacks">Could SLSA have prevented these attacks?</a>    <ul>
      <li><a href="#group-1-stolen-credentials-used-to-publish-outside-the-build-pipeline" id="markdown-toc-group-1-stolen-credentials-used-to-publish-outside-the-build-pipeline">Group 1: stolen credentials used to publish outside the build pipeline</a></li>
      <li><a href="#group-2-the-build-pipeline-itself-is-compromised" id="markdown-toc-group-2-the-build-pipeline-itself-is-compromised">Group 2: the build pipeline itself is compromised</a></li>
    </ul>
  </li>
  <li><a href="#summary" id="markdown-toc-summary">Summary</a></li>
  <li><a href="#official-and-primary-sources" id="markdown-toc-official-and-primary-sources">Official and primary sources</a></li>
</ul>

<hr />

<h2 id="a-short-list-of-recent-attacks">A short list of recent attacks</h2>

<h3 id="chalk-debug-and-18-other-packages-september-8-2025">chalk, debug, and 18 other packages (September 8, 2025)</h3>
<p>An attacker phished the npm maintainer “qix” (Josh Junon) with a fake 2FA reset
email from the domain <code class="language-plaintext highlighter-rouge">npmjs.help</code>. The attacker took over the account and
published versions of 18-20 packages, including <code class="language-plaintext highlighter-rouge">chalk</code> and <code class="language-plaintext highlighter-rouge">debug</code>, that
together have over 2 billion weekly downloads. The payload was a browser script
that rewrote crypto wallet addresses during transactions. The versions were live
for about two hours.
Source: <a href="https://www.paloaltonetworks.com/blog/cloud-security/npm-supply-chain-attack/">Palo Alto Networks</a>,
<a href="https://thehackernews.com/2025/09/20-popular-npm-packages-with-2-billion.html">The Hacker News</a></p>

<h3 id="shai-hulud-worm-september-15-2025">Shai-Hulud worm (September 15, 2025)</h3>
<p>A self-replicating worm spread through npm. When it ran in an environment that
held npm tokens, it published new versions of any package those tokens could
reach. It also harvested credentials and sent them to public GitHub
repositories. It compromised over 500 packages. Researchers linked it to the
earlier s1ngularity/Nx token theft from late August 2025.
Source: <a href="https://www.cisa.gov/news-events/alerts/2025/09/23/widespread-supply-chain-compromise-impacting-npm-ecosystem">CISA Alert</a>,
<a href="https://unit42.paloaltonetworks.com/npm-supply-chain-attack/">Unit 42</a>,
<a href="https://www.wiz.io/blog/shai-hulud-npm-supply-chain-attack">Wiz</a></p>

<h3 id="shai-hulud-20-november-2025">Shai-Hulud 2.0 (November 2025)</h3>
<p>A second wave used the same propagation idea but moved the payload to the
pre-install step, which widened the impact. It affected tens of thousands of
GitHub repositories and added a fallback that could delete a user’s home
directory.
Source: <a href="https://unit42.paloaltonetworks.com/npm-supply-chain-attack/">Unit 42</a>,
<a href="https://securitylabs.datadoghq.com/articles/shai-hulud-2.0-npm-worm/">Datadog Security Labs</a></p>

<h3 id="axios-march-31-2026">axios (March 31, 2026)</h3>
<p>An attacker took over the npm account of the axios maintainer (<code class="language-plaintext highlighter-rouge">jasonsaayman</code>),
changed the account email, and published two versions (<code class="language-plaintext highlighter-rouge">1.14.1</code> and <code class="language-plaintext highlighter-rouge">0.30.4</code>).
These versions added a dependency, <code class="language-plaintext highlighter-rouge">plain-crypto-js</code>, whose post-install script
ran a cross-platform remote access trojan on Windows, macOS, and Linux. axios
has over 100 million weekly downloads. The attacker published with a long-lived
npm token from the CLI and bypassed the project’s GitHub Actions OIDC publishing
workflow. The legitimate <code class="language-plaintext highlighter-rouge">1.14.0</code> had been published through GitHub Actions; the
malicious <code class="language-plaintext highlighter-rouge">1.14.1</code> had no matching GitHub tag, release, or commit. Google and
Microsoft attributed the attack to a North Korea-linked group.
Source: <a href="https://www.microsoft.com/en-us/security/blog/2026/04/01/mitigating-the-axios-npm-supply-chain-compromise/">Microsoft</a>,
<a href="https://cloud.google.com/blog/topics/threat-intelligence/north-korea-threat-actor-targets-axios-npm-package">Google Threat Intelligence</a>,
<a href="https://unit42.paloaltonetworks.com/axios-supply-chain-attack/">Unit 42</a></p>

<h3 id="mini-shai-hulud--teampcp-may-2026">Mini Shai-Hulud / TeamPCP (May 2026)</h3>
<p>A group tracked as TeamPCP ran a worm that published versions through the
projects’ own GitHub Actions release pipelines using hijacked OIDC tokens. It hit
TanStack, UiPath, AntV, and others. Because the malicious code went through the
real build pipeline, the published packages carried valid SLSA Build Level 3
provenance. This was the first reported npm worm to produce packages with valid
provenance.
Source: <a href="https://www.stepsecurity.io/blog/mini-shai-hulud-is-back-a-self-spreading-supply-chain-attack-hits-the-npm-ecosystem">StepSecurity</a>,
<a href="https://snyk.io/blog/mini-shai-hulud-antv-npm-supply-chain-attack/">Snyk</a></p>

<h2 id="what-slsa-is">What SLSA is</h2>

<p>SLSA (Supply-chain Levels for Software Artifacts) is a framework from the
OpenSSF. It defines how to record and check the origin of a software artifact.
The record is called provenance: it states what built the artifact, what process
was used, and what the inputs were. A consumer sets an expectation for how a
package should be built, then checks each version’s provenance against that
expectation.</p>

<p>SLSA is organized into tracks. Each track has levels. The current version is
v1.2, approved in November 2025.</p>

<ul>
  <li><strong>Build Track</strong> (stable since v1.0): levels L0 to L3.
    <ul>
      <li>L0: no provenance.</li>
      <li>L1: provenance exists but can be forged.</li>
      <li>L2: provenance is signed by a hosted build platform.</li>
      <li>L3: the build runs in an isolated environment, and the signing key is not
reachable from the build process.</li>
    </ul>
  </li>
  <li><strong>Source Track</strong> (added in v1.2): covers how source code is authored,
reviewed, and managed before it reaches the builder.</li>
  <li><strong>Build Environment Track</strong> and <strong>Dependency Track</strong>: still in draft.</li>
</ul>

<p>Reference: <a href="https://slsa.dev/spec/v1.2/">SLSA specification v1.2</a>,
<a href="https://slsa.dev/spec/v1.0/levels">SLSA security levels</a>, <a href="https://blog.shivamsaraswat.com/understanding-slsa/">Understanding SLSA: Tracks, Levels, and the Checks at Each Step</a></p>

<h2 id="could-slsa-have-prevented-these-attacks">Could SLSA have prevented these attacks?</h2>

<p>The attacks fall into two groups. SLSA handles them differently.</p>

<h3 id="group-1-stolen-credentials-used-to-publish-outside-the-build-pipeline">Group 1: stolen credentials used to publish outside the build pipeline</h3>

<p>This group includes chalk/debug, the original Shai-Hulud, Shai-Hulud 2.0, and
axios. In each case the attacker obtained publishing credentials (an account or
a token) and pushed versions that never went through the project’s real build
process.</p>

<p>For axios, the legitimate releases came from GitHub Actions with OIDC. The
malicious release came from a manual token publish with no source commit behind
it. For Shai-Hulud, the worm spread by reusing stolen npm tokens to publish.</p>

<p>SLSA addresses this group through the Build Track:</p>

<ul>
  <li>At <strong>Build L2</strong>, legitimate releases carry provenance signed by the build
platform, linking the artifact to a source commit and a build process. A
version published by hand with a stolen token cannot produce that signed
provenance. A consumer who checks provenance against the expectation would
reject it. So L2 lets you <strong>detect</strong> the bad version.</li>
  <li>At <strong>Build L3</strong>, the signing capability is out of reach of anyone holding only
publish credentials. Stolen tokens are no longer enough to create a trusted
release. The SLSA documentation states that higher build levels reduce the
impact of compromised upload credentials. So L3 helps <strong>prevent</strong> the attack,
not just detect it.</li>
</ul>

<p>For this group the answer is: yes, <strong>Build Track, L2 to detect, L3 to prevent</strong>.</p>

<p>There is one condition. SLSA only stops these attacks if the registry or the
consumer actually checks provenance and rejects mismatches. Generating
provenance alone (L1) does nothing. The axios pipeline also showed a related
gap: it had OIDC set up but still passed a long-lived <code class="language-plaintext highlighter-rouge">NPM_TOKEN</code>, and npm used
the token when both were present. Removing standing tokens, which is part of the
L3 discipline, would have closed that path.</p>

<h3 id="group-2-the-build-pipeline-itself-is-compromised">Group 2: the build pipeline itself is compromised</h3>

<p>This group is the Mini Shai-Hulud / TeamPCP wave. The attacker did not publish
outside the pipeline. The attacker hijacked OIDC tokens and published through the
real GitHub Actions pipeline. The result was malicious packages with valid SLSA
Build L3 provenance.</p>

<p>This shows a limit of the Build Track. SLSA provenance states where, how, and
from what source an artifact was built. It does not state that the source or the
build is safe. If the attacker controls the pipeline, the provenance is genuine
and verification passes.</p>

<p>For this group the Build Track is not enough. Useful controls here are:</p>

<ul>
  <li><strong>Source Track</strong>: protected branches, required review, and history integrity,
to make unauthorized source changes and unauthorized releases harder.</li>
  <li><strong>Two-party review</strong>: in <a href="https://slsa.dev/spec/v1.2/source-requirements#level-4-two-party-review">v1.2</a> this is a policy requirement rather than a level.</li>
  <li><strong>Build Environment Track</strong> <a href="https://slsa.dev/spec/draft/build-env-track-basics">(draft)</a>: aimed at the integrity of the build
environment and the tokens it holds.</li>
</ul>

<p>Even these do not fully prevent the attack. A privileged insider or a review
bypass can still get through. They raise the cost; they do not remove the risk.</p>

<h2 id="summary">Summary</h2>

<table>
  <thead>
    <tr>
      <th>Attack</th>
      <th>Could SLSA have stopped it?</th>
      <th>Track and level</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>chalk, debug, qix (Sep 2025)</td>
      <td>Yes</td>
      <td>Build L2 to detect, L3 to prevent, with verification</td>
    </tr>
    <tr>
      <td>Shai-Hulud / 2.0 (Sep-Nov 2025)</td>
      <td>Yes</td>
      <td>Build L3 (removes the stolen-token publish path)</td>
    </tr>
    <tr>
      <td>axios (Mar 2026)</td>
      <td>Yes</td>
      <td>Build L2 to detect, L3 to prevent, with verification</td>
    </tr>
    <tr>
      <td>Mini Shai-Hulud / TeamPCP (2026)</td>
      <td>No (Build Track alone)</td>
      <td>Needs Source Track, two-party review, Build Environment Track; still partial</td>
    </tr>
  </tbody>
</table>

<hr />

<p><em>The common lesson across all of these: SLSA helps only when consumers or
registries verify provenance against an expected source and builder. <a href="https://github.blog/changelog/2023-09-26-npm-provenance-general-availability/">npm now
produces provenance</a> and supports <a href="https://docs.npmjs.com/trusted-publishers">OIDC trusted publishing</a>, but most installs do
not check it. Provenance without verification is a record that no one reads.</em></p>

<hr />

<h2 id="official-and-primary-sources">Official and primary sources</h2>

<ul>
  <li>SLSA specification: <a href="https://slsa.dev/spec/v1.2/">https://slsa.dev/spec/v1.2/</a></li>
  <li>SLSA security levels: <a href="https://slsa.dev/spec/v1.0/levels">https://slsa.dev/spec/v1.0/levels</a></li>
  <li>Understanding SLSA: Tracks, Levels, and the Checks at Each Step: <a href="https://blog.shivamsaraswat.com/understanding-slsa/">https://blog.shivamsaraswat.com/understanding-slsa/</a></li>
  <li>CISA alert on the npm compromise: <a href="https://www.cisa.gov/news-events/alerts/2025/09/23/widespread-supply-chain-compromise-impacting-npm-ecosystem">https://www.cisa.gov/news-events/alerts/2025/09/23/widespread-supply-chain-compromise-impacting-npm-ecosystem</a></li>
  <li>Microsoft on the axios attack: <a href="https://www.microsoft.com/en-us/security/blog/2026/04/01/mitigating-the-axios-npm-supply-chain-compromise/">https://www.microsoft.com/en-us/security/blog/2026/04/01/mitigating-the-axios-npm-supply-chain-compromise/</a></li>
  <li>Google Threat Intelligence on the axios attack: <a href="https://cloud.google.com/blog/topics/threat-intelligence/north-korea-threat-actor-targets-axios-npm-package">https://cloud.google.com/blog/topics/threat-intelligence/north-korea-threat-actor-targets-axios-npm-package</a></li>
  <li>Unit 42 on Shai-Hulud and axios: <a href="https://unit42.paloaltonetworks.com/npm-supply-chain-attack/">https://unit42.paloaltonetworks.com/npm-supply-chain-attack/</a> and <a href="https://unit42.paloaltonetworks.com/axios-supply-chain-attack/">https://unit42.paloaltonetworks.com/axios-supply-chain-attack/</a></li>
</ul>

<hr />

<p><strong>Feel free to <a href="/contact/">contact me</a> for any suggestions and feedbacks. I would really appreciate those.</strong></p>

<p>Thank you for reading!</p>

<p><a href="#top" style="float: right"><strong>Back to Top<svg width="12" height="12" viewBox="0 0 24 24" aria-hidden="true"><path fill="currentColor" d="M12 4l-8 8h5v8h6v-8h5z"></path></svg></strong> </a></p>]]></content><author><name>Shivam Saraswat</name></author><category term="Security Engineering" /><category term="Supply Chain Security" /><category term="SLSA" /><category term="OpenSSF" /><category term="Open Source" /><summary type="html"><![CDATA[In recent months, we saw a run of software supply chain attacks against the npm ecosystem. Packages used by millions of projects were replaced with versions that stole credentials, drained crypto wallets, or installed remote access trojans. This post lists the main incidents, explains the SLSA framework, and works through which attacks SLSA could have stopped and at which level.]]></summary></entry><entry><title type="html">Understanding SLSA: Tracks, Levels, and the Checks at Each Step</title><link href="https://blog.shivamsaraswat.com//understanding-slsa/" rel="alternate" type="text/html" title="Understanding SLSA: Tracks, Levels, and the Checks at Each Step" /><published>2026-06-21T00:00:00+00:00</published><updated>2026-06-21T00:00:00+00:00</updated><id>https://blog.shivamsaraswat.com//slsa</id><content type="html" xml:base="https://blog.shivamsaraswat.com//understanding-slsa/"><![CDATA[<p>SLSA stands for Supply-chain Levels for Software Artifacts. It is pronounced “salsa”. It is a specification for software supply chain security, maintained by industry consensus under the Linux Foundation.</p>

<p>This post explains what SLSA is, how it works, where it applies, and the checks required at each level. It covers version 1.2 of the specification.</p>

<p>Official specification: <a href="https://slsa.dev/spec/v1.2/">slsa.dev/spec/v1.2</a></p>

<!--more-->

<hr />

<h2 id="contents-">Contents <a name="top"></a></h2>
<ul id="markdown-toc">
  <li><a href="#what-slsa-is" id="markdown-toc-what-slsa-is">What SLSA is</a></li>
  <li><a href="#how-slsa-works" id="markdown-toc-how-slsa-works">How SLSA works</a></li>
  <li><a href="#the-two-tracks-in-v12" id="markdown-toc-the-two-tracks-in-v12">The two tracks in v1.2</a></li>
  <li><a href="#who-slsa-is-for" id="markdown-toc-who-slsa-is-for">Who SLSA is for</a></li>
  <li><a href="#build-track-levels-and-checks" id="markdown-toc-build-track-levels-and-checks">Build Track: levels and checks</a>    <ul>
      <li><a href="#build-l0-no-guarantees" id="markdown-toc-build-l0-no-guarantees">Build L0: no guarantees</a></li>
      <li><a href="#build-l1-provenance-exists" id="markdown-toc-build-l1-provenance-exists">Build L1: provenance exists</a></li>
      <li><a href="#build-l2-hosted-build-platform-adds-to-l1" id="markdown-toc-build-l2-hosted-build-platform-adds-to-l1">Build L2: hosted build platform (adds to L1)</a></li>
      <li><a href="#build-l3-hardened-builds-adds-to-l2" id="markdown-toc-build-l3-hardened-builds-adds-to-l2">Build L3: hardened builds (adds to L2)</a></li>
    </ul>
  </li>
  <li><a href="#source-track-levels-and-checks" id="markdown-toc-source-track-levels-and-checks">Source Track: levels and checks</a>    <ul>
      <li><a href="#organization-checks-by-level" id="markdown-toc-organization-checks-by-level">Organization checks by level</a></li>
      <li><a href="#source-control-system-checks-by-level" id="markdown-toc-source-control-system-checks-by-level">Source Control System checks by level</a></li>
    </ul>
  </li>
  <li><a href="#attestations" id="markdown-toc-attestations">Attestations</a></li>
  <li><a href="#what-slsa-does-not-cover" id="markdown-toc-what-slsa-does-not-cover">What SLSA does not cover</a></li>
  <li><a href="#a-path-to-adoption" id="markdown-toc-a-path-to-adoption">A path to adoption</a></li>
  <li><a href="#sources" id="markdown-toc-sources">Sources</a></li>
</ul>

<hr />

<h2 id="what-slsa-is">What SLSA is</h2>

<p>SLSA is a set of guidelines for securing the software supply chain. You adopt it in steps. It works for two groups:</p>

<ul>
  <li>Producers use it to reduce the chance that their software is changed without authorization on the way to users.</li>
  <li>Consumers use it to decide whether to trust a package.</li>
</ul>

<p>SLSA gives you:</p>

<ul>
  <li>A shared vocabulary for supply chain security.</li>
  <li>A method to evaluate the artifacts you consume.</li>
  <li>A checklist to improve your own software.</li>
  <li>A way to measure progress toward the NIST Secure Software Development Framework (SSDF). See <a href="https://csrc.nist.gov/Projects/ssdf">csrc.nist.gov/Projects/ssdf</a>.</li>
</ul>

<p>Reference: <a href="https://slsa.dev/spec/v1.2/about">About SLSA</a>.</p>

<h2 id="how-slsa-works">How SLSA works</h2>

<p>SLSA is organized into tracks. Each track is divided into levels.</p>

<ul>
  <li>A track covers one part of the supply chain. Examples: how an artifact was built, or how a source revision was created.</li>
  <li>Levels within a track go up in order. A higher level means stronger guarantees and more work to implement. A lower level is easier to adopt and gives fewer guarantees. Level 0 means the software meets no level yet.</li>
</ul>

<p>The mechanism behind every track is the attestation. An attestation is a signed, machine-readable statement about how an artifact or source revision was produced. Verification means comparing the attestation that exists against the attestation that was expected.</p>

<p>Each ecosystem or organization decides the details: how expectations are defined, which formats are accepted, how attestations are distributed, when verification runs, and what happens on failure.</p>

<p>Reference: <a href="https://slsa.dev/spec/v1.2/tracks">Tracks</a>.</p>

<h2 id="the-two-tracks-in-v12">The two tracks in v1.2</h2>

<table>
  <thead>
    <tr>
      <th>Track</th>
      <th>What it covers</th>
      <th>Levels</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Build Track</td>
      <td>How an artifact was built: who built it, what process was used, what the inputs were.</td>
      <td>L0 to L3</td>
    </tr>
    <tr>
      <td>Source Track</td>
      <td>How a source revision was created and managed.</td>
      <td>L1 to L4</td>
    </tr>
  </tbody>
</table>

<p>Version history: the first version of SLSA used one track with levels 1 to 4. Version 1.0 removed source and focused on the build track. Version 1.2 adds source back as its own track.</p>

<h2 id="who-slsa-is-for">Who SLSA is for</h2>

<table>
  <thead>
    <tr>
      <th>Audience</th>
      <th>What SLSA provides</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Software producers (open source projects, vendors, internal teams)</td>
      <td>Protection against changes to software on the path to users. Reduces insider risk.</td>
    </tr>
    <tr>
      <td>Software consumers (teams using open source, agencies, security officers)</td>
      <td>A method to assess the practices behind software they depend on, and to confirm they received what they expected.</td>
    </tr>
    <tr>
      <td>Infrastructure providers (package managers, build and CI/CD platforms)</td>
      <td>A way to enable a secure supply chain between producers and consumers.</td>
    </tr>
  </tbody>
</table>

<h2 id="build-track-levels-and-checks">Build Track: levels and checks</h2>

<p>The Build Track lets you prove that an artifact was built the way it was meant to be, on infrastructure you can trust. Each level includes the requirements of the level below it.</p>

<table>
  <thead>
    <tr>
      <th>Level</th>
      <th>Requirement</th>
      <th>Threat addressed</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Build L0</td>
      <td>None</td>
      <td>None</td>
    </tr>
    <tr>
      <td>Build L1</td>
      <td>Provenance shows how the package was built</td>
      <td>Mistakes and missing records</td>
    </tr>
    <tr>
      <td>Build L2</td>
      <td>Signed provenance from a hosted build platform</td>
      <td>Changes after the build</td>
    </tr>
    <tr>
      <td>Build L3</td>
      <td>Hardened build platform</td>
      <td>Changes during the build</td>
    </tr>
  </tbody>
</table>

<h3 id="build-l0-no-guarantees">Build L0: no guarantees</h3>
<ul>
  <li>No requirements. Used for builds that run and are consumed on the same machine, such as unit tests.</li>
</ul>

<h3 id="build-l1-provenance-exists">Build L1: provenance exists</h3>
<ul>
  <li>Producer: follow one build process so others can define what a correct build looks like.</li>
  <li>Producer: run builds on a platform that meets Build L1.</li>
  <li>Producer: distribute provenance to consumers.</li>
  <li>Build platform: generate provenance that records the entity that built the package, the build process used, and the top-level inputs.</li>
  <li>Note: at L1 the provenance can be incomplete or unsigned. It prevents mistakes, not deliberate attacks.</li>
</ul>

<h3 id="build-l2-hosted-build-platform-adds-to-l1">Build L2: hosted build platform (adds to L1)</h3>
<ul>
  <li>Producer: run builds on a hosted build platform that meets Build L2.</li>
  <li>Build platform: generate and sign the provenance.</li>
  <li>Consumer: check that the provenance is authentic.</li>
  <li>Result: signed provenance enables detection of changes after the build (assuming signing keys and trust anchors are secure).</li>
</ul>

<h3 id="build-l3-hardened-builds-adds-to-l2">Build L3: hardened builds (adds to L2)</h3>
<ul>
  <li>Producer: run builds on a hosted build platform that meets Build L3.</li>
  <li>Build platform: prevent one build run from affecting another, including runs in the same project.</li>
  <li>Build platform: keep the signing secrets out of reach of user-defined build steps.</li>
  <li>Result: protection against changes during the build from insiders, stolen credentials, or other tenants.</li>
  <li>Note: L3 reduces risk but does not cover compromise of the build platform itself, such as a malicious platform administrator. Verifiers should choose which build platforms to trust and configure their roots of trust accordingly. See <a href="https://slsa.dev/spec/v1.2/assessing-build-platforms">Assessing build platforms</a>.</li>
</ul>

<p>Reference: <a href="https://slsa.dev/spec/v1.2/build-track-basics">Build Track Basics</a>. Detailed requirements: <a href="https://slsa.dev/spec/v1.2/build-requirements">Producing artifacts</a>. Verification: <a href="https://slsa.dev/spec/v1.2/verifying-artifacts">Verifying artifacts</a>.</p>

<h2 id="source-track-levels-and-checks">Source Track: levels and checks</h2>

<p>The Source Track lets you trust how a source revision was created and confirm that its history was not rewritten. The repository owner (the organization) defines the process and runs the controls that enforce it. Consumers review attestations to confirm a revision meets their bar.</p>

<table>
  <thead>
    <tr>
      <th>Level</th>
      <th>Requirement</th>
      <th>Focus</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Source L1</td>
      <td>Use a modern version control system (produce discrete, immutable revisions)</td>
      <td>Discrete revisions for precise use</td>
    </tr>
    <tr>
      <td>Source L2</td>
      <td>Keep change history and produce source provenance</td>
      <td>History backed by evidence</td>
    </tr>
    <tr>
      <td>Source L3</td>
      <td>Enforce the organization’s technical controls</td>
      <td>Controls that consumers can see</td>
    </tr>
    <tr>
      <td>Source L4</td>
      <td>Require two-party review</td>
      <td>Code review and insider-threat resistance</td>
    </tr>
  </tbody>
</table>

<p>Responsibility is split between the organization and the Source Control System (SCS), such as GitHub, GitLab, Gerrit, or a self-hosted system. Each has its own checks.</p>

<p>Claims apply only forward from the revision where a branch is onboarded to a level. No claims are made about earlier history.</p>

<h3 id="organization-checks-by-level">Organization checks by level</h3>

<table>
  <thead>
    <tr>
      <th>Check</th>
      <th style="text-align: center">L1</th>
      <th style="text-align: center">L2</th>
      <th style="text-align: center">L3</th>
      <th style="text-align: center">L4</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Choose an SCS that can reach the target level</td>
      <td style="text-align: center">x</td>
      <td style="text-align: center">x</td>
      <td style="text-align: center">x</td>
      <td style="text-align: center">x</td>
    </tr>
    <tr>
      <td>Configure access control and enforce history; prevent tags from being moved or deleted</td>
      <td style="text-align: center"> </td>
      <td style="text-align: center">x</td>
      <td style="text-align: center">x</td>
      <td style="text-align: center">x</td>
    </tr>
    <tr>
      <td>Document a safe process for removing content for legal or privacy reasons, with logging</td>
      <td style="text-align: center"> </td>
      <td style="text-align: center">x</td>
      <td style="text-align: center">x</td>
      <td style="text-align: center">x</td>
    </tr>
    <tr>
      <td>Provide evidence of continuous enforcement for every control claimed, and document each control</td>
      <td style="text-align: center"> </td>
      <td style="text-align: center"> </td>
      <td style="text-align: center">x</td>
      <td style="text-align: center">x</td>
    </tr>
  </tbody>
</table>

<h3 id="source-control-system-checks-by-level">Source Control System checks by level</h3>

<table>
  <thead>
    <tr>
      <th>Check</th>
      <th style="text-align: center">L1</th>
      <th style="text-align: center">L2</th>
      <th style="text-align: center">L3</th>
      <th style="text-align: center">L4</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Repositories are uniquely identifiable with a stable locator</td>
      <td style="text-align: center">x</td>
      <td style="text-align: center">x</td>
      <td style="text-align: center">x</td>
      <td style="text-align: center">x</td>
    </tr>
    <tr>
      <td>Revisions are immutable and uniquely identifiable</td>
      <td style="text-align: center">x</td>
      <td style="text-align: center">x</td>
      <td style="text-align: center">x</td>
      <td style="text-align: center">x</td>
    </tr>
    <tr>
      <td>Provide tooling to show diffs between revisions</td>
      <td style="text-align: center">x</td>
      <td style="text-align: center">x</td>
      <td style="text-align: center">x</td>
      <td style="text-align: center">x</td>
    </tr>
    <tr>
      <td>Issue a Source Verification Summary Attestation (VSA) for any revision at L1 or above</td>
      <td style="text-align: center">x</td>
      <td style="text-align: center">x</td>
      <td style="text-align: center">x</td>
      <td style="text-align: center">x</td>
    </tr>
    <tr>
      <td>Record all changes to references; allow a branch to move only to descendant revisions (no force-push)</td>
      <td style="text-align: center"> </td>
      <td style="text-align: center">x</td>
      <td style="text-align: center">x</td>
      <td style="text-align: center">x</td>
    </tr>
    <tr>
      <td>Track continuous enforcement of each control from a start revision</td>
      <td style="text-align: center"> </td>
      <td style="text-align: center">x</td>
      <td style="text-align: center">x</td>
      <td style="text-align: center">x</td>
    </tr>
    <tr>
      <td>Authenticate actors and let the organization set who can perform sensitive actions</td>
      <td style="text-align: center"> </td>
      <td style="text-align: center">x</td>
      <td style="text-align: center">x</td>
      <td style="text-align: center">x</td>
    </tr>
    <tr>
      <td>Produce source provenance for each revision at the time the branch is updated</td>
      <td style="text-align: center"> </td>
      <td style="text-align: center">x</td>
      <td style="text-align: center">x</td>
      <td style="text-align: center">x</td>
    </tr>
    <tr>
      <td>Let the organization enforce custom controls on chosen branches and tags, and record them</td>
      <td style="text-align: center"> </td>
      <td style="text-align: center"> </td>
      <td style="text-align: center">x</td>
      <td style="text-align: center">x</td>
    </tr>
    <tr>
      <td>Require two trusted persons to agree to each change on protected branches</td>
      <td style="text-align: center"> </td>
      <td style="text-align: center"> </td>
      <td style="text-align: center"> </td>
      <td style="text-align: center">x</td>
    </tr>
  </tbody>
</table>

<p>Two-party review applies to the final submitted revision. Later edits are reviewed again. Organizations may grant standing exceptions to trusted automation, such as Dependabot or migration bots.</p>

<p>Reference: <a href="https://slsa.dev/spec/v1.2/source-requirements">Producing source</a>. Verification: <a href="https://slsa.dev/spec/v1.2/verifying-source">Verifying source</a>.</p>

<h2 id="attestations">Attestations</h2>

<p>Every track is enforced through attestations. These use the in-toto attestation format. See the <a href="https://github.com/in-toto/attestation">in-toto attestation specification</a>.</p>

<ul>
  <li>Build provenance: records who built an artifact, the process, and the inputs. See <a href="https://slsa.dev/spec/v1.2/provenance">Provenance</a>.</li>
  <li>Source provenance: SCS-issued evidence of how a revision was created. The format is left open so each SCS can fit its own model.</li>
  <li>Verification Summary Attestation (VSA): a summary issued by an authority that states the level a revision or artifact meets, for example SLSA_SOURCE_LEVEL_3. VSAs use predicateType <code class="language-plaintext highlighter-rouge">https://slsa.dev/verification_summary/v1</code> in the in-toto attestation framework. See <a href="https://slsa.dev/spec/v1.2/verification_summary">Verification Summary</a>.</li>
</ul>

<p>Verification means a verifier compares the attestation against the expectations defined for the artifact or revision. The level tells the consumer how much weight that comparison carries.</p>

<h2 id="what-slsa-does-not-cover">What SLSA does not cover</h2>

<ul>
  <li>Code quality: SLSA does not check whether the code itself is written securely.</li>
  <li>Producer trust: SLSA does not stop an organization that intends to ship malware. It reduces insider risk inside an organization you already trust.</li>
  <li>Transitive dependencies: an artifact’s level is separate from the levels of its dependencies. There is no single level that covers an artifact and its full dependency tree.</li>
</ul>

<p><em>Pair SLSA with vulnerability scanning, SBOMs, code review, and dependency management.</em></p>

<p>Reference: <a href="https://slsa.dev/spec/v1.2/threats">Threats and mitigations</a>.</p>

<h2 id="a-path-to-adoption">A path to adoption</h2>

<ol>
  <li>Reach Build L1 by producing provenance from your current pipeline.</li>
  <li>Move to a hosted build platform that signs provenance to reach Build L2.</li>
  <li>Harden the platform to reach Build L3 for production releases.</li>
  <li>Walk the Source Track in parallel: L1 uses a version control system, L2 adds history and source provenance, L3 enforces controls, L4 requires two-party review.</li>
  <li>Verify, not just produce. Provenance has value only when consumers compare it against expectations and reject mismatches.</li>
</ol>

<h2 id="sources">Sources</h2>

<ul>
  <li>SLSA v1.2 specification: <a href="https://slsa.dev/spec/v1.2/">slsa.dev/spec/v1.2</a></li>
  <li>About SLSA: <a href="https://slsa.dev/spec/v1.2/about">slsa.dev/spec/v1.2/about</a></li>
  <li>Tracks: <a href="https://slsa.dev/spec/v1.2/tracks">slsa.dev/spec/v1.2/tracks</a></li>
  <li>Build Track Basics: <a href="https://slsa.dev/spec/v1.2/build-track-basics">slsa.dev/spec/v1.2/build-track-basics</a></li>
  <li>Producing artifacts: <a href="https://slsa.dev/spec/v1.2/build-requirements">slsa.dev/spec/v1.2/build-requirements</a></li>
  <li>Producing source: <a href="https://slsa.dev/spec/v1.2/source-requirements">slsa.dev/spec/v1.2/source-requirements</a></li>
  <li>NIST SSDF: <a href="https://csrc.nist.gov/Projects/ssdf">csrc.nist.gov/Projects/ssdf</a></li>
</ul>

<hr />

<p><strong>Feel free to <a href="/contact/">contact me</a> for any suggestions and feedbacks. I would really appreciate those.</strong></p>

<p>Thank you for reading!</p>

<p><a href="#top" style="float: right"><strong>Back to Top<svg width="12" height="12" viewBox="0 0 24 24" aria-hidden="true"><path fill="currentColor" d="M12 4l-8 8h5v8h6v-8h5z"></path></svg></strong> </a></p>]]></content><author><name>Shivam Saraswat</name></author><category term="Security Engineering" /><category term="Supply Chain Security" /><category term="SLSA" /><category term="OpenSSF" /><category term="Open Source" /><summary type="html"><![CDATA[SLSA stands for Supply-chain Levels for Software Artifacts. It is pronounced “salsa”. It is a specification for software supply chain security, maintained by industry consensus under the Linux Foundation. This post explains what SLSA is, how it works, where it applies, and the checks required at each level. It covers version 1.2 of the specification. Official specification: slsa.dev/spec/v1.2]]></summary></entry><entry><title type="html">How to Actually Defend Against AI Static Threats</title><link href="https://blog.shivamsaraswat.com//ai-static-threats-defense/" rel="alternate" type="text/html" title="How to Actually Defend Against AI Static Threats" /><published>2026-03-08T00:00:00+00:00</published><updated>2026-03-08T00:00:00+00:00</updated><id>https://blog.shivamsaraswat.com//ai-static-threats-defense</id><content type="html" xml:base="https://blog.shivamsaraswat.com//ai-static-threats-defense/"><![CDATA[<p>In the <a href="/ai-static-threats/">last post</a>, we went through the static threats that live inside AI models before they ever see a user. Training data poisoning, model backdoors, serialization exploits, weight tampering, hardcoded behavior, weight theft, and compression artifacts. These are not theoretical. They are real, documented, and growing as a concern as more organizations build and deploy models at speed.</p>

<p>This post is about what you can do about them. Not in theory. In practice, today, with tools that exist.</p>

<!--more-->

<hr />

<h2 id="contents-">Contents <a name="top"></a></h2>
<ul id="markdown-toc">
  <li><a href="#start-with-the-right-mental-model" id="markdown-toc-start-with-the-right-mental-model">Start With the Right Mental Model</a></li>
  <li><a href="#measure-1-verify-model-files-before-loading" id="markdown-toc-measure-1-verify-model-files-before-loading">Measure 1: Verify Model Files Before Loading</a></li>
  <li><a href="#measure-2-scan-models-with-security-tools" id="markdown-toc-measure-2-scan-models-with-security-tools">Measure 2: Scan Models With Security Tools</a></li>
  <li><a href="#measure-3-verify-hashes-and-provenance" id="markdown-toc-measure-3-verify-hashes-and-provenance">Measure 3: Verify Hashes and Provenance</a></li>
  <li><a href="#measure-4-run-behavioral-evaluations-before-deployment" id="markdown-toc-measure-4-run-behavioral-evaluations-before-deployment">Measure 4: Run Behavioral Evaluations Before Deployment</a></li>
  <li><a href="#measure-5-audit-training-data-pipelines" id="markdown-toc-measure-5-audit-training-data-pipelines">Measure 5: Audit Training Data Pipelines</a></li>
  <li><a href="#measure-6-lock-down-access-to-model-weights" id="markdown-toc-measure-6-lock-down-access-to-model-weights">Measure 6: Lock Down Access to Model Weights</a></li>
  <li><a href="#measure-7-validate-quantized-or-compressed-models" id="markdown-toc-measure-7-validate-quantized-or-compressed-models">Measure 7: Validate Quantized or Compressed Models</a></li>
  <li><a href="#building-a-process-not-just-using-tools" id="markdown-toc-building-a-process-not-just-using-tools">Building a Process, Not Just Using Tools</a></li>
  <li><a href="#the-honest-state-of-things" id="markdown-toc-the-honest-state-of-things">The Honest State of Things</a></li>
</ul>

<hr />

<h2 id="start-with-the-right-mental-model">Start With the Right Mental Model</h2>

<p>Before getting into specifics, it helps to reframe how you think about model deployment. Most teams treat the model as output: something you receive, load, and use. Security thinking lives at the edges, in the API, in the prompt handling, in access controls.</p>

<p>But the model file itself is infrastructure. It is more like a binary you are running than a document you are reading. And you should treat it the way you treat any third-party binary: with verification, scanning, and a clear chain of trust.</p>

<p>Once you have that framing, the rest follows.</p>

<hr />

<h2 id="measure-1-verify-model-files-before-loading">Measure 1: Verify Model Files Before Loading</h2>

<p>The first thing to do is stop loading model files without checking them.</p>

<p>This sounds simple, but a huge number of workflows skip it. Someone runs a tutorial, copies a <code class="language-plaintext highlighter-rouge">torch.load()</code> call, and loads a model they pulled from a repository. That call can execute code in the file. No exploit needed. Just loading is enough.</p>

<p><strong>What to do:</strong></p>

<p>Use the <code class="language-plaintext highlighter-rouge">weights_only=True</code> parameter in PyTorch when loading model files. This blocks the code execution path.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Risky
</span><span class="n">model</span> <span class="o">=</span> <span class="n">torch</span><span class="p">.</span><span class="nf">load</span><span class="p">(</span><span class="sh">"</span><span class="s">model.pt</span><span class="sh">"</span><span class="p">)</span>

<span class="c1"># Safe
</span><span class="n">model</span> <span class="o">=</span> <span class="n">torch</span><span class="p">.</span><span class="nf">load</span><span class="p">(</span><span class="sh">"</span><span class="s">model.pt</span><span class="sh">"</span><span class="p">,</span> <span class="n">weights_only</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
</code></pre></div></div>

<p>Better yet, move to the <code class="language-plaintext highlighter-rouge">safetensors</code> format entirely. It was built specifically to avoid the serialization problem. It stores weights and nothing else. There is no code execution surface.</p>

<p>The <a href="https://github.com/huggingface/safetensors">safetensors library</a> is maintained by Hugging Face and supports all the major frameworks. Switching is not hard, and most model hubs are beginning to prioritize it.</p>

<hr />

<h2 id="measure-2-scan-models-with-security-tools">Measure 2: Scan Models With Security Tools</h2>

<p>Model scanning is a real thing now, not just a future idea. A few tools are worth knowing.</p>

<p><strong>ModelScan</strong> — open-source, built by Protect AI. It scans model files for unsafe serialization patterns, including pickle exploits. You can run it before loading any downloaded model.</p>

<p>GitHub: <a href="https://github.com/protectai/modelscan">protectai/modelscan</a></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pip <span class="nb">install </span>modelscan
modelscan <span class="nt">-p</span> path/to/model.pkl
</code></pre></div></div>

<p><strong>Protect AI Guardian</strong> — the commercial version of the above, with a broader set of checks and integrations into ML pipelines.</p>

<p><strong>HiddenLayer Model Scanner</strong> — another scanner that checks models for known malicious patterns. HiddenLayer has published research on backdoors in computational graphs (the ShadowLogic work), so their tooling reflects real threat research.</p>

<p>These tools will not catch everything, especially novel backdoors. But they catch known attack patterns and unsafe file formats, which covers a lot of the threat surface for models pulled from public repositories.</p>

<hr />

<h2 id="measure-3-verify-hashes-and-provenance">Measure 3: Verify Hashes and Provenance</h2>

<p>When you download a model from a repository, verify the hash. Most repositories provide SHA256 hashes alongside model files. Check them.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sha256sum </span>model.safetensors
</code></pre></div></div>

<p>Compare the output to what the repository lists. If they match, the file is what was uploaded. That is not a full guarantee of safety, but it tells you no one tampered with it in transit or on the host.</p>

<p>For internal models, treat weights the way you treat build artifacts. Version them. Store them with checksums. Log who accessed them and when. If you are using object storage like S3 or GCS, enable versioning and access logging. Model weights can walk out the door just like source code can.</p>

<hr />

<h2 id="measure-4-run-behavioral-evaluations-before-deployment">Measure 4: Run Behavioral Evaluations Before Deployment</h2>

<p>This is how you catch backdoors and hardcoded behavior that no file scanner will find, because they live in the weights, not in the file format.</p>

<p>The idea is to test the model across a range of inputs, including inputs that test for known backdoor trigger patterns, before you deploy it. This is called behavioral evaluation or red-teaming at the model level.</p>

<p><strong>What this looks like in practice:</strong></p>

<p>Build a test suite that covers the behaviors you care about. Run the model against edge cases, unusual inputs, and inputs that probe for inconsistency between what the model says about itself and what it does. If you are using a base model from a public source, run it through a standard set of jailbreak and trigger probes before you fine-tune.</p>

<p><strong>Tools that help:</strong></p>

<p><a href="https://github.com/NVIDIA/garak">Garak</a> — open-source, from NVIDIA. It is a framework for probing LLMs for a range of vulnerabilities including hallucination, data leakage, and backdoor-style behaviors. It is easy to run and generates reports you can act on.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pip <span class="nb">install </span>garak
python <span class="nt">-m</span> garak <span class="nt">--model_type</span> huggingface <span class="nt">--model_name</span> your-model <span class="nt">--probes</span> all
</code></pre></div></div>

<p><a href="https://github.com/mnns/LLMFuzzer">LLM-Fuzzer</a> — a fuzzing tool for language models, useful for finding unexpected behavior under input variation.</p>

<p><a href="https://github.com/Azure/PyRIT">Microsoft PyRIT</a> — Python Risk Identification Toolkit for Generative AI. Built for red-teaming AI systems at scale. Covers a range of risk categories and is well-documented.</p>

<p>None of these are backdoor detectors in a strict sense. But they are how you build evidence that a model behaves consistently, which is the closest thing you have to assurance.</p>

<hr />

<h2 id="measure-5-audit-training-data-pipelines">Measure 5: Audit Training Data Pipelines</h2>

<p>If you are training or fine-tuning models on data you collected or sourced, you need a process for reviewing that data before it goes into training.</p>

<p>This is analogous to input validation in software security. You do not trust external input. You inspect it, filter it, and log what you kept and what you dropped.</p>

<p><strong>Practical steps:</strong></p>

<p>For web-scraped data, use content filtering to remove known malicious domains, hate content, and adversarial patterns. Tools like <a href="https://github.com/allenai/dolma">Dolma</a> from AI2 include filtering pipelines you can adapt.</p>

<p>For fine-tuning data from internal or third-party sources, do a human review sample at minimum. If the dataset is large, sample 1-2% and have someone read it. You are looking for content that would teach the model something you did not intend.</p>

<p>Keep records of what data you trained on. If you discover a problem later, you need to know whether the training data is the likely source.</p>

<hr />

<h2 id="measure-6-lock-down-access-to-model-weights">Measure 6: Lock Down Access to Model Weights</h2>

<p>Weight theft is often overlooked because it does not feel like a security incident until the model shows up somewhere it should not be.</p>

<p>Model weights are files. They need access controls.</p>

<p><strong>Basic controls:</strong></p>

<p>Restrict who can read model files in your storage systems. Not everyone on the team needs access to the weights. Apply least privilege: the inference server needs read access, most developers do not.</p>

<p>Log access to weight files. If a weight file is downloaded or copied, you want to know.</p>

<p>Encrypt model weights at rest and in transit. This does not stop an insider who has legitimate access, but it raises the bar for external attackers and reduces exposure from misconfigured storage buckets (a common issue).</p>

<p>If you are serving models via API, the weights should never be directly reachable by clients. The inference layer sits in between. But also be aware that a determined attacker with API access can probe your model to reconstruct its behavior, a process called model extraction. Rate limiting, output watermarking, and anomaly detection on query patterns are the defenses here.</p>

<hr />

<h2 id="measure-7-validate-quantized-or-compressed-models">Measure 7: Validate Quantized or Compressed Models</h2>

<p>If you are using a third-party quantized model, or if someone on your team compresses a model for deployment, treat the output as a new artifact that needs testing.</p>

<p>The compressed model is not the same model that was evaluated. Run your behavioral test suite against it. Check that safety behaviors held through compression. Check that outputs on your evaluation sets match expectations.</p>

<p>This is not a one-time thing. Every time a model is quantized, pruned, or otherwise transformed, the resulting artifact needs to go through the same checks as the original.</p>

<hr />

<h2 id="building-a-process-not-just-using-tools">Building a Process, Not Just Using Tools</h2>

<p>Tools help. But the bigger shift is having a process where model files are treated as something you verify, not just something you use.</p>

<p>In practice, this looks like:</p>

<p>A checklist that runs before any model is loaded into production. It covers format verification, hash checking, scanning, and behavioral evaluation. No model goes to production without passing it.</p>

<p>A record of where every model in production came from. The source, the version, the checks it passed, and when. This is your audit trail.</p>

<p>A clear owner for model security. Someone whose job includes asking “where did this model come from and do we trust it?” before deployment happens.</p>

<p>This does not require a large team. It requires a small amount of process and the willingness to treat the model file as infrastructure rather than output.</p>

<hr />

<h2 id="the-honest-state-of-things">The Honest State of Things</h2>

<p>Some of these threats do not have strong technical defenses yet. Backdoor detection in trained weights is still an open research problem. There is no tool you can run that will reliably tell you whether a model has a backdoor embedded in it. The research cited in the <a href="/ai-static-threats/">previous post</a> shows that backdoors can survive fine-tuning, which means even building on top of a compromised model does not clean it.</p>

<p>What you have instead is a combination of supply chain hygiene, behavioral testing, and file-level scanning. Together, these raise the bar significantly. They will not catch every attack. But they make your model deployment look much less like an open door.</p>

<p>The field is moving. Backdoor detection research is active. Model scanning tooling is improving. Formats like safetensors are gaining adoption. The picture in two years will look different from today.</p>

<hr />

<p><em>For now: verify what you load, scan what you can, test how the model behaves, and keep records of where it came from. That is not everything. But it is where to start.</em></p>

<hr />

<p>Tools mentioned in this post: <a href="https://github.com/huggingface/safetensors">safetensors</a>, <a href="https://github.com/protectai/modelscan">ModelScan</a>, <a href="https://github.com/NVIDIA/garak">Garak</a>, <a href="https://github.com/Azure/PyRIT">Microsoft PyRIT</a>, <a href="https://github.com/allenai/dolma">Dolma</a></p>

<hr />

<p><strong>Feel free to <a href="/contact/">contact me</a> for any suggestions and feedbacks. I would really appreciate those.</strong></p>

<p>Thank you for reading!</p>

<p><a href="#top" style="float: right"><strong>Back to Top⮭</strong> </a></p>]]></content><author><name>Shivam Saraswat</name></author><category term="Security Engineering" /><category term="AI" /><category term="AI Security" /><category term="AI Threats" /><category term="Static Threats" /><category term="Secure AI" /><summary type="html"><![CDATA[In the last post, we went through the static threats that live inside AI models before they ever see a user. Training data poisoning, model backdoors, serialization exploits, weight tampering, hardcoded behavior, weight theft, and compression artifacts. These are not theoretical. They are real, documented, and growing as a concern as more organizations build and deploy models at speed. This post is about what you can do about them. Not in theory. In practice, today, with tools that exist.]]></summary></entry><entry><title type="html">The AI Threats Nobody Talks About</title><link href="https://blog.shivamsaraswat.com//ai-static-threats/" rel="alternate" type="text/html" title="The AI Threats Nobody Talks About" /><published>2026-03-07T00:00:00+00:00</published><updated>2026-03-07T00:00:00+00:00</updated><id>https://blog.shivamsaraswat.com//ai-static-threats</id><content type="html" xml:base="https://blog.shivamsaraswat.com//ai-static-threats/"><![CDATA[<p>Everyone in the AI space knows about prompt injection. Someone slips a bad instruction into a model’s input at runtime, and the model does something it shouldn’t. It’s the kind of attack that gets blog posts, conference talks, and CVEs. But there is a whole category of threats that get almost no attention, and they are arguably harder to detect and fix. These are static threats: vulnerabilities that live inside the model itself, before it ever sees a single user input.</p>

<p>This post is about those threats.</p>

<!--more-->

<hr />

<h2 id="contents-">Contents <a name="top"></a></h2>
<ul id="markdown-toc">
  <li><a href="#what-do-we-mean-by-static" id="markdown-toc-what-do-we-mean-by-static">What Do We Mean by “Static”?</a></li>
  <li><a href="#the-static-threats" id="markdown-toc-the-static-threats">The Static Threats</a>    <ul>
      <li><a href="#1-training-data-poisoning" id="markdown-toc-1-training-data-poisoning">1. Training Data Poisoning</a></li>
      <li><a href="#2-model-backdoors-trojan-models" id="markdown-toc-2-model-backdoors-trojan-models">2. Model Backdoors (Trojan Models)</a></li>
      <li><a href="#3-serialization-exploits-in-model-files" id="markdown-toc-3-serialization-exploits-in-model-files">3. Serialization Exploits in Model Files</a></li>
      <li><a href="#4-supply-chain-attacks-on-model-weights" id="markdown-toc-4-supply-chain-attacks-on-model-weights">4. Supply Chain Attacks on Model Weights</a></li>
      <li><a href="#5-bias-and-hardcoded-behavior-in-weights" id="markdown-toc-5-bias-and-hardcoded-behavior-in-weights">5. Bias and Hardcoded Behavior in Weights</a></li>
      <li><a href="#6-model-theft-and-weight-extraction" id="markdown-toc-6-model-theft-and-weight-extraction">6. Model Theft and Weight Extraction</a></li>
      <li><a href="#7-quantization-and-compression-artifacts" id="markdown-toc-7-quantization-and-compression-artifacts">7. Quantization and Compression Artifacts</a></li>
    </ul>
  </li>
  <li><a href="#why-this-gets-less-attention-than-prompt-injection" id="markdown-toc-why-this-gets-less-attention-than-prompt-injection">Why This Gets Less Attention Than Prompt Injection</a></li>
  <li><a href="#what-needs-to-change" id="markdown-toc-what-needs-to-change">What Needs to Change</a></li>
  <li><a href="#coming-up-next" id="markdown-toc-coming-up-next">Coming Up Next</a></li>
</ul>

<hr />

<h2 id="what-do-we-mean-by-static">What Do We Mean by “Static”?</h2>

<p>A dynamic threat happens at runtime. The model is running, a user sends something, and that input triggers harmful behavior.</p>

<p>A static threat is different. It lives in the model’s weights, its training data, its file format, or its supply chain. It is there before deployment. It is there before the first request. And in many cases, the people deploying the model have no idea.</p>

<p>As more organizations build models in-house or pull models from open-source repositories, this matters more than ever. You can have the best prompt filtering in the world and still be running a model that is compromised at the foundation.</p>

<hr />

<h2 id="the-static-threats">The Static Threats</h2>

<h3 id="1-training-data-poisoning">1. Training Data Poisoning</h3>

<p>This is where it starts. A model learns from data. If someone can influence what data goes into training, they can influence what the model learns.</p>

<p>The attack works by injecting content into datasets before or during collection. This content is designed to teach the model specific behaviors. It might cause the model to produce false information on a particular topic. It might make the model favor certain outputs. It might plant a trigger that activates later.</p>

<p>What makes this hard to defend against is scale. Training datasets are often enormous. No one reads them in full. Automated filters catch some things but not everything, especially when the poisoned content is designed to look normal.</p>

<p>For organizations that train on data scraped from the web, or that fine-tune on data they did not fully audit, this threat is real and present today.</p>

<hr />

<h3 id="2-model-backdoors-trojan-models">2. Model Backdoors (Trojan Models)</h3>

<p>A backdoor in a model works like this: the model behaves normally in almost every situation, but when it encounters a specific trigger, it produces a specific output that an attacker designed.</p>

<p>The trigger might be a word, a phrase, a symbol, or even a pattern in an image. The model is trained to respond to it in a way that looks unintentional from the outside. Users see an error or an unusual output. They might not even notice something is wrong.</p>

<p>This kind of attack can happen during training, during fine-tuning, or even during model merging. And because the backdoor is stored in the weights, you cannot remove it by changing the model’s instructions or system prompt. It is part of the model.</p>

<p>Research has shown that backdoors can survive fine-tuning. That means even if an organization takes a compromised base model and fine-tunes it on their own data, the backdoor can persist.</p>

<blockquote>
  <p><strong>Key research on this:</strong></p>
  <ul>
    <li><a href="https://arxiv.org/abs/2401.05566">Sleeper Agents: Training Deceptive LLMs that Persist Through Safety Training</a> (Hubinger et al., Anthropic, 2024) — showed that backdoor behavior persists through supervised fine-tuning, reinforcement learning, and adversarial training. In one test, a model was trained to write safe code in 2023 but insert code vulnerabilities in 2024. Safety training failed to remove this.</li>
    <li><a href="https://arxiv.org/abs/2505.16567">Watch your steps: Dormant Adversarial Behaviors that Activate upon LLM Finetuning</a> (Gloaguen et al., 2025) — demonstrated that an attacker can release a model that looks clean but activates harmful behavior only after a downstream user fine-tunes it on their own data.</li>
    <li><a href="https://www.sciltp.com/journals/tai/articles/2505000595">A Survey on Backdoor Threats in Large Language Models</a> (2025) — found that even parameter-efficient fine-tuning methods like LoRA are insufficient to remove backdoors, because they update too few parameters to overwrite what was embedded in pretraining.</li>
  </ul>
</blockquote>

<hr />

<h3 id="3-serialization-exploits-in-model-files">3. Serialization Exploits in Model Files</h3>

<p>This one is underappreciated even by people who think about security.</p>

<p>Model weights are stored in files. The most common format for PyTorch models is <code class="language-plaintext highlighter-rouge">pickle</code>. And <code class="language-plaintext highlighter-rouge">pickle</code> is a format that can execute code when it is loaded.</p>

<p>This means that a model file downloaded from the internet, when loaded with <code class="language-plaintext highlighter-rouge">torch.load()</code>, can run code on your machine without you doing anything other than loading the model. The weights might be perfectly fine, but the file itself is a vector for code execution.</p>

<p>This is not a theoretical attack. There have been cases of models uploaded to repositories that include pickle exploits. When you download and load them, you are running code someone else wrote.</p>

<p>The fix exists. PyTorch has a <code class="language-plaintext highlighter-rouge">weights_only=True</code> parameter. Safer formats like <code class="language-plaintext highlighter-rouge">safetensors</code> exist. But a lot of tooling, tutorials, and workflows still use the defaults.</p>

<hr />

<h3 id="4-supply-chain-attacks-on-model-weights">4. Supply Chain Attacks on Model Weights</h3>

<p>The open-source model ecosystem has grown fast. Repositories like Hugging Face host thousands of models. Developers pull these models and use them directly, or use them as a base for fine-tuning.</p>

<p>The problem is trust. When you download a model, how do you know the weights have not been modified? A weight tampering attack involves changing a trained model’s weights in a targeted way, altering its behavior without changing the architecture or the file structure in a way that would be obvious.</p>

<p>Model hashes exist. Some repositories show them. But many users do not verify them. And even if the hash matches the repository, it only tells you the file is the same as what was uploaded. It says nothing about whether the weights are safe.</p>

<hr />

<h3 id="5-bias-and-hardcoded-behavior-in-weights">5. Bias and Hardcoded Behavior in Weights</h3>

<p>This threat is different in nature. It is not always the work of an attacker. Sometimes it is the result of the training process itself.</p>

<p>Models can learn behaviors from training data that are never intended and never documented. These behaviors can be consistent and predictable, which is what makes them a threat. They can also be deliberately introduced during fine-tuning by a party that has access to the training pipeline.</p>

<p>In an internal model built at an organization, the fine-tuning data controls a lot. If someone with access to that process wants to embed behavior into the model, whether it is a tendency to downplay certain topics, steer outputs in a direction, or produce unreliable outputs in specific contexts, the weights are where that happens.</p>

<p>This is hard to audit because there is no “check weights for bias” function. It requires testing, evaluation sets, and the knowledge of what to look for in the first place.</p>

<hr />

<h3 id="6-model-theft-and-weight-extraction">6. Model Theft and Weight Extraction</h3>

<p>This is a threat to the organization that built the model rather than to its users.</p>

<p>Once a model is deployed, an attacker can send it many queries and use the responses to reconstruct the model’s behavior. In some cases, they can get close to recovering the weights themselves. In other cases, they can build a model that imitates the target closely enough to compete with it.</p>

<p>But there is also a simpler version of this threat: someone inside the organization copies the weights and takes them somewhere else. Model weights are files. They can fit on a USB drive. They can be uploaded to a cloud bucket. If the weights are not treated with the same care as source code or proprietary data, they will not be protected like source code or proprietary data.</p>

<hr />

<h3 id="7-quantization-and-compression-artifacts">7. Quantization and Compression Artifacts</h3>

<p>When a model is compressed for deployment, through quantization or pruning, its behavior can change in ways that are not fully tested.</p>

<p>This becomes a threat when the compression is done by a third party, or when the compressed model is distributed without proper validation. The model that was tested and approved is not the same model that is running in production. And the differences might be in the directions that matter for safety.</p>

<p>There is also the possibility of deliberate manipulation during quantization, where a model is compressed in a way that introduces specific behavioral changes while looking like a routine optimization step.</p>

<hr />

<h2 id="why-this-gets-less-attention-than-prompt-injection">Why This Gets Less Attention Than Prompt Injection</h2>

<p>Prompt injection is visible. You can demonstrate it in a demo. You can show before and after. It happens at the layer most people interact with.</p>

<p>Static threats are invisible by default. The model looks fine. It passes tests. It gives good answers in evaluation. The threat is waiting for a condition that testing did not cover, or it is already affecting outputs in ways that are not being measured.</p>

<p>There is also an attribution problem. If a model produces a wrong or harmful output, it is easy to assume the model just made a mistake. The idea that the model was deliberately compromised at training time requires a different mental model of how AI systems can fail.</p>

<hr />

<h2 id="what-needs-to-change">What Needs to Change</h2>

<p>The field needs to treat model files the way software engineering treats dependencies: with verification, auditing, and supply chain awareness. It needs to treat training data the way security teams treat input validation: as an attack surface.</p>

<p>Some of this is starting to happen. The <code class="language-plaintext highlighter-rouge">safetensors</code> format is gaining adoption. Some model repositories are adding scanning. Research on backdoor detection is growing.</p>

<p>But for organizations building or deploying models today, especially internal ones where security scrutiny is lower, most of these threats are not on the radar at all.</p>

<p>That needs to change. The model is not just an interface. It is infrastructure. And like any infrastructure, it can be compromised at the foundation.</p>

<hr />

<p><em>If you are building or deploying AI models and want to think through your threat model, start with the weights. That is where the trust begins.</em></p>

<hr />

<h2 id="coming-up-next">Coming Up Next</h2>

<p>Now that we have a map of the threats, the <a href="/ai-static-threats-defense/">next post</a> will get into what you can actually do about them. We will go through the security measures that exist today, the tools you can use to scan models before you deploy them, and how to build a process that treats model files the way software teams treat code: with verification, auditing, and a real sense of what you are trusting. If you are building or running models in production, that post is the one to read next.</p>

<p><strong>Feel free to <a href="/contact/">contact me</a> for any suggestions and feedbacks. I would really appreciate those.</strong></p>

<p>Thank you for reading!</p>

<p><a href="#top" style="float: right"><strong>Back to Top⮭</strong> </a></p>]]></content><author><name>Shivam Saraswat</name></author><category term="Security Engineering" /><category term="AI" /><category term="AI Security" /><category term="AI Threats" /><category term="Prompt Injection" /><category term="Static Threats" /><summary type="html"><![CDATA[Everyone in the AI space knows about prompt injection. Someone slips a bad instruction into a model’s input at runtime, and the model does something it shouldn’t. It’s the kind of attack that gets blog posts, conference talks, and CVEs. But there is a whole category of threats that get almost no attention, and they are arguably harder to detect and fix. These are static threats: vulnerabilities that live inside the model itself, before it ever sees a single user input. This post is about those threats.]]></summary></entry><entry><title type="html">The Rising Tide of Software Supply Chain Threats</title><link href="https://blog.shivamsaraswat.com//software-supply-chain-security/" rel="alternate" type="text/html" title="The Rising Tide of Software Supply Chain Threats" /><published>2025-11-15T00:00:00+00:00</published><updated>2025-11-15T00:00:00+00:00</updated><id>https://blog.shivamsaraswat.com//software-supply-chain-security</id><content type="html" xml:base="https://blog.shivamsaraswat.com//software-supply-chain-security/"><![CDATA[<h2 id="why-owasp-top-10-2025s-3-risk-demands-your-immediate-attention">Why OWASP Top 10 2025’s #3 Risk Demands Your Immediate Attention</h2>

<p>In November 2025, the Open Web Application Security Project (OWASP) released its eighth edition of the Top 10 security risks, and the message is clear: software supply chain security has graduated from a niche concern to one of the <strong>most critical threats</strong> facing modern organizations. Ranked at position #3 with an alarming 5.19% incidence rate, Software Supply Chain Failures represents a paradigm shift in how we must approach application security.</p>

<!--more-->

<hr />

<h2 id="contents-">Contents <a name="top"></a></h2>
<ul id="markdown-toc">
  <li><a href="#why-owasp-top-10-2025s-3-risk-demands-your-immediate-attention" id="markdown-toc-why-owasp-top-10-2025s-3-risk-demands-your-immediate-attention">Why OWASP Top 10 2025’s #3 Risk Demands Your Immediate Attention</a></li>
  <li><a href="#the-wake-up-call-why-now" id="markdown-toc-the-wake-up-call-why-now">The Wake-Up Call: Why Now?</a></li>
  <li><a href="#understanding-the-evolution" id="markdown-toc-understanding-the-evolution">Understanding the Evolution</a>    <ul>
      <li><a href="#2013-the-beginning" id="markdown-toc-2013-the-beginning">2013: The Beginning</a></li>
      <li><a href="#2017-maintaining-status" id="markdown-toc-2017-maintaining-status">2017: Maintaining Status</a></li>
      <li><a href="#2021-broadening-scope" id="markdown-toc-2021-broadening-scope">2021: Broadening Scope</a></li>
      <li><a href="#2025-the-paradigm-shift" id="markdown-toc-2025-the-paradigm-shift">2025: The Paradigm Shift</a></li>
    </ul>
  </li>
  <li><a href="#why-this-matters-to-your-organization" id="markdown-toc-why-this-matters-to-your-organization">Why This Matters to Your Organization</a>    <ul>
      <li><a href="#the-attack-surface-has-exploded" id="markdown-toc-the-attack-surface-has-exploded">The Attack Surface Has Exploded</a></li>
      <li><a href="#developers-are-now-prime-targets" id="markdown-toc-developers-are-now-prime-targets">Developers Are Now Prime Targets</a></li>
      <li><a href="#the-trust-problem" id="markdown-toc-the-trust-problem">The Trust Problem</a></li>
    </ul>
  </li>
  <li><a href="#taking-action-protecting-your-supply-chain" id="markdown-toc-taking-action-protecting-your-supply-chain">Taking Action: Protecting Your Supply Chain</a>    <ul>
      <li><a href="#1-maintain-software-bill-of-materials-sbom" id="markdown-toc-1-maintain-software-bill-of-materials-sbom">1. Maintain Software Bill of Materials (SBOM)</a></li>
      <li><a href="#2-implement-software-composition-analysis-sca" id="markdown-toc-2-implement-software-composition-analysis-sca">2. Implement Software Composition Analysis (SCA)</a></li>
      <li><a href="#3-verify-package-integrity" id="markdown-toc-3-verify-package-integrity">3. Verify Package Integrity</a></li>
      <li><a href="#4-secure-your-cicd-pipeline" id="markdown-toc-4-secure-your-cicd-pipeline">4. Secure Your CI/CD Pipeline</a></li>
      <li><a href="#5-harden-developer-workstations" id="markdown-toc-5-harden-developer-workstations">5. Harden Developer Workstations</a></li>
      <li><a href="#6-adopt-dependency-management-best-practices" id="markdown-toc-6-adopt-dependency-management-best-practices">6. Adopt Dependency Management Best Practices</a></li>
    </ul>
  </li>
  <li><a href="#the-bottom-line" id="markdown-toc-the-bottom-line">The Bottom Line</a></li>
  <li><a href="#whats-next" id="markdown-toc-whats-next">What’s Next?</a></li>
</ul>

<hr />

<h2 id="the-wake-up-call-why-now">The Wake-Up Call: Why Now?</h2>

<p>The elevation of supply chain security to the #3 position isn’t arbitrary. It reflects the harsh reality of our interconnected software ecosystem. In the 2025 community survey, <strong>exactly 50% of respondents ranked supply chain failures as their #1 concern</strong>, making it the most voted risk category in OWASP history.</p>

<p>The stakes have never been higher. Recent attacks demonstrate the devastating potential:</p>

<ul>
  <li><strong>Shai Hulud worm (September 2025):</strong> First successful self-replicating attack in the npm ecosystem, compromising 500+ packages and harvesting credentials from developer machines through malicious post-install scripts</li>
  <li><strong>GlassWorm attack (2025):</strong> Malicious VS Code marketplace extension deployed self-replicating code that harvested secrets from developer machines and emptied crypto wallets</li>
  <li><strong>SolarWinds compromise (2020):</strong> Affected over 18,000 organizations globally through compromised software updates</li>
</ul>

<h2 id="understanding-the-evolution">Understanding the Evolution</h2>

<p>To understand why supply chain security has become so critical, we need to trace its evolution through OWASP’s Top 10 lists:</p>

<h3 id="2013-the-beginning">2013: The Beginning</h3>

<p><strong>A9 – Using Components with Known Vulnerabilities</strong> first appeared in 2013. At this stage, the focus was narrow: organizations simply needed to update libraries with known security flaws. The solution seemed straightforward: patch your dependencies.</p>

<h3 id="2017-maintaining-status">2017: Maintaining Status</h3>

<p>The risk persisted at <strong>A9:2017 - Using Components with Known Vulnerabilities</strong>, remaining in the same position. While the problem was recognized, the scope hadn’t expanded beyond vulnerable components.</p>

<h3 id="2021-broadening-scope">2021: Broadening Scope</h3>

<p>By 2021, the category evolved to <strong>A06:2021 - Vulnerable and Outdated Components</strong>. The name change reflected growing awareness that the problem wasn’t just about known vulnerabilities — outdated components, even without CVEs, posed significant risks.</p>

<h3 id="2025-the-paradigm-shift">2025: The Paradigm Shift</h3>

<p>Now, in 2025, we have <strong>A03:2025 - Software Supply Chain Failures</strong> (jumped to #3 position!). This isn’t just a name change — it’s a fundamental reimagining of the threat. The scope now encompasses <em>everything</em> involved in building, distributing, and updating software:</p>

<ul>
  <li>Third-party dependencies and libraries</li>
  <li>Build systems and CI/CD pipelines</li>
  <li>Package repositories (npm, PyPI, Maven Central)</li>
  <li>Developer tools and IDE extensions</li>
  <li>Distribution infrastructure</li>
  <li>Software update mechanisms</li>
</ul>

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1600 1200" width="1600" height="1200">
  <defs>
    <linearGradient id="grad1" x1="0%" y1="0%" x2="100%" y2="100%">
      <stop offset="0%" style="stop-color:#667eea;stop-opacity:1" />
      <stop offset="100%" style="stop-color:#764ba2;stop-opacity:1" />
    </linearGradient>
    <linearGradient id="grad2" x1="0%" y1="0%" x2="100%" y2="0%">
      <stop offset="0%" style="stop-color:#f093fb;stop-opacity:1" />
      <stop offset="100%" style="stop-color:#f5576c;stop-opacity:1" />
    </linearGradient>
    <linearGradient id="grad3" x1="0%" y1="0%" x2="100%" y2="0%">
      <stop offset="0%" style="stop-color:#4facfe;stop-opacity:1" />
      <stop offset="100%" style="stop-color:#00f2fe;stop-opacity:1" />
    </linearGradient>
    <linearGradient id="grad4" x1="0%" y1="0%" x2="100%" y2="0%">
      <stop offset="0%" style="stop-color:#43e97b;stop-opacity:1" />
      <stop offset="100%" style="stop-color:#38f9d7;stop-opacity:1" />
    </linearGradient>
    <linearGradient id="grad5" x1="0%" y1="0%" x2="100%" y2="0%">
      <stop offset="0%" style="stop-color:#fa709a;stop-opacity:1" />
      <stop offset="100%" style="stop-color:#fee140;stop-opacity:1" />
    </linearGradient>
    
    <filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
      <feGaussianBlur in="SourceAlpha" stdDeviation="3" />
      <feOffset dx="2" dy="2" result="offsetblur" />
      <feComponentTransfer>
        <feFuncA type="linear" slope="0.3" />
      </feComponentTransfer>
      <feMerge>
        <feMergeNode />
        <feMergeNode in="SourceGraphic" />
      </feMerge>
    </filter>
  </defs>
  
  <!-- Background -->
  <rect width="1600" height="1200" fill="url(#grad1)" />
  
  <!-- Title -->
  <text x="800" y="60" font-family="Arial, sans-serif" font-size="36" font-weight="bold" fill="white" text-anchor="middle">
    OWASP Top 10: Software Supply Chain Security Evolution
  </text>
  <text x="800" y="95" font-family="Arial, sans-serif" font-size="18" fill="white" text-anchor="middle" opacity="0.9">
    From Component Vulnerabilities to Software Supply Chain Failures (2013-2025)
  </text>
  
  <!-- Central Node -->
  <circle cx="800" cy="600" r="120" fill="white" filter="url(#shadow)" />
  <circle cx="800" cy="600" r="110" fill="#667eea" />
  <text x="800" y="590" font-family="Arial, sans-serif" font-size="20" font-weight="bold" fill="white" text-anchor="middle">
    Supply Chain
  </text>
  <text x="800" y="615" font-family="Arial, sans-serif" font-size="20" font-weight="bold" fill="white" text-anchor="middle">
    Security
  </text>
  
  <!-- Connecting Lines -->
  <line x1="800" y1="480" x2="800" y2="250" stroke="white" stroke-width="3" opacity="0.6" />
  <line x1="920" y1="600" x2="1150" y2="600" stroke="white" stroke-width="3" opacity="0.6" />
  <line x1="800" y1="720" x2="800" y2="950" stroke="white" stroke-width="3" opacity="0.6" />
  <line x1="680" y1="600" x2="450" y2="600" stroke="white" stroke-width="3" opacity="0.6" />
  
  <!-- 2013 Node (Top) -->
  <g transform="translate(800, 200)">
    <rect x="-160" y="-80" width="320" height="160" rx="15" fill="white" filter="url(#shadow)" />
    <rect x="-155" y="-75" width="310" height="150" rx="12" fill="url(#grad2)" />
    <text x="0" y="-45" font-family="Arial, sans-serif" font-size="28" font-weight="bold" fill="white" text-anchor="middle">2013</text>
    <text x="0" y="-15" font-family="Arial, sans-serif" font-size="16" font-weight="bold" fill="white" text-anchor="middle">Position #9</text>
    <text x="0" y="10" font-family="Arial, sans-serif" font-size="13" fill="white" text-anchor="middle">A9: Using Components with</text>
    <text x="0" y="30" font-family="Arial, sans-serif" font-size="13" fill="white" text-anchor="middle">Known Vulnerabilities</text>
    <text x="0" y="55" font-family="Arial, sans-serif" font-size="11" fill="white" text-anchor="middle" opacity="0.9">Focus: Patch your dependencies</text>
  </g>
  
  <!-- 2017 Node (Right) -->
  <g transform="translate(1280, 600)">
    <rect x="-160" y="-80" width="320" height="160" rx="15" fill="white" filter="url(#shadow)" />
    <rect x="-155" y="-75" width="310" height="150" rx="12" fill="url(#grad3)" />
    <text x="0" y="-45" font-family="Arial, sans-serif" font-size="28" font-weight="bold" fill="white" text-anchor="middle">2017</text>
    <text x="0" y="-15" font-family="Arial, sans-serif" font-size="16" font-weight="bold" fill="white" text-anchor="middle">Position #9</text>
    <text x="0" y="10" font-family="Arial, sans-serif" font-size="13" fill="white" text-anchor="middle">A9: Using Components with</text>
    <text x="0" y="30" font-family="Arial, sans-serif" font-size="13" fill="white" text-anchor="middle">Known Vulnerabilities</text>
    <text x="0" y="55" font-family="Arial, sans-serif" font-size="11" fill="white" text-anchor="middle" opacity="0.9">Status: Unchanged scope</text>
  </g>
  
  <!-- 2021 Node (Bottom) -->
  <g transform="translate(800, 1000)">
    <rect x="-160" y="-80" width="320" height="160" rx="15" fill="white" filter="url(#shadow)" />
    <rect x="-155" y="-75" width="310" height="150" rx="12" fill="url(#grad4)" />
    <text x="0" y="-45" font-family="Arial, sans-serif" font-size="28" font-weight="bold" fill="white" text-anchor="middle">2021</text>
    <text x="0" y="-15" font-family="Arial, sans-serif" font-size="16" font-weight="bold" fill="white" text-anchor="middle">Position #6 ⬆</text>
    <text x="0" y="10" font-family="Arial, sans-serif" font-size="13" fill="white" text-anchor="middle">A06: Vulnerable and</text>
    <text x="0" y="30" font-family="Arial, sans-serif" font-size="13" fill="white" text-anchor="middle">Outdated Components</text>
    <text x="0" y="55" font-family="Arial, sans-serif" font-size="11" fill="white" text-anchor="middle" opacity="0.9">Broader: Not just CVEs</text>
  </g>
  
  <!-- 2025 Node (Left) -->
  <g transform="translate(320, 600)">
    <rect x="-160" y="-100" width="320" height="200" rx="15" fill="white" filter="url(#shadow)" />
    <rect x="-155" y="-95" width="310" height="190" rx="12" fill="url(#grad5)" />
    <text x="0" y="-65" font-family="Arial, sans-serif" font-size="28" font-weight="bold" fill="white" text-anchor="middle">2025 🚀</text>
    <text x="0" y="-35" font-family="Arial, sans-serif" font-size="16" font-weight="bold" fill="white" text-anchor="middle">Position #3 ⬆⬆</text>
    <text x="0" y="-5" font-family="Arial, sans-serif" font-size="13" fill="white" text-anchor="middle">A03: Software Supply</text>
    <text x="0" y="15" font-family="Arial, sans-serif" font-size="13" fill="white" text-anchor="middle">Chain Failures</text>
    <text x="0" y="40" font-family="Arial, sans-serif" font-size="11" fill="white" text-anchor="middle" opacity="0.9">50% voted #1 concern</text>
    <text x="0" y="60" font-family="Arial, sans-serif" font-size="11" fill="white" text-anchor="middle" opacity="0.9">5.19% incidence rate</text>
    <text x="0" y="80" font-family="Arial, sans-serif" font-size="11" fill="white" text-anchor="middle" opacity="0.9">Highest exploit score</text>
  </g>
  
  <!-- Key Changes Box -->
  <g transform="translate(100, 200)">
    <rect x="0" y="0" width="280" height="280" rx="10" fill="white" opacity="0.95" filter="url(#shadow)" />
    <text x="140" y="30" font-family="Arial, sans-serif" font-size="16" font-weight="bold" fill="#667eea" text-anchor="middle">
      Key Evolution
    </text>
    <line x1="20" y1="40" x2="260" y2="40" stroke="#667eea" stroke-width="2" />
    
    <text x="20" y="65" font-family="Arial, sans-serif" font-size="12" font-weight="bold" fill="#333">2013-2017:</text>
    <text x="20" y="82" font-family="Arial, sans-serif" font-size="11" fill="#555">• Narrow focus on CVEs</text>
    <text x="20" y="98" font-family="Arial, sans-serif" font-size="11" fill="#555">• Simple patching</text>
    
    <text x="20" y="125" font-family="Arial, sans-serif" font-size="12" font-weight="bold" fill="#333">2021:</text>
    <text x="20" y="142" font-family="Arial, sans-serif" font-size="11" fill="#555">• Outdated components</text>
    <text x="20" y="158" font-family="Arial, sans-serif" font-size="11" fill="#555">• Unmaintained libs</text>
    
    <text x="20" y="185" font-family="Arial, sans-serif" font-size="12" font-weight="bold" fill="#333">2025:</text>
    <text x="20" y="202" font-family="Arial, sans-serif" font-size="11" fill="#555">• Entire supply chain</text>
    <text x="20" y="218" font-family="Arial, sans-serif" font-size="11" fill="#555">• CI/CD pipelines</text>
    <text x="20" y="234" font-family="Arial, sans-serif" font-size="11" fill="#555">• Build systems</text>
    <text x="20" y="250" font-family="Arial, sans-serif" font-size="11" fill="#555">• Developer tools</text>
    <text x="20" y="266" font-family="Arial, sans-serif" font-size="11" fill="#555">• Self-replicating attacks</text>
  </g>
  
  <!-- Real-World Examples Box -->
  <g transform="translate(1220, 200)">
    <rect x="0" y="0" width="300" height="280" rx="10" fill="white" opacity="0.95" filter="url(#shadow)" />
    <text x="150" y="30" font-family="Arial, sans-serif" font-size="16" font-weight="bold" fill="#667eea" text-anchor="middle">
      Real-World Attacks
    </text>
    <line x1="20" y1="40" x2="280" y2="40" stroke="#667eea" stroke-width="2" />
    
    <text x="20" y="65" font-family="Arial, sans-serif" font-size="12" font-weight="bold" fill="#d63031">Shai Hulud (Sep 2025)</text>
    <text x="20" y="82" font-family="Arial, sans-serif" font-size="11" fill="#555">First self-replicating npm</text>
    <text x="20" y="98" font-family="Arial, sans-serif" font-size="11" fill="#555">worm, 500+ packages</text>
    <text x="20" y="114" font-family="Arial, sans-serif" font-size="11" fill="#555">compromised</text>
    
    <text x="20" y="141" font-family="Arial, sans-serif" font-size="12" font-weight="bold" fill="#d63031">GlassWorm (2025)</text>
    <text x="20" y="158" font-family="Arial, sans-serif" font-size="11" fill="#555">VS Code marketplace</text>
    <text x="20" y="174" font-family="Arial, sans-serif" font-size="11" fill="#555">extension attack</text>
    
    <text x="20" y="201" font-family="Arial, sans-serif" font-size="12" font-weight="bold" fill="#d63031">SolarWinds (2020)</text>
    <text x="20" y="218" font-family="Arial, sans-serif" font-size="11" fill="#555">18,000+ organizations</text>
    <text x="20" y="234" font-family="Arial, sans-serif" font-size="11" fill="#555">affected globally</text>
  </g>
  
  <!-- Impact Indicators -->
  <g transform="translate(1220, 830)">
    <rect x="0" y="0" width="300" height="200" rx="10" fill="white" opacity="0.95" filter="url(#shadow)" />
    <text x="150" y="30" font-family="Arial, sans-serif" font-size="16" font-weight="bold" fill="#667eea" text-anchor="middle">
      2025 Statistics
    </text>
    <line x1="20" y1="40" x2="280" y2="40" stroke="#667eea" stroke-width="2" />
    
    <circle cx="40" cy="70" r="15" fill="#fa709a" />
    <text x="70" y="75" font-family="Arial, sans-serif" font-size="13" font-weight="bold" fill="#333">50% Community Vote</text>
    <text x="70" y="92" font-family="Arial, sans-serif" font-size="11" fill="#555">Ranked as #1 concern</text>
    
    <circle cx="40" cy="125" r="15" fill="#fee140" />
    <text x="70" y="130" font-family="Arial, sans-serif" font-size="13" font-weight="bold" fill="#333">5.19% Incidence</text>
    <text x="70" y="147" font-family="Arial, sans-serif" font-size="11" fill="#555">Highest in Top 10</text>
    
    <circle cx="40" cy="180" r="15" fill="#f5576c" />
    <text x="70" y="185" font-family="Arial, sans-serif" font-size="13" font-weight="bold" fill="#333">Highest Impact</text>
  </g>
  
  <!-- Threat Scope Box -->
  <g transform="translate(100, 830)">
    <rect x="0" y="0" width="280" height="240" rx="10" fill="white" opacity="0.95" filter="url(#shadow)" />
    <text x="140" y="30" font-family="Arial, sans-serif" font-size="16" font-weight="bold" fill="#667eea" text-anchor="middle">
      2025 Threat Scope
    </text>
    <line x1="20" y1="40" x2="260" y2="40" stroke="#667eea" stroke-width="2" />
    
    <text x="20" y="65" font-family="Arial, sans-serif" font-size="11" fill="#555">✓ Dependencies &amp; libraries</text>
    <text x="20" y="85" font-family="Arial, sans-serif" font-size="11" fill="#555">✓ Build systems</text>
    <text x="20" y="105" font-family="Arial, sans-serif" font-size="11" fill="#555">✓ CI/CD pipelines</text>
    <text x="20" y="125" font-family="Arial, sans-serif" font-size="11" fill="#555">✓ Package repositories</text>
    <text x="20" y="145" font-family="Arial, sans-serif" font-size="11" fill="#555">✓ Developer workstations</text>
    <text x="20" y="165" font-family="Arial, sans-serif" font-size="11" fill="#555">✓ IDE extensions</text>
    <text x="20" y="185" font-family="Arial, sans-serif" font-size="11" fill="#555">✓ Distribution infrastructure</text>
    <text x="20" y="205" font-family="Arial, sans-serif" font-size="11" fill="#555">✓ Update mechanisms</text>
    <text x="20" y="225" font-family="Arial, sans-serif" font-size="11" fill="#555">✓ Entire build process</text>
  </g>
  
  <!-- Footer -->
  <text x="800" y="1180" font-family="Arial, sans-serif" font-size="14" fill="white" text-anchor="middle" opacity="0.8">
    OWASP Top 10:2025 | Source: https://owasp.org/Top10/
  </text>
</svg>

<h2 id="why-this-matters-to-your-organization">Why This Matters to Your Organization</h2>

<h3 id="the-attack-surface-has-exploded">The Attack Surface Has Exploded</h3>

<p>Modern applications are built on stacks of dependencies. A typical web application might have hundreds or thousands of direct and transitive dependencies. Each one represents a potential entry point for attackers.</p>

<blockquote>
  <p><em>“Despite the increased scope, supply chain failures continue to be a challenge to identify with only 11 Common Vulnerability and Exposures (CVEs) having the related CWEs.”</em> — (OWASP Top 10:2025)</p>
</blockquote>

<p>This detection challenge is precisely what makes supply chain attacks so dangerous. Traditional security tools struggle to identify these threats, yet they have the <strong>highest average exploit and impact scores</strong> from CVEs in the entire OWASP Top 10.</p>

<h3 id="developers-are-now-prime-targets">Developers Are Now Prime Targets</h3>

<p>The GlassWorm attack demonstrated a terrifying evolution: attackers are now targeting <strong>developer workstations</strong> as entry points. By compromising developer tools and extensions, malicious actors gain access to trusted environments where traditional security controls are often relaxed.</p>

<p>Once a developer’s machine is compromised, the malware can:</p>

<ul>
  <li>Harvest credentials and API tokens</li>
  <li>Inject malicious code into repositories</li>
  <li>Propagate through CI/CD pipelines</li>
  <li>Access production environments</li>
</ul>

<h3 id="the-trust-problem">The Trust Problem</h3>

<p>Supply chain attacks exploit our fundamental need to trust external code. When you install a package from npm or PyPI, you’re implicitly trusting:</p>

<ul>
  <li>The package maintainer’s security practices</li>
  <li>The integrity of the repository infrastructure</li>
  <li>All transitive dependencies</li>
  <li>The build and distribution pipeline</li>
</ul>

<p>A compromise at any point in this chain can cascade throughout your entire application.</p>

<h2 id="taking-action-protecting-your-supply-chain">Taking Action: Protecting Your Supply Chain</h2>

<p>OWASP’s recommendations for managing supply chain risk focus on visibility, verification, and vigilance:</p>

<h3 id="1-maintain-software-bill-of-materials-sbom">1. Maintain Software Bill of Materials (SBOM)</h3>

<p>Know exactly what’s in your software stack. An SBOM provides a comprehensive inventory of all components, including transitive dependencies. This visibility is crucial for rapid response when vulnerabilities are disclosed.</p>

<h3 id="2-implement-software-composition-analysis-sca">2. Implement Software Composition Analysis (SCA)</h3>

<p>Use automated tools to continuously monitor your dependencies for:</p>

<ul>
  <li>Known vulnerabilities (CVEs)</li>
  <li>Outdated or unmaintained components</li>
  <li>License compliance issues</li>
  <li>Suspicious package updates</li>
</ul>

<h3 id="3-verify-package-integrity">3. Verify Package Integrity</h3>

<p>Only obtain components from official, trusted sources over secure channels. Prefer signed packages to reduce the risk of including modified, malicious components. Verify checksums and signatures before use.</p>

<h3 id="4-secure-your-cicd-pipeline">4. Secure Your CI/CD Pipeline</h3>

<p>Your build infrastructure is now part of your attack surface. Treat CI/CD systems with the same rigor as production:</p>

<ul>
  <li>Implement strong access controls and authentication</li>
  <li>Use separate credentials for different pipeline stages</li>
  <li>Monitor and log all pipeline activities</li>
  <li>Scan build artifacts for malware</li>
</ul>

<h3 id="5-harden-developer-workstations">5. Harden Developer Workstations</h3>

<p>Given that developers are now prime targets, secure their environments:</p>

<ul>
  <li>Restrict and monitor IDE extension installations</li>
  <li>Implement endpoint detection and response (EDR) solutions</li>
  <li>Use separate accounts for development and browsing</li>
  <li>Regularly scan for compromised credentials</li>
</ul>

<h3 id="6-adopt-dependency-management-best-practices">6. Adopt Dependency Management Best Practices</h3>

<ul>
  <li>Pin dependency versions instead of using version ranges</li>
  <li>Review and test updates before deploying</li>
  <li>Monitor for suspicious update patterns</li>
  <li>Consider using private package mirrors</li>
  <li>Implement virtual patches when direct updates aren’t possible</li>
</ul>

<h2 id="the-bottom-line">The Bottom Line</h2>

<p>The elevation of Software Supply Chain Failures to position #3 in the OWASP Top 10 isn’t just a ranking — it’s a <strong>call to action</strong>. The attacks are real, the consequences are severe, and the threat is only growing.</p>

<p>With the highest incidence rate (5.19%) and the highest average exploit and impact scores, supply chain failures represent a perfect storm of prevalence, difficulty to detect, and potential damage. Organizations that treat this as just another checkbox security item do so at their peril.</p>

<p>The message from OWASP is clear: supply chain security is no longer optional. It’s not a future problem — it’s a <strong>right now</strong> problem that demands immediate, sustained attention.</p>

<h2 id="whats-next">What’s Next?</h2>

<p>Start by conducting a supply chain risk assessment for your organization:</p>

<ol>
  <li>Inventory all dependencies across your applications</li>
  <li>Identify critical components and high-risk dependencies</li>
  <li>Assess your current visibility and monitoring capabilities</li>
  <li>Evaluate your CI/CD pipeline security</li>
  <li>Review developer workstation security policies</li>
  <li>Implement continuous monitoring and alerting</li>
</ol>

<p>The full OWASP Top 10:2025 is available at <strong><a href="https://owasp.org/Top10/">https://owasp.org/Top10/</a></strong>.</p>

<hr />

<p><em>The software supply chain has become one of the most critical battlegrounds in cybersecurity. The question isn’t whether your organization will be targeted — it’s whether you’ll be prepared when it happens.</em></p>

<hr />

<p><strong>Feel free to <a href="/contact/">contact me</a> for any suggestions and feedbacks. I would really appreciate those.</strong></p>

<p>Thank you for reading!</p>

<p><a href="#top" style="float: right"><strong>Back to Top⮭</strong> </a></p>]]></content><author><name>Shivam Saraswat</name></author><category term="Security Engineering" /><category term="DevSecOps" /><category term="Supply Chain Security" /><category term="OWASP Top 10" /><summary type="html"><![CDATA[Why OWASP Top 10 2025’s #3 Risk Demands Your Immediate Attention In November 2025, the Open Web Application Security Project (OWASP) released its eighth edition of the Top 10 security risks, and the message is clear: software supply chain security has graduated from a niche concern to one of the most critical threats facing modern organizations. Ranked at position #3 with an alarming 5.19% incidence rate, Software Supply Chain Failures represents a paradigm shift in how we must approach application security.]]></summary></entry><entry><title type="html">Why Your Node.js App Has Golang Vulnerabilities (And What To Do About It)</title><link href="https://blog.shivamsaraswat.com//golang-vuln-in-nodejs/" rel="alternate" type="text/html" title="Why Your Node.js App Has Golang Vulnerabilities (And What To Do About It)" /><published>2025-10-10T00:00:00+00:00</published><updated>2025-10-10T00:00:00+00:00</updated><id>https://blog.shivamsaraswat.com//golang-vuln-in-nodejs</id><content type="html" xml:base="https://blog.shivamsaraswat.com//golang-vuln-in-nodejs/"><![CDATA[<p><em>A practical guide to understanding and fixing a common security scanner false alarm.</em></p>

<!--more-->

<hr />

<h2 id="contents-">Contents <a name="top"></a></h2>
<ul id="markdown-toc">
  <li><a href="#the-mysterious-alert" id="markdown-toc-the-mysterious-alert">The Mysterious Alert</a></li>
  <li><a href="#the-plot-twist-your-javascript-tools-are-written-in-go" id="markdown-toc-the-plot-twist-your-javascript-tools-are-written-in-go">The Plot Twist: Your JavaScript Tools Are Written in Go</a></li>
  <li><a href="#real-world-example-the-vanilla-extract-mystery" id="markdown-toc-real-world-example-the-vanilla-extract-mystery">Real-World Example: The Vanilla Extract Mystery</a></li>
  <li><a href="#the-critical-question-should-you-care" id="markdown-toc-the-critical-question-should-you-care">The Critical Question: Should You Care?</a>    <ul>
      <li><a href="#understanding-build-time-vs-runtime" id="markdown-toc-understanding-build-time-vs-runtime">Understanding Build-Time vs Runtime</a></li>
      <li><a href="#the-risk-matrix" id="markdown-toc-the-risk-matrix">The Risk Matrix</a></li>
    </ul>
  </li>
  <li><a href="#solution-1-multi-stage-docker-builds-best-practice" id="markdown-toc-solution-1-multi-stage-docker-builds-best-practice">Solution 1: Multi-Stage Docker Builds (Best Practice)</a>    <ul>
      <li><a href="#bad-single-stage-build" id="markdown-toc-bad-single-stage-build">Bad: Single-Stage Build</a></li>
      <li><a href="#good-multi-stage-build" id="markdown-toc-good-multi-stage-build">Good: Multi-Stage Build</a></li>
      <li><a href="#verification" id="markdown-toc-verification">Verification</a></li>
    </ul>
  </li>
  <li><a href="#solution-2-remove-unnecessary-build-tools" id="markdown-toc-solution-2-remove-unnecessary-build-tools">Solution 2: Remove Unnecessary Build Tools</a>    <ul>
      <li><a href="#case-study-css-in-js-libraries" id="markdown-toc-case-study-css-in-js-libraries">Case Study: CSS-in-JS Libraries</a></li>
      <li><a href="#before-removing-check-usage" id="markdown-toc-before-removing-check-usage">Before Removing, Check Usage</a></li>
    </ul>
  </li>
  <li><a href="#solution-3-update-dependencies" id="markdown-toc-solution-3-update-dependencies">Solution 3: Update Dependencies</a></li>
  <li><a href="#solution-4-configure-your-security-scanner" id="markdown-toc-solution-4-configure-your-security-scanner">Solution 4: Configure Your Security Scanner</a>    <ul>
      <li><a href="#github-dependabot-dependabotyml" id="markdown-toc-github-dependabot-dependabotyml">GitHub Dependabot (dependabot.yml)</a></li>
      <li><a href="#npm-audit" id="markdown-toc-npm-audit">npm Audit</a></li>
    </ul>
  </li>
  <li><a href="#solution-5-accept-the-risk-with-documentation" id="markdown-toc-solution-5-accept-the-risk-with-documentation">Solution 5: Accept the Risk (With Documentation)</a>    <ul>
      <li><a href="#risk-acceptance-template" id="markdown-toc-risk-acceptance-template">Risk Acceptance Template</a></li>
    </ul>
  </li>
  <li><a href="#real-world-attack-scenarios" id="markdown-toc-real-world-attack-scenarios">Real-World Attack Scenarios</a>    <ul>
      <li><a href="#scenario-1-direct-web-exploitation" id="markdown-toc-scenario-1-direct-web-exploitation">Scenario 1: Direct Web Exploitation</a></li>
      <li><a href="#scenario-2-container-compromise--binary-execution" id="markdown-toc-scenario-2-container-compromise--binary-execution">Scenario 2: Container Compromise → Binary Execution</a></li>
      <li><a href="#scenario-3-cicd-pipeline-compromise" id="markdown-toc-scenario-3-cicd-pipeline-compromise">Scenario 3: CI/CD Pipeline Compromise</a></li>
    </ul>
  </li>
  <li><a href="#best-practices-checklist" id="markdown-toc-best-practices-checklist">Best Practices Checklist</a>    <ul>
      <li><a href="#for-all-projects" id="markdown-toc-for-all-projects">For All Projects</a></li>
      <li><a href="#for-build-environment" id="markdown-toc-for-build-environment">For Build Environment</a></li>
      <li><a href="#for-dependency-management" id="markdown-toc-for-dependency-management">For Dependency Management</a></li>
    </ul>
  </li>
  <li><a href="#the-bottom-line" id="markdown-toc-the-bottom-line">The Bottom Line</a>    <ul>
      <li><a href="#quick-decision-tree" id="markdown-toc-quick-decision-tree">Quick Decision Tree</a></li>
      <li><a href="#priority-order" id="markdown-toc-priority-order">Priority Order</a></li>
    </ul>
  </li>
  <li><a href="#tools-and-resources" id="markdown-toc-tools-and-resources">Tools and Resources</a>    <ul>
      <li><a href="#dependency-analysis" id="markdown-toc-dependency-analysis">Dependency Analysis</a></li>
      <li><a href="#security-scanning" id="markdown-toc-security-scanning">Security Scanning</a></li>
      <li><a href="#learning-resources" id="markdown-toc-learning-resources">Learning Resources</a></li>
    </ul>
  </li>
  <li><a href="#conclusion" id="markdown-toc-conclusion">Conclusion</a></li>
</ul>

<hr />

<h2 id="the-mysterious-alert">The Mysterious Alert</h2>

<p>You run your security scanner on your Node.js application. Everything’s written in JavaScript and TypeScript. Your <code class="language-plaintext highlighter-rouge">package.json</code> has React, Next.js, Express - all the usual JavaScript suspects.</p>

<p>Then the security report drops:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>🔴 CRITICAL: Golang vulnerability CVE-2024-XXXXX in esbuild
🔴 HIGH: Go binary exploit in @esbuild/linux-x64
⚠️ MEDIUM: Multiple Golang security issues detected
</code></pre></div></div>

<p>Your first reaction: <strong>“But this is a Node.js project. We don’t use Go!”</strong></p>

<p>Welcome to one of the most confusing aspects of modern JavaScript development. Let me explain what’s happening and, more importantly, how to fix it.</p>

<h2 id="the-plot-twist-your-javascript-tools-are-written-in-go">The Plot Twist: Your JavaScript Tools Are Written in Go</h2>

<p>Here’s the reality: some of the most popular JavaScript build tools are actually written in other languages for performance reasons:</p>

<ul>
  <li><strong>esbuild</strong> - Written in Go (50-100x faster than traditional bundlers)</li>
  <li><strong>SWC</strong> - Written in Rust (20-70x faster than Babel)</li>
  <li><strong>Rome/Biome</strong> - Written in Rust</li>
  <li><strong>Turbopack</strong> - Written in Rust</li>
</ul>

<p>When you <code class="language-plaintext highlighter-rouge">npm install</code> these packages, you’re downloading <strong>pre-compiled binaries</strong> for your operating system. These binaries just happen to be Go (or Rust) executables.</p>

<h2 id="real-world-example-the-vanilla-extract-mystery">Real-World Example: The Vanilla Extract Mystery</h2>

<p>Let me share a common scenario I’ve seen dozens of times:</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">//</span><span class="w"> </span><span class="err">Your</span><span class="w"> </span><span class="err">package.json</span><span class="w">
</span><span class="p">{</span><span class="w">
  </span><span class="nl">"dependencies"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"@vanilla-extract/next-plugin"</span><span class="p">:</span><span class="w"> </span><span class="s2">"^2.4.8"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"next"</span><span class="p">:</span><span class="w"> </span><span class="s2">"^15.0.0"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"react"</span><span class="p">:</span><span class="w"> </span><span class="s2">"^18.0.0"</span><span class="w">
  </span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p>Looks innocent, right? But here’s what actually gets installed:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>node_modules/
├── @vanilla-extract/next-plugin/
│   ├── @vanilla-extract/webpack-plugin/
│       └── @vanilla-extract/integration/
│           └── esbuild@0.25.5/
│               ├── @esbuild/darwin-arm64/  ← Go binary <span class="k">for </span>Mac ARM
│               ├── @esbuild/linux-x64/     ← Go binary <span class="k">for </span>Linux
│               ├── @esbuild/win32-x64/     ← Go binary <span class="k">for </span>Windows
│               └── ... <span class="o">(</span>21 more platform binaries<span class="o">)</span>
</code></pre></div></div>

<p><strong>You now have 24 Go binaries in your <code class="language-plaintext highlighter-rouge">node_modules</code>.</strong></p>

<p>Your security scanner finds them, checks for known CVEs, and raises the alarm.</p>

<h2 id="the-critical-question-should-you-care">The Critical Question: Should You Care?</h2>

<p>The answer is nuanced and depends on <strong>when and where</strong> these binaries execute.</p>

<h3 id="understanding-build-time-vs-runtime">Understanding Build-Time vs Runtime</h3>

<pre><code class="language-plain">┌─────────────────────────────────────────────┐
│ Development / CI/CD (Build Time)            │
├─────────────────────────────────────────────┤
│ $ npm install                               │
│   → Downloads esbuild binaries              │
│                                             │
│ $ npm run build                             │
│   → esbuild EXECUTES (compiles your code)   │
│   → Generates optimized JavaScript          │
│                                             │
│ Risk: MEDIUM (if build env compromised)     │
└─────────────────────────────────────────────┘

┌─────────────────────────────────────────────┐
│ Production (Runtime)                        │
├─────────────────────────────────────────────┤
│ $ npm start                                 │
│   → Node.js serves HTTP requests            │
│   → esbuild binary just sits there (idle)   │
│   → NOT executing                           │
│                                             │
│ Risk: LOW (secondary exploit only)          │
└─────────────────────────────────────────────┘
</code></pre>

<h3 id="the-risk-matrix">The Risk Matrix</h3>

<table>
  <thead>
    <tr>
      <th>Scenario</th>
      <th>Can Exploit Go Vulnerability?</th>
      <th>Risk Level</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>User sends HTTP request</strong></td>
      <td>❌ NO - Go binary not in request path</td>
      <td>🟢 VERY LOW</td>
    </tr>
    <tr>
      <td><strong>Attacker gains shell access</strong></td>
      <td>✅ YES - Could execute binary</td>
      <td>🟡 LOW-MEDIUM</td>
    </tr>
    <tr>
      <td><strong>Build environment compromise</strong></td>
      <td>✅ YES - Binary executes during build</td>
      <td>🟠 MEDIUM</td>
    </tr>
  </tbody>
</table>

<p><strong>Key Insight</strong>: Go binaries in production are like having a power drill in your closet. It’s there, but unless someone uses it, it’s not dangerous. And if a burglar breaks into your house, the drill isn’t the primary problem - the break-in is.</p>

<h2 id="solution-1-multi-stage-docker-builds-best-practice">Solution 1: Multi-Stage Docker Builds (Best Practice)</h2>

<p>The cleanest solution is to <strong>keep build tools out of production entirely</strong>.</p>

<h3 id="bad-single-stage-build">Bad: Single-Stage Build</h3>

<div class="language-docker highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">FROM</span><span class="s"> node:20</span>

<span class="k">WORKDIR</span><span class="s"> /app</span>
<span class="k">COPY</span><span class="s"> package*.json ./</span>
<span class="k">RUN </span>npm ci                    <span class="c"># esbuild installed here</span>

<span class="k">COPY</span><span class="s"> . .</span>
<span class="k">RUN </span>npm run build             <span class="c"># esbuild executes here</span>

<span class="k">EXPOSE</span><span class="s"> 3000</span>
<span class="k">CMD</span><span class="s"> ["npm", "start"]          # esbuild STILL in container ⚠️</span>
</code></pre></div></div>

<p><strong>Problem</strong>: All 24 esbuild binaries ship to production unnecessarily.</p>

<h3 id="good-multi-stage-build">Good: Multi-Stage Build</h3>

<div class="language-docker highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># ===== STAGE 1: Build (Temporary) =====</span>
<span class="k">FROM</span><span class="w"> </span><span class="s">node:20</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="s">builder</span>

<span class="k">WORKDIR</span><span class="s"> /app</span>
<span class="k">COPY</span><span class="s"> package*.json ./</span>
<span class="k">RUN </span>npm ci                    <span class="c"># esbuild installed HERE</span>

<span class="k">COPY</span><span class="s"> . .</span>
<span class="k">RUN </span>npm run build             <span class="c"># esbuild executes HERE</span>
<span class="c"># After this, we're done with esbuild ↑</span>

<span class="c"># ===== STAGE 2: Production (What Actually Deploys) =====</span>
<span class="k">FROM</span><span class="w"> </span><span class="s">node:20-slim</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="s">production</span>

<span class="k">WORKDIR</span><span class="s"> /app</span>

<span class="c"># Install ONLY production dependencies (no esbuild!)</span>
<span class="k">COPY</span><span class="s"> package*.json ./</span>
<span class="k">RUN </span>npm ci <span class="nt">--production</span> <span class="nt">--ignore-scripts</span>

<span class="c"># Copy ONLY compiled output from builder</span>
<span class="k">COPY</span><span class="s"> --from=builder /app/dist ./dist</span>
<span class="k">COPY</span><span class="s"> --from=builder /app/.next ./.next</span>
<span class="k">COPY</span><span class="s"> --from=builder /app/public ./public</span>

<span class="c"># Run as non-root user</span>
<span class="k">USER</span><span class="s"> node</span>

<span class="k">EXPOSE</span><span class="s"> 3000</span>
<span class="k">CMD</span><span class="s"> ["npm", "start"]</span>
</code></pre></div></div>

<p><strong>Result</strong>:</p>

<ul>
  <li>Builder stage: Has esbuild, compiles your code</li>
  <li>Production image: <strong>No esbuild binaries at all</strong></li>
  <li>Image size: <strong>~60% smaller</strong></li>
  <li>Security scan: <strong>No more Go vulnerabilities</strong></li>
</ul>

<h3 id="verification">Verification</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Build production image</span>
docker build <span class="nt">-t</span> myapp <span class="nb">.</span>

<span class="c"># Check if esbuild is present</span>
docker run <span class="nt">--rm</span> myapp sh <span class="nt">-c</span> <span class="s2">"find / -name esbuild 2&gt;/dev/null"</span>

<span class="c"># Expected output: (empty)</span>
</code></pre></div></div>

<h2 id="solution-2-remove-unnecessary-build-tools">Solution 2: Remove Unnecessary Build Tools</h2>

<p>Sometimes the tool causing the alert isn’t even needed!</p>

<h3 id="case-study-css-in-js-libraries">Case Study: CSS-in-JS Libraries</h3>

<p>Many projects have this pattern:</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
  </span><span class="nl">"dependencies"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"@vanilla-extract/next-plugin"</span><span class="p">:</span><span class="w"> </span><span class="s2">"^2.4.8"</span><span class="p">,</span><span class="w">  </span><span class="err">//</span><span class="w"> </span><span class="err">←</span><span class="w"> </span><span class="err">Brings</span><span class="w"> </span><span class="err">esbuild</span><span class="w">
    </span><span class="nl">"@emotion/react"</span><span class="p">:</span><span class="w"> </span><span class="s2">"^11.0.0"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"styled-components"</span><span class="p">:</span><span class="w"> </span><span class="s2">"^6.0.0"</span><span class="w">
  </span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p><strong>Question</strong>: Are you actually using <code class="language-plaintext highlighter-rouge">@vanilla-extract</code>?</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Search your codebase</span>
<span class="nb">grep</span> <span class="nt">-r</span> <span class="s2">"@vanilla-extract"</span> <span class="nt">--include</span><span class="o">=</span><span class="s2">"*.tsx"</span> <span class="nt">--include</span><span class="o">=</span><span class="s2">"*.ts"</span> src/

<span class="c"># If no results...</span>
npm uninstall @vanilla-extract/next-plugin

<span class="c"># Problem solved!</span>
</code></pre></div></div>

<h3 id="before-removing-check-usage">Before Removing, Check Usage</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Find .css.ts files (vanilla-extract pattern)</span>
find src/ <span class="nt">-name</span> <span class="s2">"*.css.ts"</span>

<span class="c"># Check Next.js config</span>
<span class="nb">grep</span> <span class="nt">-i</span> <span class="s2">"vanilla"</span> next.config.js

<span class="c"># Check imports</span>
rg <span class="s2">"from ['</span><span class="se">\"</span><span class="s2">@]vanilla-extract"</span> src/
</code></pre></div></div>

<h2 id="solution-3-update-dependencies">Solution 3: Update Dependencies</h2>

<p>Often, newer versions have patched vulnerabilities.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Update specific package</span>
npm update @vanilla-extract/next-plugin

<span class="c"># Update all dependencies</span>
npm update

<span class="c"># Check for security patches</span>
npm audit fix

<span class="c"># For major version updates</span>
npx npm-check-updates <span class="nt">-u</span>
npm <span class="nb">install</span>
</code></pre></div></div>

<h2 id="solution-4-configure-your-security-scanner">Solution 4: Configure Your Security Scanner</h2>

<p>If you’ve confirmed the binaries are build-time only, configure your scanner appropriately.</p>

<h3 id="github-dependabot-dependabotyml">GitHub Dependabot (dependabot.yml)</h3>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">version</span><span class="pi">:</span> <span class="m">2</span>
<span class="na">updates</span><span class="pi">:</span>
  <span class="pi">-</span> <span class="na">package-ecosystem</span><span class="pi">:</span> <span class="s2">"</span><span class="s">npm"</span>
    <span class="na">directory</span><span class="pi">:</span> <span class="s2">"</span><span class="s">/"</span>
    <span class="na">schedule</span><span class="pi">:</span>
      <span class="na">interval</span><span class="pi">:</span> <span class="s2">"</span><span class="s">weekly"</span>
    <span class="na">ignore</span><span class="pi">:</span>
      <span class="c1"># Don't alert on esbuild patch versions</span>
      <span class="pi">-</span> <span class="na">dependency-name</span><span class="pi">:</span> <span class="s2">"</span><span class="s">esbuild"</span>
        <span class="na">update-types</span><span class="pi">:</span> <span class="pi">[</span><span class="s2">"</span><span class="s">version-update:semver-patch"</span><span class="pi">]</span>
</code></pre></div></div>

<h3 id="npm-audit">npm Audit</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Audit only production dependencies</span>
npm audit <span class="nt">--production</span>

<span class="c"># Generate report excluding dev dependencies</span>
npm audit <span class="nt">--production</span> <span class="nt">--json</span> <span class="o">&gt;</span> audit-report.json
</code></pre></div></div>

<h2 id="solution-5-accept-the-risk-with-documentation">Solution 5: Accept the Risk (With Documentation)</h2>

<p>For some projects, the Go binaries are unavoidable. Document why.</p>

<h3 id="risk-acceptance-template">Risk Acceptance Template</h3>

<pre><code class="language-plain">## Security Finding: esbuild Go Vulnerabilities

**Package**: esbuild@0.25.5 (via @vanilla-extract/next-plugin)
**CVEs**: CVE-2024-XXXXX, CVE-2024-YYYYY
**Severity**: MEDIUM

**Risk Assessment**:
- Vulnerability exists in build-time tooling only
- Not present in production container (multi-stage build)
- Not accessible to end users
- Build environment secured with:
  - Ephemeral build agents
  - Network segmentation
  - Access controls
  - Build process monitoring

**Mitigation Strategies**:
1. Multi-stage Docker builds (binaries not in production)
2. Build environment hardening (non-root, read-only FS)
3. Regular dependency updates (monthly)
4. Continuous monitoring for new CVEs

**Business Justification**:
- @vanilla-extract required by component library
- No viable alternative for our use case
- Performance benefits outweigh minimal risk

**Risk Level**: LOW (secondary exploit vector only)

**Accepted By**: Security Team
**Date**: 2025-10-01
**Next Review**: 2026-03-01
</code></pre>

<h2 id="real-world-attack-scenarios">Real-World Attack Scenarios</h2>

<p>Let’s be concrete about what could actually happen.</p>

<h3 id="scenario-1-direct-web-exploitation">Scenario 1: Direct Web Exploitation</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Attacker → HTTP Request → Your App
                            ↓
                         Node.js handles request
                         esbuild NOT involved

Result: esbuild vulnerability IRRELEVANT
</code></pre></div></div>

<p><strong>Risk</strong>: None. The Go binary doesn’t execute.</p>

<h3 id="scenario-2-container-compromise--binary-execution">Scenario 2: Container Compromise → Binary Execution</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Step 1: Attacker exploits DIFFERENT vulnerability (e.g., RCE in express)
Step 2: Gains shell access to container
Step 3: Discovers esbuild binary
Step 4: Attempts to exploit esbuild CVE for privilege escalation

Result: Could work, but you're already compromised
</code></pre></div></div>

<p><strong>Risk</strong>: Low-Medium. The real problem was Step 1.</p>

<h3 id="scenario-3-cicd-pipeline-compromise">Scenario 3: CI/CD Pipeline Compromise</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Step 1: Attacker compromises build server
Step 2: npm install runs → esbuild post-install scripts execute
Step 3: Exploits esbuild vulnerability DURING BUILD
Step 4: Injects malicious code into build artifacts

Result: Supply chain attack
</code></pre></div></div>

<p><strong>Risk</strong>: Medium. This is the most realistic threat.</p>

<p><strong>Mitigation</strong>:</p>

<ul>
  <li>Isolated, ephemeral build agents</li>
  <li>Signed commits required</li>
  <li>Build artifact signing and verification</li>
  <li>Network egress monitoring during builds</li>
</ul>

<h2 id="best-practices-checklist">Best Practices Checklist</h2>

<h3 id="for-all-projects">For All Projects</h3>

<ul>
  <li>Use multi-stage Docker builds</li>
  <li>Run production containers as non-root user</li>
  <li>Implement read-only root filesystem where possible</li>
  <li>Regular dependency updates (automated, but reviewed by engineers)</li>
  <li>Security scanning in CI/CD pipeline</li>
  <li>Document accepted risks</li>
</ul>

<h3 id="for-build-environment">For Build Environment</h3>

<ul>
  <li>Ephemeral build agents (destroyed after each build)</li>
  <li>Network segmentation for build infrastructure</li>
  <li>Artifact signing and verification</li>
  <li>Build process monitoring and alerting</li>
  <li>Access controls on build systems</li>
</ul>

<h3 id="for-dependency-management">For Dependency Management</h3>

<ul>
  <li>Lock file committed to version control</li>
  <li>Use <code class="language-plaintext highlighter-rouge">npm ci</code> not <code class="language-plaintext highlighter-rouge">npm install</code> in production</li>
  <li>Regular security audits (<code class="language-plaintext highlighter-rouge">npm audit</code>)</li>
  <li>Dependency update automation (Dependabot, Renovate, etc.)</li>
  <li>Review new dependencies before adding</li>
</ul>

<h2 id="the-bottom-line">The Bottom Line</h2>

<p>Finding Go vulnerabilities in your Node.js project is <strong>surprisingly common</strong> and <strong>usually low risk</strong> if handled correctly.</p>

<h3 id="quick-decision-tree">Quick Decision Tree</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Go vulnerabilities detected
         ↓
Is the package needed?
         ├─ NO → Remove it
         └─ YES
              ↓
         Is it in production image?
              ├─ NO → Multi-stage build
              └─ YES
                   ↓
              Can you use multi-stage builds?
                   ├─ YES → Implement them
                   └─ NO → Document risk + harden container
</code></pre></div></div>

<h3 id="priority-order">Priority Order</h3>

<ol>
  <li><strong>Remove if possible</strong> (fastest, zero risk)</li>
  <li><strong>Multi-stage builds</strong> (best practice)</li>
  <li><strong>Update dependencies</strong> (ongoing maintenance)</li>
  <li><strong>Configure scanners</strong> (reduce noise)</li>
  <li><strong>Document accepted risk</strong> (compliance)</li>
</ol>

<h2 id="tools-and-resources">Tools and Resources</h2>

<h3 id="dependency-analysis">Dependency Analysis</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Why is this package installed?</span>
npm <span class="nb">ls </span>esbuild

<span class="c"># Full dependency tree</span>
npm <span class="nb">ls</span> <span class="nt">--all</span> <span class="o">&gt;</span> dependency-tree.txt

<span class="c"># Find all Go binaries</span>
find node_modules <span class="nt">-name</span> <span class="s2">"*.go"</span> <span class="nt">-o</span> <span class="nt">-name</span> <span class="s2">"*darwin*"</span> <span class="nt">-o</span> <span class="nt">-name</span> <span class="s2">"*linux*"</span> | <span class="nb">grep</span> <span class="nt">-i</span> esbuild

<span class="c"># Check production vs dev dependencies</span>
npm <span class="nb">ls</span> <span class="nt">--production</span>
npm <span class="nb">ls</span> <span class="nt">--dev</span>
</code></pre></div></div>

<h3 id="security-scanning">Security Scanning</h3>

<ul>
  <li><a href="https://docs.npmjs.com/cli/v8/commands/npm-audit">npm audit</a> - Built-in npm security audit</li>
  <li><a href="https://socket.dev/">Socket.dev</a> - Supply chain security</li>
  <li><a href="https://github.com/aquasecurity/trivy">Trivy</a> - Container scanning</li>
</ul>

<h3 id="learning-resources">Learning Resources</h3>

<ul>
  <li><a href="https://esbuild.github.io/faq/#why-is-esbuild-fast">Why is esbuild fast?</a></li>
  <li><a href="https://docs.docker.com/build/building/multi-stage/">Docker Multi-Stage Builds</a></li>
  <li><a href="https://nodejs.org/en/learn/getting-started/security-best-practices">Node.js Security Best Practices</a></li>
</ul>

<h2 id="conclusion">Conclusion</h2>

<p>Go vulnerabilities in Node.js projects are a symptom of the modern JavaScript ecosystem’s reliance on high-performance native tooling. While the initial security alert can be alarming, the actual risk is often much lower than it appears.</p>

<p>The key is understanding:</p>

<ol>
  <li><strong>When</strong> these binaries execute (build-time vs runtime)</li>
  <li><strong>Where</strong> they’re deployed (development, CI/CD, production)</li>
  <li><strong>How</strong> to properly isolate them (multi-stage builds, containerization)</li>
</ol>

<p>By following the solutions outlined in this post, you can either <strong>eliminate</strong> these vulnerabilities entirely (best outcome) or <strong>properly contextualize</strong> them with appropriate mitigations (acceptable outcome).</p>

<hr />

<p><em>Remember: <strong>presence doesn’t equal execution</strong>. Just because a binary is in your <code class="language-plaintext highlighter-rouge">node_modules</code> doesn’t mean it poses a direct threat. Focus your security efforts on the vulnerabilities that are actually in your runtime attack surface.</em></p>

<hr />

<p><strong>Feel free to <a href="/contact/">contact me</a> for any suggestions and feedbacks. I would really appreciate those.</strong></p>

<p>Thank you for reading!</p>

<p><a href="#top" style="float: right"><strong>Back to Top⮭</strong> </a></p>]]></content><author><name>Shivam Saraswat</name></author><category term="Security Engineering" /><category term="DevSecOps" /><category term="Dependencies" /><category term="Web Security" /><summary type="html"><![CDATA[A practical guide to understanding and fixing a common security scanner false alarm.]]></summary></entry><entry><title type="html">Why Running AI Coding Tools in Pipelines is a Security Risk</title><link href="https://blog.shivamsaraswat.com//ai-threat-in-pipelines/" rel="alternate" type="text/html" title="Why Running AI Coding Tools in Pipelines is a Security Risk" /><published>2025-09-24T00:00:00+00:00</published><updated>2025-09-24T00:00:00+00:00</updated><id>https://blog.shivamsaraswat.com//ai-threat-in-pipelines</id><content type="html" xml:base="https://blog.shivamsaraswat.com//ai-threat-in-pipelines/"><![CDATA[<p>Recently I have observed more development teams using AI coding assistants like Claude Code directly in their CI/CD pipelines. While the productivity gains can be impressive, this trend is raising serious security concerns that every organization should understand.</p>

<!--more-->

<hr />

<h2 id="contents-">Contents <a name="top"></a></h2>
<ul id="markdown-toc">
  <li><a href="#whats-happening" id="markdown-toc-whats-happening">What’s Happening</a></li>
  <li><a href="#the-security-risks" id="markdown-toc-the-security-risks">The Security Risks</a>    <ul>
      <li><a href="#your-code-is-leaving-your-building" id="markdown-toc-your-code-is-leaving-your-building">Your Code is Leaving Your Building</a></li>
      <li><a href="#the-black-box-problem" id="markdown-toc-the-black-box-problem">The Black Box Problem</a></li>
      <li><a href="#pipeline-compromise-risks" id="markdown-toc-pipeline-compromise-risks">Pipeline Compromise Risks</a></li>
      <li><a href="#real-world-example-the-nx-attack" id="markdown-toc-real-world-example-the-nx-attack">Real-World Example: The Nx Attack</a></li>
      <li><a href="#compliance-headaches" id="markdown-toc-compliance-headaches">Compliance Headaches</a></li>
    </ul>
  </li>
  <li><a href="#what-this-means-for-your-organization" id="markdown-toc-what-this-means-for-your-organization">What This Means for Your Organization</a>    <ul>
      <li><a href="#key-questions-to-ask" id="markdown-toc-key-questions-to-ask">Key Questions to Ask</a></li>
    </ul>
  </li>
  <li><a href="#recommendations" id="markdown-toc-recommendations">Recommendations</a></li>
</ul>

<hr />

<h2 id="whats-happening">What’s Happening</h2>

<p>Developers are integrating AI tools into their automated build and deployment processes. Instead of just using AI to write code on their local machines, they’re having AI make changes automatically as part of their software delivery pipeline. This means AI can modify code, update configurations, and make decisions without human oversight.</p>

<h2 id="the-security-risks">The Security Risks</h2>

<h3 id="your-code-is-leaving-your-building">Your Code is Leaving Your Building</h3>

<p>When you use AI tools in pipelines, your source code gets sent to external servers. This includes not just the code itself, but potentially sensitive configuration files, API keys, and business logic. You’re essentially giving a third party access to your intellectual property and secrets.</p>

<h3 id="the-black-box-problem">The Black Box Problem</h3>

<p>We don’t really know how these AI systems make decisions. When Claude Code suggests a change, we can’t audit why it made that choice or predict what it might do in unusual situations. This makes it nearly impossible to do proper security reviews or debug problems when they occur.</p>

<h3 id="pipeline-compromise-risks">Pipeline Compromise Risks</h3>

<p>AI tools running in your pipeline have the same permissions as your build system. If something goes wrong, the AI could accidentally break security controls, bypass safety gates, or make changes that introduce vulnerabilities. There’s also the risk of prompt injection attacks where malicious input could trick the AI into doing something harmful.</p>

<h3 id="real-world-example-the-nx-attack">Real-World Example: The Nx Attack</h3>

<p>In August 2025, attackers compromised the popular Nx build tool and specifically targeted AI development tools. The malware checked for Claude Code CLI and other AI tools, then used them with carefully crafted prompts to search for cryptocurrency wallets and credentials on infected systems.</p>

<p>What made this attack particularly dangerous was that the malicious logic was hidden in natural language prompts rather than traditional code, making it much harder for security tools to detect. Over 1,400 people had their credentials and wallet information stolen.</p>

<h3 id="compliance-headaches">Compliance Headaches</h3>

<p>Many industries require detailed audit trails and accountability for code changes. When AI makes automated changes, it becomes difficult to meet these requirements. Who is responsible when the AI introduces a security bug? How do you explain to auditors that you can’t fully explain why certain changes were made?</p>

<h2 id="what-this-means-for-your-organization">What This Means for Your Organization</h2>

<p>If your teams are experimenting with AI in pipelines, you need to establish guardrails now rather than later. The risks aren’t just theoretical - attackers are already adapting to exploit these new tools.</p>

<h3 id="key-questions-to-ask">Key Questions to Ask</h3>

<ul>
  <li>Do we know what data our AI tools are sending to external services?</li>
  <li>Can we audit and review all AI-generated changes?</li>
  <li>Do we have proper access controls limiting what AI can modify?</li>
  <li>Are we meeting our compliance requirements with automated AI changes?</li>
  <li>Do we have incident response plans for AI-related security issues?</li>
</ul>

<h2 id="recommendations">Recommendations</h2>

<p>This doesn’t mean you should ban AI tools entirely. Instead, take a measured approach:</p>

<p><strong>Start with guardrails.</strong> Require security review for any AI integration in pipelines. Establish clear policies about what data can be shared with external AI services.<br />
<strong>Maintain human oversight.</strong> Don’t let AI make changes without human review, especially in production systems.<br />
<strong>Know your data flows.</strong> Understand exactly what information is being sent to AI services and ensure sensitive data is protected.<br />
<strong>Plan for incidents.</strong> Have a response plan ready for when things go wrong with AI-generated code.<br /></p>

<p>The potential of AI in development is enormous, but we need to be smart about how we adopt these tools. Security teams and developers need to work together to harness the benefits while managing the risks.</p>

<p><strong>Sources:</strong></p>

<ul>
  <li><a href="https://semgrep.dev/blog/2025/security-alert-nx-compromised-to-steal-wallets-and-credentials/">Security Alert: NX Compromised to Steal Wallets and Credentials</a> - Semgrep</li>
  <li><a href="https://github.com/nrwl/nx/security/advisories/GHSA-cxm3-wv7p-598c">Official Nx Security Advisory</a> - GitHub</li>
  <li><a href="https://www.linkedin.com/pulse/we-dont-actually-know-how-claude-code-works-thats-problem-knuth-vqu7f/">We Don’t Actually Know How Claude Code Works - That’s a Problem</a> - LinkedIn</li>
</ul>

<hr />

<p><em>The key is finding the right balance between innovation and security. Don’t let the excitement of new AI capabilities blind you to the fundamental security principles that have served us well for decades.</em></p>

<hr />

<p><strong>Feel free to <a href="/contact/">contact me</a> for any suggestions and feedbacks. I would really appreciate those.</strong></p>

<p>Thank you for reading!</p>

<p><a href="#top" style="float: right"><strong>Back to Top⮭</strong> </a></p>]]></content><author><name>Shivam Saraswat</name></author><category term="AI" /><category term="Security Engineering" /><category term="DevSecOps" /><summary type="html"><![CDATA[Recently I have observed more development teams using AI coding assistants like Claude Code directly in their CI/CD pipelines. While the productivity gains can be impressive, this trend is raising serious security concerns that every organization should understand.]]></summary></entry><entry><title type="html">Did Your Threat Model Actually Work?</title><link href="https://blog.shivamsaraswat.com//verify-threat-model/" rel="alternate" type="text/html" title="Did Your Threat Model Actually Work?" /><published>2025-09-17T00:00:00+00:00</published><updated>2025-09-17T00:00:00+00:00</updated><id>https://blog.shivamsaraswat.com//verify-threat-model</id><content type="html" xml:base="https://blog.shivamsaraswat.com//verify-threat-model/"><![CDATA[<p>You’ve done the hard work. Your team created a comprehensive threat model, identified risks, and handed recommendations to the development team. But here’s the million-dollar question: <strong>How do you know they actually implemented the security controls?</strong></p>

<p>If you’re like most security teams, you’re probably hoping developers added the right code comments, wrote proper tests, and followed all your recommendations. But let’s be honest – that’s not always realistic.</p>

<p>Here’s how to independently verify that your threat model recommendations actually made it into production.</p>

<!--more-->

<hr />

<h2 id="contents-">Contents <a name="top"></a></h2>
<ul id="markdown-toc">
  <li><a href="#the-problem-with-developer-dependent-verification" id="markdown-toc-the-problem-with-developer-dependent-verification">The Problem with Developer-Dependent Verification</a></li>
  <li><a href="#the-independent-verification-approach" id="markdown-toc-the-independent-verification-approach">The Independent Verification Approach</a>    <ul>
      <li><a href="#1-automated-black-box-testing" id="markdown-toc-1-automated-black-box-testing">1. Automated Black-Box Testing</a></li>
      <li><a href="#2-use-security-scanning-tools" id="markdown-toc-2-use-security-scanning-tools">2. Use Security Scanning Tools</a></li>
      <li><a href="#3-simple-configuration-checks" id="markdown-toc-3-simple-configuration-checks">3. Simple Configuration Checks</a></li>
    </ul>
  </li>
  <li><a href="#connecting-verification-to-penetration-testing" id="markdown-toc-connecting-verification-to-penetration-testing">Connecting Verification to Penetration Testing</a></li>
  <li><a href="#start-simple-the-3-step-approach" id="markdown-toc-start-simple-the-3-step-approach">Start Simple: The 3-Step Approach</a></li>
  <li><a href="#making-it-sustainable" id="markdown-toc-making-it-sustainable">Making It Sustainable</a></li>
  <li><a href="#the-bottom-line" id="markdown-toc-the-bottom-line">The Bottom Line</a></li>
</ul>

<hr />

<h2 id="the-problem-with-developer-dependent-verification">The Problem with Developer-Dependent Verification</h2>

<p>Most security teams make this mistake:</p>
<ul>
  <li><strong>“Did you implement input validation for threat XYZ?”</strong></li>
  <li><strong>“Can you show me the code that handles authentication?”</strong></li>
  <li><strong>“Please add threat IDs to your code comments.”</strong></li>
</ul>

<p>The problem? You’re completely dependent on developers to self-report their security implementations. That’s like asking students to grade their own exams.</p>

<h2 id="the-independent-verification-approach">The Independent Verification Approach</h2>

<p>Instead of asking developers what they built, <strong>test what actually works</strong>. Here are three simple methods any security team can use:</p>

<h3 id="1-automated-black-box-testing">1. Automated Black-Box Testing</h3>

<p>Create simple scripts that test your threats directly:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Test authentication bypass (Threat: AUTH-001)</span>
curl <span class="nt">-X</span> GET https://yourapp.com/admin
<span class="c"># Should return 401, not 200</span>

<span class="c"># Test for SQL injection (Threat: DB-001)</span>
curl <span class="s2">"https://yourapp.com/search?q=' OR '1'='1"</span>
<span class="c"># Should not return database errors</span>
</code></pre></div></div>

<p>No code access needed. No developer cooperation required.</p>

<h3 id="2-use-security-scanning-tools">2. Use Security Scanning Tools</h3>

<p>Configure your existing security tools to focus on your threat model:</p>

<p><strong>Static Analysis (SAST) - Check the Code Itself:</strong></p>
<ul>
  <li><strong>Semgrep/Snyk/Checkmarx</strong>: Create custom rules for your specific threats
    <ul>
      <li>Threat AUTH-001 (Weak Authentication): Scan for hardcoded passwords, weak crypto</li>
      <li>Threat INJECTION-001 (SQL Injection): Look for dynamic SQL queries without parameterization</li>
      <li>Threat XSS-001 (Cross-Site Scripting): Find unescaped user input in templates</li>
    </ul>
  </li>
</ul>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Example: Custom Semgrep rule for SQL injection threat</span>
rules:
  - <span class="nb">id</span>: sql-injection-python
    message: <span class="s2">"Potential SQL injection - using string formatting in execute()"</span>
    languages: <span class="o">[</span>python]
    pattern: |
      <span class="nv">$CURSOR</span>.execute<span class="o">(</span><span class="s2">"..."</span> % ...<span class="o">)</span>
    severity: WARNING

<span class="c"># This rule will catch this:</span>
query <span class="o">=</span> <span class="s2">"SELECT * FROM users WHERE name = '%s'"</span> % user_input  <span class="c"># Flagged!</span>
cursor.execute<span class="o">(</span>query<span class="o">)</span>

<span class="c"># But won't flag this (safe approach):</span>
cursor.execute<span class="o">(</span><span class="s2">"SELECT * FROM users WHERE name = %s"</span>, <span class="o">(</span>user_input,<span class="o">))</span>  <span class="c"># Safe!</span>
</code></pre></div></div>

<p><strong>Dynamic Analysis (DAST) - Test the Running App:</strong></p>
<ul>
  <li><strong>OWASP ZAP</strong>: Set up custom scan policies for each threat category</li>
  <li><strong>Burp Suite</strong>: Create specific test cases targeting your identified risks</li>
</ul>

<p><strong>Infrastructure Scanning:</strong></p>
<ul>
  <li><strong>Nmap</strong>: Verify network security controls are in place</li>
  <li><strong>AWS Config/Azure Policy</strong>: Check cloud configurations match threat requirements</li>
</ul>

<p>The key is mapping your threats to specific tool configurations and creating custom rules that look for exactly what your threat model identified.</p>

<h3 id="3-simple-configuration-checks">3. Simple Configuration Checks</h3>

<p>Many threats can be verified by checking configurations:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Check if sensitive data is encrypted (Threat: DATA-001)</span>
<span class="nb">grep</span> <span class="nt">-r</span> <span class="s2">"password</span><span class="se">\|</span><span class="s2">api_key"</span> config/ | <span class="nb">grep</span> <span class="nt">-v</span> <span class="s2">"encrypted"</span>

<span class="c"># Verify HTTPS enforcement (Threat: NET-001)</span>
curl <span class="nt">-I</span> http://yourapp.com | <span class="nb">grep</span> <span class="nt">-i</span> <span class="s2">"redirect</span><span class="se">\|</span><span class="s2">301</span><span class="se">\|</span><span class="s2">302"</span>
</code></pre></div></div>

<h2 id="connecting-verification-to-penetration-testing">Connecting Verification to Penetration Testing</h2>

<p>Here’s where it gets powerful. Create a simple mapping between your threat model and pentest scenarios:</p>

<table>
  <thead>
    <tr>
      <th>Threat ID</th>
      <th>Threat Description</th>
      <th>Pentest Test Case</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>AUTH-001</td>
      <td>Authentication bypass</td>
      <td>Try accessing admin pages without login</td>
    </tr>
    <tr>
      <td>INJECTION-001</td>
      <td>SQL injection in search</td>
      <td>Test search with malicious SQL payloads</td>
    </tr>
    <tr>
      <td>XSS-001</td>
      <td>Cross-site scripting</td>
      <td>Submit script tags in form fields</td>
    </tr>
  </tbody>
</table>

<p>Share this with your pentesters. Now they’re not just finding random vulnerabilities – they’re specifically validating your threat model.</p>

<h2 id="start-simple-the-3-step-approach">Start Simple: The 3-Step Approach</h2>

<p><strong>Week 1: Pick Your Top 5 Threats</strong></p>
<ul>
  <li>Choose the most critical threats from your threat model</li>
  <li>Write one simple test for each (like the curl examples above)</li>
</ul>

<p><strong>Week 2: Automate the Tests</strong></p>
<ul>
  <li>Put your tests in a script</li>
  <li>Run them weekly against your applications</li>
  <li>Track results in a simple spreadsheet</li>
</ul>

<p><strong>Week 3: Expand Coverage</strong></p>
<ul>
  <li>Add more threats to your testing</li>
  <li>Configure security scanners to focus on your specific risks</li>
  <li>Share results with development teams</li>
</ul>

<h2 id="making-it-sustainable">Making It Sustainable</h2>

<p>The best approach is the one you’ll actually use. Start with:</p>

<ol>
  <li><strong>Simple scripts</strong> that test basic functionality</li>
  <li><strong>Existing tools</strong> configured for your threats</li>
  <li><strong>Regular testing</strong> (weekly or monthly)</li>
  <li><strong>Clear reporting</strong> that maps back to your threat model</li>
</ol>

<p>Don’t try to verify everything at once. Pick the threats that keep you up at night and start there.</p>

<h2 id="the-bottom-line">The Bottom Line</h2>

<p>Your threat model is only as good as its implementation. Stop relying on developers to self-report their security work.</p>

<p>Build simple verification methods that give you confidence your security controls actually exist in production.</p>

<p>Because at the end of the day, attackers don’t care about your documentation – they care about what’s actually running in production.</p>

<hr />

<p><em>Want to get started? Pick one critical threat from your threat model and write a simple test for it this week. You’ll be surprised what you discover.</em></p>

<hr />

<p><strong>Feel free to <a href="/contact/">contact me</a> for any suggestions and feedbacks. I would really appreciate those.</strong></p>

<p>Thank you for reading!</p>

<p><a href="#top" style="float: right"><strong>Back to Top⮭</strong> </a></p>]]></content><author><name>Shivam Saraswat</name></author><category term="Threat Modelling" /><category term="Security Engineering" /><category term="DevSecOps" /><summary type="html"><![CDATA[You’ve done the hard work. Your team created a comprehensive threat model, identified risks, and handed recommendations to the development team. But here’s the million-dollar question: How do you know they actually implemented the security controls? If you’re like most security teams, you’re probably hoping developers added the right code comments, wrote proper tests, and followed all your recommendations. But let’s be honest – that’s not always realistic. Here’s how to independently verify that your threat model recommendations actually made it into production.]]></summary></entry><entry><title type="html">Do We Still Need to Teach Developers Security?</title><link href="https://blog.shivamsaraswat.com//security-tools-vs-security-champions/" rel="alternate" type="text/html" title="Do We Still Need to Teach Developers Security?" /><published>2025-09-01T00:00:00+00:00</published><updated>2025-09-01T00:00:00+00:00</updated><id>https://blog.shivamsaraswat.com//security-tools-vs-security-champions</id><content type="html" xml:base="https://blog.shivamsaraswat.com//security-tools-vs-security-champions/"><![CDATA[<p>With all the fancy security tools available today, you might wonder: should we still bother training developers on security? Or can we just rely on automated systems to catch all the problems?</p>

<p>The short answer: <strong>You need both.</strong></p>

<!--more-->

<hr />

<h2 id="contents-">Contents <a name="top"></a></h2>
<ul id="markdown-toc">
  <li><a href="#what-automated-tools-are-great-at" id="markdown-toc-what-automated-tools-are-great-at">What Automated Tools Are Great At</a></li>
  <li><a href="#what-only-humans-can-do" id="markdown-toc-what-only-humans-can-do">What Only Humans Can Do</a></li>
  <li><a href="#the-best-approach-team-up" id="markdown-toc-the-best-approach-team-up">The Best Approach: Team Up</a></li>
  <li><a href="#bottom-line" id="markdown-toc-bottom-line">Bottom Line</a></li>
</ul>

<hr />

<h2 id="what-automated-tools-are-great-at">What Automated Tools Are Great At</h2>

<p>Security tools are like really good watchdogs. They’re excellent at:</p>

<ul>
  <li>Spotting common security bugs (like when hackers could steal your database)</li>
  <li>Checking code 24/7 without getting tired</li>
  <li>Finding known problems in third-party code you’re using</li>
  <li>Catching accidentally shared passwords or API keys</li>
</ul>

<p>These tools have gotten <em>way</em> better over the years. They can scan millions of lines of code in minutes and catch mistakes that would take humans hours to find.</p>

<h2 id="what-only-humans-can-do">What Only Humans Can Do</h2>

<p>But here’s the thing - tools are great at following rules, but terrible at thinking creatively. Developers are still needed for:</p>

<ul>
  <li>Understanding how hackers might abuse your specific business features</li>
  <li>Making smart security choices when designing new features</li>
  <li>Deciding when breaking a security rule actually makes sense</li>
  <li>Figuring out if a tool’s warning is real or just a false alarm</li>
</ul>

<p>Think of it this way: a security tool might tell you “this password field could be hacked,” but only a human developer can decide if that matters for your specific app and how to fix it properly.</p>

<h2 id="the-best-approach-team-up">The Best Approach: Team Up</h2>

<p>The most secure companies don’t choose between tools and training - they use both together:</p>

<ul>
  <li><strong>Tools handle the boring, repetitive stuff</strong> - scanning for known problems and enforcing basic rules</li>
  <li><strong>Humans handle the creative, strategic stuff</strong> - designing secure systems and making judgment calls</li>
</ul>

<p>When developers understand security basics, they write better code that tools can check more effectively. It’s like having a good editor review a well-written first draft versus trying to fix a mess.</p>

<h2 id="bottom-line">Bottom Line</h2>

<p>Don’t think of this as “tools vs. humans.” Think of it as “tools + humans = better security.”</p>

<hr />

<p><em>Keep training your developers on security fundamentals, but also invest in good automated tools. Your future self (and your customers) will thank you when hackers come knocking.</em></p>

<hr />

<p><strong>Feel free to <a href="/contact/">contact me</a> for any suggestions and feedbacks. I would really appreciate those.</strong></p>

<p>Thank you for reading!</p>

<p><a href="#top" style="float: right"><strong>Back to Top⮭</strong> </a></p>]]></content><author><name>Shivam Saraswat</name></author><category term="Security Champions" /><category term="Security Training" /><summary type="html"><![CDATA[With all the fancy security tools available today, you might wonder: should we still bother training developers on security? Or can we just rely on automated systems to catch all the problems? The short answer: You need both.]]></summary></entry><entry><title type="html">Why Every Developer Thinks Dependabot Sucks (And They’re Right)</title><link href="https://blog.shivamsaraswat.com//dependabot-sucks/" rel="alternate" type="text/html" title="Why Every Developer Thinks Dependabot Sucks (And They’re Right)" /><published>2025-08-23T00:00:00+00:00</published><updated>2025-08-23T00:00:00+00:00</updated><id>https://blog.shivamsaraswat.com//dependabot-sucks</id><content type="html" xml:base="https://blog.shivamsaraswat.com//dependabot-sucks/"><![CDATA[<p>Dependabot gets a lot of criticism as an SCA tool, and much of it is justified. While GitHub markets it as a security solution, it lacks core capabilities that development teams need for managing supply chain risks.</p>

<!--more-->

<hr />

<h2 id="contents-">Contents <a name="top"></a></h2>
<ul id="markdown-toc">
  <li><a href="#the-transitive-dependency-problem" id="markdown-toc-the-transitive-dependency-problem">The Transitive Dependency Problem</a></li>
  <li><a href="#whats-bad-about-dependabot" id="markdown-toc-whats-bad-about-dependabot">What’s Bad About Dependabot</a>    <ul>
      <li><a href="#alert-fatigue--noise" id="markdown-toc-alert-fatigue--noise">Alert Fatigue &amp; Noise</a></li>
      <li><a href="#lack-of-context" id="markdown-toc-lack-of-context">Lack of Context</a></li>
      <li><a href="#poor-quality-intelligence" id="markdown-toc-poor-quality-intelligence">Poor Quality Intelligence</a></li>
      <li><a href="#workflow-disruption" id="markdown-toc-workflow-disruption">Workflow Disruption</a></li>
      <li><a href="#basic-reporting" id="markdown-toc-basic-reporting">Basic Reporting</a></li>
    </ul>
  </li>
  <li><a href="#technical-limitations-beyond-transitive-dependencies" id="markdown-toc-technical-limitations-beyond-transitive-dependencies">Technical Limitations Beyond Transitive Dependencies</a></li>
  <li><a href="#whats-actually-good-about-it" id="markdown-toc-whats-actually-good-about-it">What’s Actually Good About It</a>    <ul>
      <li><a href="#accessibility" id="markdown-toc-accessibility">Accessibility</a></li>
      <li><a href="#automation" id="markdown-toc-automation">Automation</a></li>
      <li><a href="#integration" id="markdown-toc-integration">Integration</a></li>
    </ul>
  </li>
  <li><a href="#the-reality-check" id="markdown-toc-the-reality-check">The Reality Check</a></li>
  <li><a href="#when-dependabot-makes-sense" id="markdown-toc-when-dependabot-makes-sense">When Dependabot Makes Sense</a></li>
  <li><a href="#the-bottom-line" id="markdown-toc-the-bottom-line">The Bottom Line</a></li>
  <li><a href="#sources" id="markdown-toc-sources">Sources</a></li>
</ul>

<hr />

<h2 id="the-transitive-dependency-problem">The Transitive Dependency Problem</h2>

<p>The most significant weakness is Dependabot’s inability to handle transitive dependencies across most ecosystems. Looking at <a href="https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/dependency-graph-supported-package-ecosystems#supported-package-ecosystems">GitHub’s own documentation</a>, only 4 out of 15 supported package managers have built-in transitive dependency analysis:</p>

<ul>
  <li>Maven (Java, Scala)</li>
  <li>npm, pnpm (JavaScript)</li>
  <li>Yarn (JavaScript)</li>
</ul>

<p>This means 73% of ecosystems lack native transitive dependency scanning. Python, Go, Rust, Ruby, .NET, and PHP developers get zero visibility into indirect dependencies unless they manually configure dependency submission actions.</p>

<p>Consider this: if you’re using pip for Python, Dependabot only scans your direct dependencies listed in requirements.txt. But your actual vulnerability exposure comes from hundreds of transitive dependencies you never directly specified. A vulnerability in a sub-dependency three levels deep remains invisible.</p>

<p>GitHub only <a href="https://github.blog/changelog/2025-03-26-transitive-dependencies-are-now-available-for-maven/">added transitive support for Maven in March 2025</a>. <a href="https://github.blog/security/supply-chain-security/unlocking-security-updates-for-transitive-dependencies-with-npm/">NPM support</a> came earlier but still recently. Meanwhile, dedicated SCA tools have offered this functionality for years across all ecosystems.</p>

<h2 id="whats-bad-about-dependabot">What’s Bad About Dependabot</h2>

<h3 id="alert-fatigue--noise">Alert Fatigue &amp; Noise</h3>

<ul>
  <li>Generates tons of pull requests and security alerts without proper prioritization</li>
  <li>Treats all vulnerabilities equally regardless of actual exploitability or business impact</li>
  <li>Creates PR spam that teams often ignore, defeating the purpose</li>
</ul>

<h3 id="lack-of-context">Lack of Context</h3>

<ul>
  <li>No understanding of whether vulnerable code paths are actually reachable in your application</li>
  <li>Can’t distinguish between a dev dependency vulnerability and a critical runtime exposure</li>
  <li>Missing business context about which applications are customer-facing vs internal tools</li>
</ul>

<h3 id="poor-quality-intelligence">Poor Quality Intelligence</h3>

<ul>
  <li>Relies heavily on automated vulnerability detection that produces false positives</li>
  <li>Often flags vulnerabilities in transitive dependencies that aren’t exploitable in your context</li>
  <li>Limited remediation guidance beyond “update to version X”</li>
</ul>

<h3 id="workflow-disruption">Workflow Disruption</h3>

<ul>
  <li>Automated PRs can break builds without warning</li>
  <li>Limited customization for update schedules and policies</li>
  <li>Doesn’t integrate well with existing security review processes</li>
</ul>

<h3 id="basic-reporting">Basic Reporting</h3>

<ul>
  <li>Minimal analytics and trending data</li>
  <li>Hard to get organization-wide visibility into security posture</li>
  <li>No risk scoring or business impact assessment</li>
</ul>

<h2 id="technical-limitations-beyond-transitive-dependencies">Technical Limitations Beyond Transitive Dependencies</h2>

<p>The <a href="https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/dependency-graph-supported-package-ecosystems">documentation</a> reveals other problems:</p>

<ul>
  <li>Python setup.py files may not parse completely</li>
  <li>GitHub Actions only get alerts for semantic versioning, not SHA-pinned versions</li>
  <li>Workflows must be in <code class="language-plaintext highlighter-rouge">.github/workflows/</code> to be recognized</li>
  <li>No license compliance scanning</li>
  <li>Basic SBOM generation - While GitHub <a href="https://github.blog/enterprise-software/governance-and-compliance/introducing-self-service-sboms/">introduced SBOM export in 2023</a>, it only generates SBOMs based on the dependency graph, meaning the same transitive dependency limitations apply. The SBOM will be incomplete for 73% of ecosystems.</li>
  <li>No container or binary analysis</li>
</ul>

<p>As noted in the <a href="https://docs.github.com/en/code-security/dependabot/dependabot-alerts/about-dependabot-alerts">GitHub Actions documentation</a>: “Dependabot will only create Dependabot alerts for vulnerable GitHub Actions that use semantic versioning. You will not receive alerts for a vulnerable action that uses SHA versioning.”</p>

<p>The <a href="https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/exporting-a-software-bill-of-materials-for-your-repository">SBOM export documentation</a> confirms that SBOMs are generated from the dependency graph, inheriting all its limitations. For ecosystems without transitive dependency support, your SBOM will miss critical components, making it unsuitable for compliance requirements like Executive Order 14028.</p>

<h2 id="whats-actually-good-about-it">What’s Actually Good About It</h2>

<h3 id="accessibility">Accessibility</h3>

<ul>
  <li>Free for public repos, cheap for private ones</li>
  <li>Zero setup complexity if you’re already on GitHub</li>
  <li>Covers most major package ecosystems (npm, pip, bundler, etc.)</li>
</ul>

<h3 id="automation">Automation</h3>

<ul>
  <li>Does catch real vulnerabilities automatically</li>
  <li>Handles the tedious work of dependency version tracking</li>
  <li>Better than having no SCA tool at all</li>
</ul>

<h3 id="integration">Integration</h3>

<ul>
  <li>Native GitHub integration means it fits into existing workflows</li>
  <li>Plays reasonably well with GitHub’s security tab and insights</li>
</ul>

<h2 id="the-reality-check">The Reality Check</h2>

<p>Dependabot works okay for small teams or projects where someone can manually triage alerts, but it scales poorly and lacks the intelligence that modern development teams need. Many organizations end up supplementing it with tools like Snyk Open Source, Semgrep Supply Chain or building custom filtering on top of it.</p>

<p>It’s basically the “good enough” option that’s better than nothing but frustrating if you need actual strategic dependency management.</p>

<h2 id="when-dependabot-makes-sense">When Dependabot Makes Sense</h2>

<p>Despite its limitations, Dependabot can work for:</p>

<ul>
  <li>Open source projects with limited budgets</li>
  <li>Small teams without dedicated security resources</li>
  <li>Projects with simple dependency trees</li>
  <li>Organizations just starting their security journey</li>
</ul>

<p>If you’re stuck with Dependabot, you can improve the experience by implementing proper configuration and workflows. This guide shows how to set up automatic PR management using Dependabot: [<a href="https://blog.shivamsaraswat.com/dependabot-automatic-pr/">How to Make Dependabot Actually Work for You</a>]</p>

<h2 id="the-bottom-line">The Bottom Line</h2>

<p>Dependabot is not a comprehensive SCA solution. It’s a basic dependency updater with vulnerability alerts bolted on. The lack of transitive dependency support for 73% of ecosystems makes it unsuitable for serious security programs.</p>

<p>For organizations that need real supply chain security, look at dedicated SCA tools that offer:</p>

<ul>
  <li>Complete transitive dependency analysis across all languages</li>
  <li>Reachability analysis to reduce false positives</li>
  <li>License compliance scanning</li>
  <li>Risk-based prioritization</li>
  <li>Detailed remediation guidance</li>
  <li>Enterprise reporting and governance</li>
</ul>

<h2 id="sources">Sources</h2>

<ol>
  <li><a href="https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/dependency-graph-supported-package-ecosystems">GitHub Dependency Graph Supported Package Ecosystems</a></li>
  <li><a href="https://github.blog/changelog/2025-03-26-transitive-dependencies-are-now-available-for-maven/">Transitive Dependencies Now Available for Maven - GitHub Blog</a></li>
  <li><a href="https://github.blog/security/supply-chain-security/unlocking-security-updates-for-transitive-dependencies-with-npm/">Unlocking Security Updates for Transitive Dependencies with npm - GitHub Blog</a></li>
  <li><a href="https://docs.github.com/en/code-security/dependabot/dependabot-alerts/about-dependabot-alerts">About Dependabot Alerts - GitHub Docs</a></li>
  <li><a href="https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/about-dependabot-version-updates">About Dependabot Version Updates - GitHub Docs</a></li>
  <li><a href="https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions">Workflow Syntax for GitHub Actions</a></li>
</ol>

<hr />

<p><em>Dependabot might be free, but the cost of missing vulnerabilities in your dependency tree could be much higher than investing in proper SCA tooling.</em></p>

<hr />

<p><strong>Feel free to <a href="/contact/">contact me</a> for any suggestions and feedbacks. I would really appreciate those.</strong></p>

<p>Thank you for reading!</p>

<p><a href="#top" style="float: right"><strong>Back to Top⮭</strong> </a></p>]]></content><author><name>Shivam Saraswat</name></author><category term="Security at Scale" /><category term="Security Engineering" /><category term="DevSecOps" /><category term="Dependabot" /><summary type="html"><![CDATA[Dependabot gets a lot of criticism as an SCA tool, and much of it is justified. While GitHub markets it as a security solution, it lacks core capabilities that development teams need for managing supply chain risks.]]></summary></entry></feed>