Software Supply Chain Security Guide

A defender’s reference for software supply chain risks — threat model across the SDLC, package-registry attack patterns, CI/CD hardening, artifact provenance and signing, SBOMs, dependency scanning, case studies, and a checklist. Compiled from 29 research articles, advisories, and incident writeups.


Table of Contents

  1. Fundamentals
  2. Threat Model Across the SDLC
  3. Package Registry Risks
  4. Dependency Confusion, Typosquatting, Slopsquatting
  5. Maintainer Account Compromise
  6. CI/CD Pipeline Hardening
  7. Container Image Provenance & Verification
  8. SLSA Framework
  9. Sigstore, Cosign, in-toto
  10. SBOMs (SPDX, CycloneDX)
  11. Dependency Scanning Tooling
  12. Developer Host Hardening
  13. Admission Control & Runtime Verification
  14. Case Studies — Defensive Lessons
  15. Detection Signals & IOCs
  16. Defender Checklist
  17. Reference Configurations

1. Fundamentals

A software supply chain attack compromises a dependency, tool, build system, or distribution channel that the target trusts, rather than attacking the target directly. The malicious payload rides in on a routine npm install, pip install, docker pull, or CI build — bypassing perimeter defenses because the artifact appears legitimate.

Why the category exploded:

FactorEffect
Modular package ecosystemsOne compromised transitive dep can reach thousands of downstream apps
~85% of enterprises use OSSHuge shared attack surface
Registries default to “latest”Window between publish and detection is the blast radius
Lifecycle scripts (postinstall, prepare)Arbitrary code executes during install, before any runtime control
AI-suggested dependencies~20% of LLM-suggested packages do not exist — creates slopsquatting openings
CI/CD secrets co-located with buildsStealing them grants further publishing rights → worm behavior

OWASP Top 10 2025 — A03 Software Supply Chain Failures:

MetricValue
Community ranking#1 (50% of respondents)
Avg incidence rate5.19% (highest in Top 10)
Mapped CWEs477, 1035, 1104, 1329, 1357, 1395

Growth: Supply chain attacks on package registries surged 73% in 2025–2026. Sonatype tracked a 742% increase between 2019 and 2022. OSSF and Bastion 2026 reports attribute the spike to nation-state actors (notably DPRK clusters publishing ~1,700 malicious packages across npm, PyPI, Go, and Rust), credential-stealing worms, and industrialized typosquatting.


2. Threat Model Across the SDLC

Map threats to lifecycle stages. Each stage has distinct actors, assets, and controls.

StageAssetsRepresentative ThreatsPrimary Controls
DevelopSource code, IDEs, dev workstations, SSH/GPG keysStolen creds, IDE extensions (Glassworm, OpenVSX), malicious packages on dev host, AI slopsquattingMFA, commit signing, dev-host hardening, release-age gates, disabled install scripts
SourceGit repo, branches, PRs, code reviewForce-pushed tags, compromised reviewer, self-merge, secret commitBranch protection, required reviews, signed commits/tags, CODEOWNERS, secret scanning
BuildCI runners, build tools, cache, ephemeral credsPoisoned runner, compromised action/plugin, cache poisoning, post-build provenance forgeryEphemeral isolated runners, pinned action SHAs, SLSA L3 hosted builds, OIDC federation, egress allowlist
PackageArtifacts, signatures, SBOMs, attestationsUnsigned release, forged provenance, hidden transitive dep injectioncosign sign, in-toto attestations, SLSA provenance, SBOM attached
DistributeRegistries (npm/PyPI/GHCR/Docker Hub), mirrors, CDNAccount takeover, typosquat, dep confusion, registry abuse, force-push image tagScoped tokens, 2FA, publisher policies, repository firewall, signed pulls
DeployKubernetes, cloud, admission policiesUnsigned image rollout, drift, sidecar injectionAdmission controllers (Kyverno/OPA/Gatekeeper), signature verification, image allowlists
RuntimeRunning containers, nodes, secrets storesBackdoor C2, token exfil via metadata, lateral movementeBPF runtime, egress filtering, metadata service IMDSv2, least-priv IAM

STRIDE per stage: Every stage maps to Spoofing (forged provenance), Tampering (injected code), Repudiation (missing attestations), Information disclosure (leaked secrets via install scripts), DoS (dependency deletion à la left-pad), and Elevation (signing-key theft).

Blast-radius formula:

blast_radius = trust_score(package) × downstream_installs × window_before_detection × privilege(install_context)

Reduce any factor. Release-age gates attack window_before_detection; ignore-scripts attacks privilege(install_context); pinning attacks trust_score drift.


3. Package Registry Risks

Registry-by-registry quick reference

RegistryLanguageNotable attack patterns (2025–2026)Key defender features
npmJavaScript/TypeScriptChalk/Debug, Shai-Hulud/Shai-Hulud 2.0, Axios, Nx/s1ngularity, CanisterWorm, Glasswormmin-release-age, ignore-scripts, 2FA, scoped publish tokens, trusted publishers via OIDC
PyPIPythonLiteLLM, Telnyx, DPRK ghost-package swarms, wallet stealers2FA mandatory for top projects, Trusted Publishers (OIDC), --require-hashes
Maven CentralJavaTyposquats of groupIds, unsigned POMsGPG signing mandatory, namespace verification
RubyGemsRubyStrong_password-style hijacksMFA, bundle config set --global frozen true
Go proxyGoTyposquat import paths, DPRK-seeded modulesModule proxy immutability, go.sum verification, GOSUMDB
crates.ioRustTyposquats, DPRK-seeded cratesLockfile enforcement, cargo vet, cargo-audit
Docker Hub / GHCRContainersHijacked image tags, base-image tampering, Trivy v0.69.4 force-pushSigned images, content trust, immutable digests
VS Code Marketplace / OpenVSXIDE extensionsGlassworm, TeamPCP OpenVSXExtension signing (preview), allowlists
GitHub ActionsCI actionsTag repoint, compromised action → secret dumpPin by SHA, permissions: read-all, OIDC, allowlisted actions

Attack pattern taxonomy

PatternDescriptionDefender signal
Direct malware uploadNet-new package with malicious payloadBehavioral scanning (Socket.dev), new-publisher heuristics
TyposquatName differs by 1–2 chars from popular packageLevenshtein monitoring, registry deny-list
Dependency confusionPublic package with same name as private internalNamespace private scopes (@org/*), lockfile + private-registry priority
Transitive injectionLegitimate package quietly pulls new malicious depLockfile diffs, SBOM diff alerts
Account takeoverPhishing maintainer → legit publishPublisher-change alerts, 2FA enforcement
Worm / self-propagationPayload steals tokens → republishesAnomalous publish events, new runner names, post-install egress
Force-push tag repointGit tag moved to malicious commitSigned tag verification, tag immutability
Install-time executionpostinstall / setup.py runs payload on installignore-scripts, sandboxed installs, CI egress allowlist
Protestware / maintainer sabotageMaintainer introduces destructive logicBehavioral scanning, diff review of minor versions
SlopsquattingLLM hallucinates package name → attacker registers itVerify AI-suggested packages before install

4. Dependency Confusion, Typosquatting, Slopsquatting

Dependency confusion (Birsan 2021)

Occurs when a package manager prefers public registries over private ones for a name used both internally and publicly.

Root causeFix
Package manager falls back to public when private lookup fails or private registry is unreachableConfigure scoped registries; hard-fail if internal package not found in private index
Internal package names leaked in package.json / requirements.txtUse @org/name scopes on npm; prefix on PyPI; private Maven groupIds
Higher version on public winsPre-register internal names on public registry as “security holder” stubs

npm mitigation:

# .npmrc
@myorg:registry=https://nexus.myorg.local/repository/npm-private/
registry=https://registry.npmjs.org/
always-auth=true

pip / uv mitigation:

# pip.conf — single index, no extra-index-url fallback
[global]
index-url = https://artifactory.myorg.local/artifactory/api/pypi/pypi/simple/

Avoid --extra-index-url — it merges indices and picks highest version. Use --index-url to a repository-manager virtual registry that proxies public content behind policy.

Typosquatting

Detection leverTool / technique
Name similarity to top-1000 packagesSocket.dev, Phylum, Sonatype Repository Firewall
New package + suspicious postinstallAikido, GitGuardian
Namespace deny-list in repo managerNexus / Artifactory policies
Lockfile diff alertsGitHub Actions: compare package-lock.json PR diffs

Slopsquatting (AI-coined)

LLMs regularly hallucinate plausible-sounding package names. Attackers squat those names. Defensive verification before installing any AI-suggested package:

# npm
npm view <pkg> time.created versions maintainers --json

# PyPI
curl -s https://pypi.org/pypi/<pkg>/json | jq '{name:.info.name,author:.info.author,home_page:.info.home_page,releases:(.releases|keys|length)}'

Red flags: created <30 days ago, single maintainer, no linked repo, download count in tens, no release history.


5. Maintainer Account Compromise

Phishing an npm/PyPI maintainer became the single most prolific entry vector in 2025–2026 (Chalk, Debug, Axios, LiteLLM, Telnyx, Shai-Hulud, Shai-Hulud 2.0).

PhaseAttacker actionDefender control
ReconIdentify maintainers of high-traffic packagesPublic — accept
PhishingLookalike npm/PyPI login page, OAuth consent phishingHardware-backed 2FA (WebAuthn), phishing-resistant MFA, allowlisted OAuth apps
PublishUse legitimate account to push malicious versionTrusted Publishers (OIDC from CI only), publish-alerts, velocity anomaly detection
PropagateStolen tokens from infected victims used to publish new packages (worm)Short-lived tokens, token scoping per package, detect new runner names (e.g. SHA1HULUD)

Key principle: a legitimate publisher account with a valid 2FA bypass is indistinguishable from the real maintainer at the artifact level. The only durable defense is post-publish attestation verification (SLSA provenance + Sigstore identity) tied to a CI workflow identity rather than a human account.


6. CI/CD Pipeline Hardening

CI/CD is high-value: it holds secrets, has network egress, and signs artifacts. Compromising it turns it into a factory for malicious releases.

Control baseline

ControlRationale
Ephemeral runnersNo state between builds; no cache contamination
Isolated builds (SLSA L3)User build steps cannot touch signing material
OIDC federation (no long-lived cloud creds)Revokes secret exfil value; token valid minutes
Pin GitHub Actions by SHAuses: actions/checkout@b4ffde65... not @v4; defeats tag repoint
Minimal permissions:Default contents: read; grant id-token: write only when signing
Read-only filesystemLimits payload persistence
Egress allowlist on runnersBlocks curl-to-C2, anomalous registries
Secret masking + short-lived tokensShrinks exfil window
Separation of dutiesNo single human pushes code → prod
Signed commits/tags enforced by branch protectionAttacker cannot force-push malicious tag without signing key
Runner fingerprintingDetect rogue self-hosted runners (e.g., SHA1HULUD)
Audit log export + alertingDetect anomalous workflow_dispatch, new deploy keys

GitHub Actions hardened job skeleton

name: build-and-release
on:
  push:
    tags: ['v*']

permissions:
  contents: read
  id-token: write      # for keyless cosign + OIDC to cloud
  packages: write      # scoped; only if publishing to GHCR

jobs:
  build:
    runs-on: ubuntu-24.04
    steps:
      - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11  # v4.1.1 pinned SHA
        with:
          persist-credentials: false

      - uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8  # v4.0.2
        with:
          node-version: 20
          cache: 'npm'

      - run: npm ci --ignore-scripts

      - run: npm run build

      - name: Generate SBOM
        uses: anchore/sbom-action@d94f46e13c6c62f59525ac9a1e147a99dc0b9bf5
        with:
          format: cyclonedx-json
          output-file: sbom.cdx.json

      - name: Scan SBOM
        uses: anchore/scan-action@be7a22da4f22dde4c7c9e0b14dea0d0f7a4a16a3
        with:
          sbom: sbom.cdx.json
          fail-build: true
          severity-cutoff: high

      - name: Build & push image
        id: build
        run: |
          IMAGE=ghcr.io/${{ github.repository }}:${{ github.ref_name }}
          docker build -t "$IMAGE" .
          docker push "$IMAGE"
          echo "digest=$(docker inspect --format='{{index .RepoDigests 0}}' $IMAGE)" >> "$GITHUB_OUTPUT"

      - name: Sign image (keyless)
        env:
          COSIGN_EXPERIMENTAL: "1"
        run: cosign sign --yes ${{ steps.build.outputs.digest }}

      - name: Attest SBOM
        run: |
          cosign attest --yes --predicate sbom.cdx.json \
            --type cyclonedx ${{ steps.build.outputs.digest }}

      - name: Attest SLSA provenance
        uses: slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@v2.0.0
        with:
          image: ${{ steps.build.outputs.digest }}

Runner egress allowlist (example)

registry.npmjs.org
pypi.org
files.pythonhosted.org
ghcr.io
*.actions.githubusercontent.com
fulcio.sigstore.dev
rekor.sigstore.dev
oauth2.sigstore.dev

Block everything else. Most supply-chain malware phones home on install — an allowlist surfaces it immediately.


7. Container Image Provenance & Verification

Container images are the delivery unit and must be identified by digest, not tag.

BadGood
FROM node:20FROM node:20.11.1-alpine3.19@sha256:7c3...
docker pull myimage:latestdocker pull myimage@sha256:…
Tag-based Kubernetes rolloutDigest-pinned manifests + admission verification

Base image hygiene

PracticeWhy
Prefer distroless / chainguard / wolfi base imagesSmaller attack surface, signed by producer
Rebuild on base CVE, not periodicallyProvenance ties to cause
Pin base by digest in FROMDefeats silent tag repoint
Scan final image with Grype/TrivyCatches inherited CVEs
Verify base image signature in CIcosign verify cgr.dev/chainguard/static@sha256:…

cosign image sign + verify

# Keyless sign (uses OIDC → Fulcio → Rekor)
COSIGN_EXPERIMENTAL=1 cosign sign --yes \
  ghcr.io/myorg/app@sha256:abcd...

# Verify against expected CI workflow identity
cosign verify \
  --certificate-identity-regexp="^https://github.com/myorg/app/\.github/workflows/release\.yml@refs/tags/v.*$" \
  --certificate-oidc-issuer=https://token.actions.githubusercontent.com \
  ghcr.io/myorg/app@sha256:abcd...

The identity regex is the critical verification step — it binds the signature to a specific workflow file in a specific repo, so a compromise of a different repo cannot produce a valid signature for this image.


8. SLSA Framework

SLSA (Supply-chain Levels for Software Artifacts, “salsa”) gives a vocabulary and progressive maturity levels for build integrity. Developed originally from Google’s Binary Authorization for Borg, donated to OpenSSF in 2021, now at v1.1.

Build track levels

LevelNameRequirementsProtects against
L0No SLSANothingNothing
L1Provenance existsScripted build, auto-generated provenanceAccidental wrong artifact; incident traceability
L2Signed provenanceL1 + cryptographically signed by hosted build platformPost-build forgery; builds from dev workstations
L3Hardened buildsL2 + isolated, ephemeral runners; signing keys inaccessible to build user code; non-forgeable provenanceCross-build contamination, insider tampering, signing-key theft by build step

Note: SLSA v1.0+ consolidated former L4 — hermetic and reproducible builds are now recommended practices, not strict requirements.

Provenance attack vectors addressed

VectorWithout SLSAWith SLSA L3
Source tamperingHidden in commit; hard to detectProvenance binds artifact to commit digest
Build tamperingUndetectable mid-buildHardened runner isolates build from signer
Dependency poisoningInstalled silentlyProvenance lists dependencies used
Provenance forgeryTrivialNon-forgeable; signed by platform, not user
Compromised credentialsUsed to publishOIDC-scoped short-lived, verifiable

Minimal in-toto / SLSA provenance document

{
  "_type": "https://in-toto.io/Statement/v1",
  "subject": [{
    "name": "ghcr.io/myorg/app",
    "digest": {"sha256": "abcd1234..."}
  }],
  "predicateType": "https://slsa.dev/provenance/v1",
  "predicate": {
    "buildDefinition": {
      "buildType": "https://github.com/slsa-framework/slsa-github-generator/container@v1",
      "externalParameters": {
        "repository": "https://github.com/myorg/app",
        "ref": "refs/tags/v1.2.3"
      },
      "resolvedDependencies": [
        {"uri": "git+https://github.com/myorg/app", "digest": {"gitCommit": "f00..."}}
      ]
    },
    "runDetails": {
      "builder": {
        "id": "https://github.com/slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@refs/tags/v2.0.0"
      },
      "metadata": {
        "invocationId": "https://github.com/myorg/app/actions/runs/1234567890/attempts/1",
        "startedOn": "2026-04-01T12:00:00Z"
      }
    }
  }
}

Consumer verification workflow

  1. Download artifact + provenance bundle.
  2. Verify Sigstore signature against certificate transparency log (Rekor).
  3. Check builder.id matches allowlisted trusted builder.
  4. Match artifact digest against subject.digest.
  5. Match externalParameters.repository and ref against expected.
  6. Policy engine (Kyverno / Conftest / OPA) approves or rejects.

9. Sigstore, Cosign, in-toto

Component map

ComponentRole
cosignCLI for signing/verifying container images, blobs, SBOMs, attestations
FulcioShort-lived code signing CA; issues certs from OIDC identity
RekorImmutable transparency log of signing events
policy-controller / cosign verifyEnforcement at admission or deploy time
in-toto attestationsStatement format (subject, predicateType, predicate)
SLSA provenanceA predicateType inside in-toto that describes build facts

Keyless signing flow

dev/CI → OIDC (GitHub, Google, etc.) → Fulcio (issues 10-min cert bound to identity)
      → cosign signs artifact with ephemeral key
      → signature + cert logged in Rekor transparency log
      → verifiers check cert identity + Rekor inclusion proof

Benefit: no long-lived signing keys to manage or exfil.

Common cosign operations

# Keyless sign a blob
cosign sign-blob --yes --bundle release.cosign.bundle release.tar.gz

# Verify blob using expected identity
cosign verify-blob \
  --bundle release.cosign.bundle \
  --certificate-identity-regexp="^https://github.com/myorg/app/.*$" \
  --certificate-oidc-issuer=https://token.actions.githubusercontent.com \
  release.tar.gz

# Attach an SBOM attestation
cosign attest --yes --predicate sbom.cdx.json --type cyclonedx \
  ghcr.io/myorg/app@sha256:abcd...

# Download + inspect attestation
cosign download attestation ghcr.io/myorg/app@sha256:abcd... | \
  jq -r '.payload' | base64 -d | jq .

# Verify SLSA provenance predicate
cosign verify-attestation --type slsaprovenance \
  --certificate-identity-regexp="^https://github.com/slsa-framework/.*$" \
  --certificate-oidc-issuer=https://token.actions.githubusercontent.com \
  ghcr.io/myorg/app@sha256:abcd...

Key-based signing (fallback for air-gapped builds)

cosign generate-key-pair                        # cosign.key / cosign.pub
cosign sign --key cosign.key ghcr.io/app:1.0.0
cosign verify --key cosign.pub ghcr.io/app:1.0.0

Store private keys in HSM or KMS (--key awskms://…, --key gcpkms://…); never embed in CI secrets if OIDC is available.


10. SBOMs (SPDX, CycloneDX)

An SBOM is a machine-readable inventory of components, versions, licenses, and relationships in an artifact. It answers “is package X at version Y present?” in seconds when the next Log4Shell drops.

FormatBodyTypical use
SPDXLinux FoundationLicense compliance, regulatory (NTIA, EO 14028)
CycloneDXOWASPAppSec, vuln scanning, VEX, SaaSBOM, ML-BOM

Minimum viable SBOM practice

  1. Generate at build time (not post-hoc from a registry).
  2. Attach to the artifact (cosign attest --type cyclonedx).
  3. Sign the SBOM.
  4. Store versioned alongside the release.
  5. Feed to a vuln scanner on every pull request and on new CVE disclosure.
  6. Diff SBOMs between releases to surface new transitive deps.

Generation commands

# Syft — filesystem
syft dir:. -o cyclonedx-json=sbom.cdx.json -o spdx-json=sbom.spdx.json

# Syft — container image
syft ghcr.io/myorg/app@sha256:abcd... -o cyclonedx-json=sbom.cdx.json

# cdxgen (language-native)
cdxgen -r -t javascript -o sbom.cdx.json

# Trivy
trivy image --format cyclonedx --output sbom.cdx.json ghcr.io/myorg/app@sha256:abcd...

# Docker buildx native
docker buildx build --sbom=true --provenance=mode=max -t myimage .

SBOM vulnerability scan

# Grype against the SBOM (consistent regardless of runtime env)
grype sbom:sbom.cdx.json --fail-on high

# OSV-Scanner against the SBOM
osv-scanner --sbom sbom.cdx.json

# Dependency-Track upload
curl -X POST "https://dtrack.myorg.local/api/v1/bom" \
  -H "X-API-Key: $DTRACK_TOKEN" \
  -F "autoCreate=true" \
  -F "projectName=myorg/app" \
  -F "projectVersion=1.2.3" \
  -F "bom=@sbom.cdx.json"

SBOM diff for transitive-dep injection detection

# Naive: detect new direct or transitive deps between tags
diff <(jq -r '.components[] | "\(.name)@\(.version)"' old.cdx.json | sort) \
     <(jq -r '.components[] | "\(.name)@\(.version)"' new.cdx.json | sort)

Run in PR CI — alert a human on any new dependency added by a minor/patch version bump of an existing dependency. This is the signal that would have caught the Axios → plain-crypto-js injection.


11. Dependency Scanning Tooling

ToolKindStrengthLimitation
DependabotAuto-PR bumps + advisoriesFree, GitHub-native, alertsOnly known CVEs; noisy PRs
RenovateAuto-PR bumpsHighly configurable grouping, schedules, merge confidenceConfig complexity
SnykSCA + IaC + containerGood proprietary DB + license checksCommercial
OSV-ScannerGoogle OSV DBOpen DB, fast, works on SBOM, lockfiles, directoriesCVE-only (but catches GHSA, PYSEC, etc.)
TrivyImage + SBOM + IaC + secretsOne binary does a lotNoisy defaults
GrypeSBOM-driven scannerWorks with Syft output, SPDX and CycloneDXCVE-only
Dependency-TrackContinuous SBOM mgmtAggregates SBOMs, policy, VEXSelf-hosted
Socket.devBehavioral (not CVE)Detects install scripts, obfuscation, network accessCommercial for private
PhylumBehavioral + reputationPre-install blockingCommercial
Sonatype Repository Firewall / Nexus IQRegistry proxy w/ quarantineBlocks known-malicious before cacheCommercial

OSV-Scanner CI usage

- name: OSV scan
  uses: google/osv-scanner-action/osv-scanner-action@v1.9.0
  with:
    scan-args: |-
      --lockfile=package-lock.json
      --lockfile=poetry.lock
      --recursive
      --fail-on-vuln

Dependabot minimal config

# .github/dependabot.yml
version: 2
updates:
  - package-ecosystem: "npm"
    directory: "/"
    schedule: { interval: "daily" }
    open-pull-requests-limit: 10
    groups:
      production:
        dependency-type: "production"
      development:
        dependency-type: "development"
  - package-ecosystem: "github-actions"
    directory: "/"
    schedule: { interval: "weekly" }
  - package-ecosystem: "docker"
    directory: "/"
    schedule: { interval: "weekly" }

Renovate minimal config

{
  "$schema": "https://docs.renovatebot.com/renovate-schema.json",
  "extends": ["config:recommended", ":pinAllExceptPeerDependencies"],
  "minimumReleaseAge": "7 days",
  "pinDigests": true,
  "packageRules": [
    {"matchManagers": ["github-actions"], "pinDigests": true},
    {"matchUpdateTypes": ["patch"], "automerge": true, "automergeType": "pr"}
  ],
  "vulnerabilityAlerts": {"enabled": true, "labels": ["security"]}
}

minimumReleaseAge: "7 days" is the single most effective Renovate setting: it refuses to auto-bump into a version published less than 7 days ago, which is the window most malicious releases live before takedown.


12. Developer Host Hardening

Developer workstations and personal laptops are now prime targets (Shai-Hulud, OpenVSX compromises, Glassworm). Two host-level defenses block the majority of opportunistic install-time attacks:

  1. Release-age gates — refuse to install any package version published <7 days ago.
  2. Disable install lifecycle scriptspostinstall, preinstall, prepare. This is the #1 execution vector for npm malware.

Per-package-manager configs (from 2026 practitioner gist)

uv (Python)~/.config/uv/uv.toml

exclude-newer = "7 days"

pip (Python)~/.config/pip/pip.conf + shell alias

[global]
index-url = https://artifactory.myorg.local/artifactory/api/pypi/pypi/simple/
# macOS / BSD date
alias pip='pip --uploaded-prior-to $(date -u -v-7d +%Y-%m-%dT%H:%M:%SZ)'
# Linux / GNU date
alias pip='pip --uploaded-prior-to $(date -u -d "7 days ago" +%Y-%m-%dT%H:%M:%SZ)'

npm~/.npmrc

min-release-age=7
ignore-scripts=true

pnpmpnpm-workspace.yaml

minimumReleaseAge: 10080   # minutes = 7 days
minimumReleaseAgeExclude:
  - "@myorg/*"
  - "esbuild"
pnpm config set ignore-scripts true --global

yarn~/.yarnrc.yml

npmMinimalAgeGate: "7d"
enableScripts: false
npmPreapprovedPackages:
  - "@myorg/*"

bun~/.bunfig.toml

[install]
minimumReleaseAge = 10080

Bun disables lifecycle scripts by default.

Additional host hygiene

ControlNote
Full-disk encryption + MDMTable stakes
Hardware-backed MFA (YubiKey, TouchID WebAuthn)Resists npm/PyPI phishing
Separate publish identity from daily-driverScoped npm tokens per project
EDR with script execution telemetryCatches post-install spawning shells
Allowlist outbound from dev VMBlock C2 traffic
Rotate SSH keys, move to signed-commit keys (GPG / SSH)Prevents force-push forgery
Review VS Code / JetBrains extensions regularlyGlassworm / OpenVSX TeamPCP vector
Don’t store long-lived cloud creds on diskUse SSO + short-lived tokens

13. Admission Control & Runtime Verification

CI signing is only as useful as the deploy-time verification that enforces it. Without admission control, a compromised runner or registry can push unsigned images straight into production.

Kyverno policy — require cosign-verified images

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: verify-image-signature
spec:
  validationFailureAction: Enforce
  background: false
  webhookTimeoutSeconds: 30
  rules:
    - name: check-image-signature
      match:
        any:
          - resources:
              kinds: [Pod]
      verifyImages:
        - imageReferences:
            - "ghcr.io/myorg/*"
          attestors:
            - entries:
                - keyless:
                    subject: "https://github.com/myorg/*/.github/workflows/release.yml@refs/tags/v*"
                    issuer: "https://token.actions.githubusercontent.com"
                    rekor:
                      url: https://rekor.sigstore.dev

Sigstore policy-controller — verify SLSA provenance predicate

apiVersion: policy.sigstore.dev/v1beta1
kind: ClusterImagePolicy
metadata:
  name: require-slsa-provenance
spec:
  images:
    - glob: "ghcr.io/myorg/**"
  authorities:
    - keyless:
        identities:
          - issuer: https://token.actions.githubusercontent.com
            subjectRegExp: "https://github.com/slsa-framework/slsa-github-generator/.*"
        ctlog:
          url: https://rekor.sigstore.dev
      attestations:
        - name: must-have-slsa
          predicateType: https://slsa.dev/provenance/v1
          policy:
            type: cue
            data: |
              predicate: {
                buildDefinition: {
                  externalParameters: {
                    repository: =~"^https://github.com/myorg/"
                  }
                }
              }

OPA Gatekeeper — deny unpinned image tags

package kubernetes.admission

deny[msg] {
  input.request.kind.kind == "Pod"
  image := input.request.object.spec.containers[_].image
  not contains(image, "@sha256:")
  msg := sprintf("image %q must be pinned by digest", [image])
}

Runtime

LayerControl
NodeeBPF-based runtime detection (Falco, Tetragon) for exec of shells from package dirs
NetworkEgress NetworkPolicy; deny-by-default cluster egress; CoreDNS deny lists
SecretsVault/ExternalSecrets with short-lived leases; no baked-in secrets
IAMWorkload identity (no static cloud keys); IMDSv2 only
ImageScan on pull; expired image quarantine

14. Case Studies — Defensive Lessons

Each case below summarizes what happened, how it was detected, and what defenders learned. No reproduction steps.

14.1 SolarWinds SUNBURST (2020)

AspectDetail
VectorBuild-system compromise; backdoor injected into Orion build
Scale~18,000 organizations, including US federal agencies
DetectionFireEye discovered it in its own environment via anomalous 2FA enrollment
Dwell timeMonths — code was signed with SolarWinds’ legitimate cert
Defensive lessonCode signing alone is insufficient; the build platform itself must be trusted and attested (SLSA L3). Provenance would have shown “built on dev workstation, not expected builder.”

14.2 Codecov Bash Uploader (2021)

AspectDetail
VectorAttackers modified a Bash uploader script distributed via Codecov’s Docker image creation
PayloadExfiltrated CI environment variables (secrets, tokens)
DetectionCustomer noticed checksum mismatch on the script
Defensive lessonChecksum-verify any script piped from the internet. Never use production creds in CI. Use short-lived OIDC-federated creds.

14.3 Log4Shell / CVE-2021-44228 (2021)

AspectDetail
VectorJNDI lookup RCE in a transitive dependency most teams didn’t know they used
DetectionPublic disclosure after Minecraft PoC
Defensive lessonYou cannot patch what you can’t see. SBOMs answer “am I using Log4j anywhere?” in minutes.

14.4 Event-stream (2018)

AspectDetail
VectorOriginal maintainer handed off publish rights to an unknown contributor who added a malicious transitive dep
PayloadCrypto wallet stealer targeted at one specific downstream user
DetectionDeveloper noticed deprecated API warning, investigated
Defensive lessonMaintainer handoffs are a red flag. Registry-level notifications for ownership change. Lockfile diffs would have caught the new dep.

14.5 Chalk / Debug / color-* (September 2025)

AspectDetail
VectorMaintainer phished → legitimate publish of trojanized versions of chalk, debug, ansi-styles, strip-ansi, supports-color, color-convert, color-string, color-name, ansi-regex, and 13+ others
ReachBillions of weekly downloads exposed
DetectionAikido Security; subsequent analysis by Wiz, Semgrep, Sonatype, ArmorCode, Vercel
Defensive lessonA single phished maintainer of a utility package cascades into the entire JS ecosystem. 2FA with phishing-resistant factors is now mandatory for any popular-package maintainer. Release-age gates would have stopped most installs.

14.6 Nx / s1ngularity (August 2025)

AspectDetail
VectorCompromised Nx monorepo tool versions; payload ran during nx build
PayloadCI environment enumeration + secret exfil
DetectionUpwind Security
Defensive lessonBuild-tool compromise executes inside the build context with full access to secrets. Egress allowlists on runners would have blocked exfil.

14.7 Shai-Hulud npm worm (September 2025) — “First successful self-propagating npm worm”

AspectDetail
VectorPost-install scripts harvested credentials → used stolen npm tokens to publish malicious versions of whatever the victim could publish
PropagationSelf-spreading; reached 500+ package versions before npm disruption
DetectionTrend Micro, Sonatype; npm team acted
Detection signalsAnomalous publish events, new npm versions without corresponding release commits, outbound exfil to public GitHub repos
Defensive lessonDeveloper machines themselves are now the target. ignore-scripts=true would have blocked execution. Never store long-lived npm tokens; use OIDC Trusted Publishers.

14.8 Shai-Hulud 2.0 (November 2025)

AspectDetail
Scale~25,000 repositories hijacked, ~500 GitHub users, ~700 npm packages — including Zapier, ENS Domains, PostHog, Postman
PayloadFingerprinted CI vs workstation; dumped cloud.json, truffleSecrets.json; exfiltrated to attacker-owned GitHub repos; hijacked GitHub Actions runners registered as “SHA1HULUD”
GH Actions abuseBackdoored “formatter” workflows dumped toJSON(secrets); malicious discussion.yaml for remote command execution
DetectionAikido, ReversingLabs, Wiz, Trend Micro, GitLab via GitHub Archive telemetry
Defensive lessonTreat self-hosted runners as production. Audit runner registrations. Restrict permissions: blocks. Avoid toJSON(secrets) anti-patterns.

14.9 Axios / plain-crypto-js (March 2026)

AspectDetail
VectorMaintainer account hijack → axios@1.14.1 and axios@0.30.4 published with a brand-new hidden transitive dep plain-crypto-js@4.2.1 instead of inline malware
Reachaxios = 300M weekly downloads
PayloadObfuscated cross-platform loader via postinstall; OS fingerprint; C2 fetch; OS-specific droppers (AppleScript/PowerShell/VBS/Python); RAT
Anti-forensicsDeleted artifacts after execution; rewrote package.json to restore a benign appearance
DetectionSonatype flagged within minutes (01:04 UTC March 31); StepSecurity reporting
Defensive lessonAttackers now inject a hidden transitive instead of modifying core code — SBOM diff is the fastest reliable signal. Repository firewalls that quarantine new packages would have blocked install. Related OpenClaw packages (@qqbrowser, @shadanai) also carried the same dep — blast radius extended via shared dependency

14.10 TeamPCP campaign (March 2026, ongoing)

Sub-incidentSummary
Trivy v0.69.4Stolen Aqua Security creds used to publish malicious release + force-push 76 GitHub Action tags. Propagated to GHCR, Docker Hub, ECR Public, deb/rpm, get.trivy.dev. Actions dumped CI runner memory and exfiltrated via lookalike domain.
CanisterWorm npmSelf-propagating worm across 40+ packages; stole tokens, bumped patch versions, republished; Kubernetes-targeting payload
Checkmarx KICS GitHub Action + OpenVSXSame credential-theft pattern; fallback exfil by creating public repo with victim GITHUB_TOKEN
LiteLLM (PyPI) 1.82.7/1.82.8Collected env vars, SSH keys, cloud creds, Kubernetes configs, Docker configs, shell history, DB creds, wallet files, CI secrets; encrypted locally and exfiltrated
Telnyx (PyPI) 4.87.1/4.87.2Same exfil payload

Unifying defensive lesson: credential theft → automated republishing is the modern blueprint. Required controls: (1) no long-lived publish tokens — OIDC Trusted Publishers only; (2) pinned, digest-bound Action SHAs; (3) signed tag enforcement; (4) egress allowlist on runners; (5) anomaly detection on publish velocity.

14.11 Glassworm (October 2025)

AspectDetail
VectorSelf-spreading VS Code extension on OpenVSX
Defensive lessonIDE extensions are code executing with user privileges. Treat extension installs like package installs — pin, review, scan.

14.12 PhantomRaven (October 2025)

AspectDetail
Vector126 npm packages with stealer payloads
Defensive lessonBehavioral scanners (Socket, Phylum) that look at what a package does catch these before CVE databases do.

14.13 DPRK 1,700-package flood (2025–2026)

AspectDetail
VectorNorth Korean cluster (Contagious Interview / Jackpot Panda overlaps) published across npm, PyPI, Go, Rust
Defensive lessonNation-state volume makes manual review infeasible. Automation + behavioral analysis + release-age gates are required.

14.14 dYdX npm + PyPI (2026)

AspectDetail
VectorCompromised dYdX packages deliver wallet stealers + RAT
Defensive lessonFintech / Web3 packages are high-value targets. Multi-registry campaigns mean defenders must unify SCA across language ecosystems.

14.15 React2Shell CVE-2025-55182 (Nov–Dec 2025)

Not a supply-chain injection but relevant as a dependency-triggered RCE: React Server Components 19.0.0–19.2.0 had a pre-auth RCE. Discovered by Lachlan Davidson; exploited within days by Earth Lamia, Jackpot Panda, Contagious Interview. Over 77,000 vulnerable IPs scanned by Shadowserver. CISA KEV December 17.

Defensive lesson: SBOM-driven scanning plus an emergency response playbook are load-bearing. The fastest organizations to patch had automated SBOM → KEV lookups.

14.16 Oracle EBS CVE-2025-61882 (Oct 2025) — Clop

Oracle E-Business Suite zero-day (CVSS 9.8) exploited by Clop for mass data theft (Barts Health, Canon, GlobalLogic, LKQ, Logitech, Mazda).

Lesson: Commercial dependencies need the same patching SLAs as OSS.

14.17 ToolShell CVE-2025-53770/-53771 (July 2025)

Chained SharePoint on-prem exploits by Linen Typhoon, Violet Typhoon, Storm-2603; ~396 systems compromised; web shells deployed.

Lesson: Internet-facing internally-run commercial software is a supply chain node — treat it with the same monitoring as your own binaries.

14.18 CitrixBleed 2 CVE-2025-5777 (June 2025)

Out-of-bounds read bypassing MFA / hijacking session tokens in NetScaler ADC/Gateway.

Lesson: Network-appliance firmware is supply chain. SBOM your appliances.

14.19 Bybit $1.5B (Feb 2025)

Wallet-software supply chain compromise executing only when the target wallet was active.

Lesson: Conditional payloads evade test benches. Runtime behavioral monitoring complements static analysis.

14.20 Composite: SolarWinds, Codecov, Log4Shell

Common thread: a small number of high-trust components → catastrophic downstream. The only durable defense is verifiable provenance + SBOM transparency + deploy-time enforcement.


15. Detection Signals & IOCs

Build / CI signals

SignalPossible attack
New postinstall / preinstall in a minor version bumpnpm dropper
New transitive dep introduced in a patch releaseAxios-style hidden injection
Runner egress to unrecognized domain during npm installC2 beacon
toJSON(secrets) in workflow diffShai-Hulud 2.0 pattern
Self-hosted runner registered with anomalous name (e.g. SHA1HULUD)Worm propagation
Force-push to release tagTrivy v0.69.4 pattern
Publish event without corresponding release commitWorm re-publish
Unexpected npm publish / twine upload in CI logsToken abuse

Package-level signals

SignalCheck
Obfuscated strings, base64/XOR decoding in install scriptsStatic scan
OS fingerprinting (process.platform, sys.platform) in install scriptsBehavioral
Writes to /tmp + chmod +x + exec in install scriptsBehavioral
Network fetch during installBehavioral
package.json rewritten at runtimeAnti-forensics — Axios pattern
Single-maintainer, <30 day age, no source repoMetadata heuristics

Workstation / dev signals

SignalSource
Shell spawn from node, python, pip, npm processesEDR
Read of ~/.aws/credentials, ~/.ssh/id_*, ~/.kube/config, ~/.docker/config.json by package installEDR + DLP
New files under /tmp, %TEMP%, ~/Library correlated with package installEDR
Outbound to GitHub Gists / raw.githubusercontent.com from installNetwork

Hunting queries (SIEM pseudocode)

# Anomalous npm publish from CI
process.name = "npm" AND argv contains "publish"
  AND runner.self_hosted = true
  AND runner.name NOT IN (allowlist)

# Credential file access by package install
process.parent IN ("npm","node","pip","python","uv")
  AND file.path MATCHES ("~/.aws/*","~/.ssh/*","~/.kube/*","~/.docker/*")

# New transitive dep in patch version
repo.event = "pull_request"
  AND file.path IN ("package-lock.json","poetry.lock","go.sum")
  AND diff.adds CONTAINS "new package" AND semver.bump = "patch"

16. Defender Checklist

Strategy

  • Inventory every supply chain node: registries, CI systems, artifact repos, IDE extensions, base images, vendor SaaS
  • Assign an owner per node with a runbook and rotation plan
  • Establish patch SLAs per severity; measure MTTR to KEV
  • Build an incident response playbook keyed to supply-chain scenarios (maintainer ATO, worm, hidden transitive, build poisoning)
  • Table-top a Chalk/Debug-scale and an Axios-scale incident annually

Source & Code

  • Branch protection on default branch
  • Required review (>=1), with CODEOWNERS for sensitive paths
  • Signed commits + signed tags enforced
  • Disallow force-push to protected branches/tags
  • Secret scanning enabled on all repos (GitGuardian / GitHub push protection)
  • No long-lived secrets in CI — OIDC federation to cloud

Dependencies

  • Lockfiles committed for all language ecosystems
  • --require-hashes or equivalent for reproducibility where supported
  • Dependabot or Renovate enabled, with minimumReleaseAge >= 7 days
  • OSV-Scanner or Trivy on every PR + on a nightly schedule
  • Dependency-Track (or equivalent) SBOM aggregation and VEX
  • Behavioral scanner (Socket, Phylum) wired into PR gate
  • Private-registry virtual proxy (Nexus/Artifactory) quarantining new packages

Build / CI

  • Ephemeral runners only
  • GitHub Actions pinned by commit SHA, not tag
  • Minimal permissions: per job; default deny
  • ignore-scripts=true where possible in CI installs
  • Egress allowlist on runners
  • No toJSON(secrets) anywhere
  • Tamper-evident audit log export
  • Separation of duties: code author != release signer

Artifacts / Packaging

  • SBOM generated at build (CycloneDX + SPDX)
  • SBOM attached to artifact as attestation (cosign attest)
  • Image signed keyless via cosign + Sigstore
  • SLSA L3 provenance via slsa-github-generator
  • Reproducible builds where feasible
  • Artifacts immutable once published

Registry / Distribution

  • 2FA required on all maintainer accounts (hardware, not SMS)
  • Trusted Publishers (OIDC) replacing long-lived tokens
  • Publish-alert notifications to shared channel
  • Namespace/scope claim for internal packages on public registries
  • Repository firewall quarantining newly published or low-reputation deps

Deploy / Runtime

  • Admission controller (Kyverno / policy-controller) verifies cosign signature + SLSA predicate
  • Images referenced by digest only
  • Deny-by-default egress NetworkPolicy
  • IMDSv2 only; workload identity; no baked creds
  • Runtime detection (Falco/Tetragon) for shells-from-package dirs
  • Canary / staged rollout — never deploy all systems simultaneously (OWASP A03 guidance)

Developer Host

  • Release-age gate configured in npm/pnpm/yarn/bun/pip/uv
  • ignore-scripts / enableScripts: false globally
  • Hardware MFA on registry accounts
  • EDR with script-execution telemetry
  • IDE extension allowlist; review extension updates
  • Verify AI-suggested packages before install (slopsquatting)

Response

  • On suspected compromise, assume full credential exposure — rotate all secrets, cloud keys, SSH keys, tokens touched by the affected environment
  • Rebuild affected workstations and CI runners from a clean image
  • Pull audit logs for the suspected window
  • Block the indicator at repository firewall and network egress
  • Publish an internal advisory with affected package/version/IOC list
  • Retrospect to close the gap that permitted the compromise

17. Reference Configurations

17.1 Full hardened .npmrc

registry=https://nexus.myorg.local/repository/npm-group/
@myorg:registry=https://nexus.myorg.local/repository/npm-private/
always-auth=true
audit=true
fund=false
save-exact=true
min-release-age=7
ignore-scripts=true
engine-strict=true
package-lock=true

17.2 Full hardened pip.conf

[global]
index-url = https://artifactory.myorg.local/artifactory/api/pypi/pypi/simple/
require-virtualenv = true
disable-pip-version-check = true
no-cache-dir = false
require-hashes = true

17.3 GitHub Actions repository default permissions

permissions:
  actions: read
  contents: read
  deployments: none
  id-token: none
  issues: none
  packages: none
  pages: none
  pull-requests: none
  repository-projects: none
  security-events: none
  statuses: none

Escalate per-workflow only where needed.

17.4 Trivy image + config scan

trivy image --severity HIGH,CRITICAL --exit-code 1 \
  --ignore-unfixed \
  --format sarif --output trivy.sarif \
  ghcr.io/myorg/app@sha256:abcd...

trivy config --severity HIGH,CRITICAL --exit-code 1 .
trivy fs --scanners secret,vuln,misconfig .

17.5 OSV-Scanner offline

osv-scanner --experimental-offline --experimental-download-offline-databases ./

17.6 Syft + Grype end-to-end

syft dir:. -o cyclonedx-json=sbom.cdx.json
cosign sign-blob --yes --bundle sbom.cosign.bundle sbom.cdx.json
grype sbom:sbom.cdx.json --fail-on high -o sarif > grype.sarif

17.7 Policy-as-code example (Conftest / OPA on Dockerfile)

package main

deny[msg] {
  input[i].Cmd == "from"
  val := input[i].Value[0]
  not contains(val, "@sha256:")
  msg := sprintf("FROM %s must use @sha256 digest", [val])
}

deny[msg] {
  input[i].Cmd == "run"
  contains(input[i].Value[_], "curl")
  contains(input[i].Value[_], "|")
  contains(input[i].Value[_], "sh")
  msg := "curl | sh is banned; use pinned, verified installers"
}

17.8 Dependency-Track policy example

PolicyConditionAction
New high-severity CVEcomponent.vuln.severity >= HIGHFail build
Unmaintained depcomponent.last_modified > 24 monthsWarn
Unapproved licenselicense NOT IN allowlistFail
Dep from untrusted registrycomponent.purl !~ allowed_registriesFail
New publishercomponent.publisher NEWManual review

17.9 Release playbook summary

1. Feature branch -> PR -> required review -> merge to main
2. Tag v* -> triggers release workflow (OIDC, read-only by default)
3. Workflow: build -> SBOM -> scan -> sign -> attest (SLSA + SBOM)
4. Publish artifact + signature bundle to registry
5. Admission controller verifies at deploy time
6. Canary rollout 5% -> 25% -> 100% with automated rollback
7. Post-deploy: runtime telemetry + SBOM archived alongside release

17.10 Emergency triage on a suspected compromised dependency

1. Identify affected package + version(s) from advisory
2. Query SBOM store: "which services ship this?"
3. For each hit:
   - Pin to last-known-good version and force-rebuild
   - Invalidate all secrets accessible from the build and runtime context
   - Rebuild and redeploy affected workloads from clean state
   - Review CI runner logs + egress traffic during vulnerable window
4. Block malicious version at repository firewall
5. Add advisory to internal KEV-equivalent list
6. Notify downstream consumers if you publish packages
7. Post-incident: determine which SLSA level / SBOM coverage / admission rule would have prevented it; file follow-up action items

Appendix A — Frameworks & Standards Quick Map

StandardBodyScope
SLSA v1.1OpenSSFBuild integrity levels, provenance format
in-totoCNCFAttestation statement format
Sigstore / cosignOpenSSFKeyless signing, transparency log
SPDX 2.3 / 3.0Linux FoundationSBOM (compliance-oriented)
CycloneDX 1.5/1.6OWASPSBOM (security-oriented), VEX, ML-BOM
NIST SSDF (SP 800-218)NISTSecure software development framework
EO 14028US Executive OrderFederal software supply chain baseline
NIST SP 800-161 Rev.1NISTC-SCRM for systems and organizations
ISO/IEC 5230 (OpenChain)ISOOSS compliance program
OWASP SAMM / ASVS V15OWASPSecure coding & architecture verification
CIS Software Supply Chain Security GuideCISBenchmark controls
SAFECode Software Integrity ControlsSAFECodeIntegrity control practices

Appendix B — Key CWEs

CWEDescription
CWE-477Use of Obsolete Function
CWE-1035Using Components with Known Vulnerabilities (2017 Top 10 A9)
CWE-1104Use of Unmaintained Third-Party Components
CWE-1329Reliance on Component That Is Not Updateable
CWE-1357Reliance on Insufficiently Trustworthy Component
CWE-1395Dependency on Vulnerable Third-Party Component

Appendix C — Sources (29 articles)

  1. 12 Months That Changed Supply Chain Security (Silobreaker)
  2. 2026 Supply Chain Security Report — Lessons from a Year of Devastating Attacks (Bastion)
  3. OWASP Top 10 2025 A03 — Software Supply Chain Failures (Authgear)
  4. Axios Compromise on npm Introduces Hidden Malicious Package (Sonatype)
  5. Axios npm Package Compromised in Supply Chain Attack (InfoQ)
  6. Compromised dYdX npm and PyPI Packages Deliver Wallet Stealers and RAT Malware (The Hacker News)
  7. Five Key Flaws Exploited in 2025’s Major Software Supply Chain Incidents (Infosecurity Magazine)
  8. Hackers Supply Chain Attack Moves From npm to PyPI as Trivy Breach Extends into LiteLLM (Semgrep)
  9. How to Prevent OWASP Software Supply Chain Failures (CrossClassify)
  10. LiteLLM PyPI Packages Compromised in Expanding TeamPCP Supply Chain Attacks (Help Net Security)
  11. Malicious PyPI and npm Packages Discovered Exploiting Dependencies in Supply Chain Attacks (The Hacker News)
  12. N. Korean Hackers Spread 1,700 Malicious Packages Across npm, PyPI, Go, Rust (The Hacker News)
  13. NPM Supply Chain Attacks Explained — Dependency Confusion, Exploits, and Defense (jsmon)
  14. OWASP Top 10 2025 A03 — Software Supply Chain Failures (OWASP)
  15. Predictions for Open Source Security in 2025 — AI, State Actors, and Supply Chains (OpenSSF)
  16. Protecting Your Software Supply Chain — Typosquatting and Dependency Confusion (GitGuardian)
  17. PyPI, npm, and the New Frontline of Software Supply Chain Attacks (RapidFort)
  18. Securing Software Supply Chains — Critical Infrastructure Priorities for 2026 (Leadership Connect)
  19. SLSA Framework — The Definitive Guide for Securing Your Software Supply Chain (Practical DevSecOps)
  20. Software Supply Chain Attacks 2025–2026 — Axios, Shai-Hulud, Chalk, TeamPCP (Cyber Army)
  21. Software Supply Chain Risks — 2026 Software Supply Chain Report (Sonatype)
  22. Supply-Chain Attack Defense — Developer Host Machine Hardening (gist)
  23. Supply-chain Levels for Software Artifacts (slsa.dev)
  24. Supply Chain Attack — How Attackers Weaponize Software Supply Chains (Netlas)
  25. Supply Chain Attacks Are Exploiting Our Assumptions (Trail of Bits)
  26. Supply Chain Attacks in Q4 2025 — From Isolated Incidents to Systemic Failure Modes (Sygnia)
  27. Supply Chain Security in CI — SBOMs, SLSA, and Sigstore (nathanberg.io)
  28. The 2026 Guide to Software Supply Chain Security (Cloudsmith)
  29. The Next Wave of Supply Chain Attacks — NPM, PyPI, Docker Hub Set the Stage for 2026 (LinuxSecurity)

This document synthesizes publicly reported research and advisories for defensive reference. It contains no reproduction steps, no working malicious code, and no attacker tooling. All code snippets are defensive configurations.