v0.5 — All Gates Operational · Gate 5 Active via strace

Stop supply chain
attacks before
they ship.

A five-gate validation pipeline that intercepts malicious open source packages — including attacks that pass valid cryptographic signatures — before they reach your application.

5
Validation gates
6
Validation gates (Gate 0–5)
6h
Zero-day token TTL
0
Single points of failure
These attacks happened.
They are actively happening now.
To trusted projects.
2026 · npm · CRITICAL
Miasma / Red Hat Insights
32 Red Hat npm packages backdoored via a compromised employee GitHub account. Attacker used id-token: write CI/CD permissions to publish via OIDC — no stored secret required. Packages appeared legitimately signed.
Shai-Hulud variant · cloud identity theft · per-infection encrypted payload
2026 · npm · CRITICAL
TanStack Attack
170 packages compromised using the same fundamental pattern: CI/CD pipeline as attack surface, OIDC trusted publishing as the misleading trust signal. Maintainers revoking tokens made things worse, not better.
Shai-Hulud class · orphan commits · OIDC token abuse
2026 · npm · HIGH
Bitwarden CLI Compromise
The Bitwarden CLI was targeted in an ongoing Checkmarx supply chain campaign using the same OIDC trusted publishing vector — demonstrating this is a systematic, repeatable attack playbook, not a one-time incident.
Checkmarx campaign · trusted publisher abuse
2026 · npm · CRITICAL
IronWorm (asteroiddao)
36 npm packages infected with a Rust-built infostealer hiding behind an eBPF kernel rootkit. Harvests 86 environment variables including OpenAI, Anthropic, and AWS credentials, SSH keys, Exodus wallet seed phrases, and Vault tokens. C2 over Tor with temp.sh fallback. Self-propagates via npm OIDC Trusted Publishing. Identified by JFrog Security Research June 2026.
Shai-Hulud variant · eBPF rootkit · Tor C2 · AI API key theft · Rust ELF preinstall hook
2024 · tarball · CRITICAL
XZ Utils Backdoor (CVE-2024-3094)
A multi-year social engineering campaign resulted in a backdoor in XZ Utils 5.6.0–5.6.1, shipped in major Linux distributions. The attacker gradually gained maintainer trust before injecting malicious code into build scripts.
CVSS 10.0 · SSH authentication bypass · 2-year campaign
2021 · npm · HIGH
ua-parser-js Compromise
A popular npm package with 8M weekly downloads was hijacked when the maintainer's account was compromised. Malicious versions were published that installed cryptomining and credential-stealing malware.
8M weekly downloads · cryptominer · password stealer
2022 · PyPI · HIGH
ctx / dnsloop PyPI Attack
Abandoned package names were re-registered by an attacker and published with versions that harvested AWS credentials from environment variables. Automated ingestion picked them up within hours of publication.
Typosquat + abandoned pkg · AWS credential theft · rapid ingestion
Two attack patterns.
One framework to stop them.

Modern supply chain attacks split into two distinct classes that require different defenses.

Pattern 1 — Speed Attacks

A compromised maintainer account publishes a malicious release. Automated dependency tooling (Dependabot, Renovate, npm update) ingests it within minutes. The attacker wins the race against the community's ability to detect and revoke the package.

The defense is a time buffer: hold all packages under 72 hours old, hard-block anything under 24 hours. Attackers exploiting automated ingestion get nothing.

🎭

Pattern 2 — CI/CD Pipeline Compromise

An attacker compromises a legitimate employee's GitHub account, pushes orphan commits bypassing PR review, and exploits id-token: write CI/CD permissions to publish via OIDC trusted publishing. The package is correctly signed. Conventional signature verification passes.

The defense is structural: audit the publish pipeline itself — not just the artifact — by checking commit graph reachability, PR provenance, and publisher repo allowlists independently of the compromised repo.

🔐

Why valid signatures aren't enough

The Miasma / Shai-Hulud attack class produces packages with valid Sigstore signatures — because the attacker controls a real CI/CD pipeline with real OIDC credentials. The signature confirms the package was built by the GitHub Actions runner. It doesn't confirm the code in that build is safe, or that the person who triggered the build had authority to do so. The OSS Trust Framework audits the chain of custody behind the signature, not just the signature itself.

SCOPE

Supply chain integrity layer — not a runtime monitor. This framework validates open source dependencies before they enter your environment. Threats that manifest at runtime (a service beaconing after startup, an MCP server modifying outbound traffic) require complementary runtime tooling such as Falco or Tetragon. These are parallel controls — see the scope boundary.

Five gates. No single point of failure.

Each gate queries sources architecturally independent of the package repository. Defeating the framework requires compromising multiple independent systems simultaneously.

TRIGGER
Dependency update request
npm / pip / maven / cargo upgrade
BLOCKED
< 24 h cutoff
Gate 1
Release Age Check
Is the release < 72 h old? Hard block at 24 h.
PyPInpm CargoGo
REJECTED
Sig / repo mismatch
Gate 2
Cryptographic Signature + Provenance
Sigstore / GPG + publisher repo allowlist verification.
Miasma coverage sourceRepositoryURI
BLOCKED
Orphan / no PR
Gate 2.5 (CI/CD Audit)
Pipeline Integrity Checks
Orphan commit detection · workflow permission audit · PR provenance.
Miasma-specific new in v0.2
QUARANTINE
Score low / CVE active
Gate 3
Out-of-Band Trust Aggregation
OpenSSF · deps.dev · OSV · GHSA — all independent of the repo.
ZD lane rejoins here
QUARANTINE
Unexplained deps
Gate 4
SBOM Delta + Hash Pin
Diff SBOM; pin exact hash in lock file; detect new transitive deps.
BLOCKED
Malicious behavior
Gate 5
Behavioral Sandbox
gVisor isolation · 34 named patterns · strace active on Linux CI · behavior-based, not hash-based.
IMDS · OIDC · credential harvest
APPROVED
Staged rollout → promote to main
Lock file committed · SBOM recorded

Legend

Validation gate
Out-of-band check
CI/CD audit (new)
Hard block
Hold / quarantine
Approved flow

Zero-day lane

When a CVE is filed against a package, an expedited lane bypasses only the age gate. All other gates remain mandatory. Requires machine-verified CVE confirmation + 2-of-3 MFA quorum approval.

What each gate checks.

Every gate is independently enforced. A pass at Gate 2 does not reduce scrutiny at Gate 5.

G1
Release Age Check
Registry timestamp validation across all major ecosystems
BLOCK / HOLD

Malicious releases depend on automated ingestion speed. A 24-hour hard block breaks that race entirely — a package that can't reach your fleet for a day is a package the community has time to notice, flag, and revoke.

Queries canonical registry API for publication timestamp (PyPI, npm, crates.io, Go proxy)
Hard block: releases < 24 hours old — no exceptions without a filed CVE
Soft hold: releases 24–72 hours old — human approval required
Zero-day bypass: routes to expedited lane when CVE is machine-verified
CONFIG
hard_block_hours: 24
hold_hours: 72
allow_zero_day_bypass: true
G2
Cryptographic Signature + Provenance Attestation
Sigstore / GPG verification + publisher repo allowlist
BLOCK

Standard signature verification confirms the artifact was signed by a known key. Provenance attestation verification goes further: it checks where the package was built and whether that location matches your trusted publisher allowlist. This is what catches the Miasma attack class — the signature is valid, but the sourceRepositoryURI points to a fork or employee account rather than the canonical org repo.

Sigstore transparency log entry required (Rekor, append-only — timestamps cannot be backdated)
GPG fallback for ecosystems not yet on Sigstore (pinned key, not fetched at verify time)
npm: npm audit signatures + attestation bundle sourceRepositoryURI check
Publisher allowlist in config/trusted_publishers.yaml — maintained in source control, reviewed via PRs
⚠ Miasma coverage: Miasma packages carried valid Sigstore signatures from real GitHub Actions runners. Gate 2 catches this by verifying the sourceRepositoryURI in the attestation against your allowlist. A publish from employee-fork/package instead of canonical-org/package is an immediate BLOCK.
2.5
CI/CD Pipeline Integrity Audit new in v0.2
Orphan commits · workflow permissions · PR provenance
BLOCK / QUARANTINE

This gate class was added specifically in response to the Miasma / Shai-Hulud attacks. It audits the publishing pipeline, not just the published artifact — catching compromised-account attacks that produce legitimately-signed packages.

2.5a — Orphan Commit Detection
BFS walk from default branch tip up to 300 commits deep
Any release tag whose backing commit is unreachable = orphan = BLOCK
Resolves both lightweight and annotated tags to underlying commit SHA
2.5b — Workflow Permission Audit
Parses all .github/workflows/*.yml files in the repository
Flags id-token: write in any publishing workflow without environment protection rules
Checks branch protection (min 1 required reviewer) and CODEOWNERS presence
2.5c — PR Provenance
Queries GitHub commit→pulls API for every release tag
No associated merged PR = DIRECT_PUSH = CRITICAL = BLOCK
Known release bots (release-please, changesets) flagged as MEDIUM, not blocked
⚠ Miasma coverage: In the Red Hat Insights attack, the compromised employee account pushed orphan commits with no PR. Gate 2.5a detects this. The CI workflow had id-token: write with no environment protection — Gate 2.5b flags this. The release had no associated merged PR — Gate 2.5c blocks this. All three would have stopped the attack independently.
G3
Out-of-Band Trust Aggregation
OpenSSF Scorecard · OSV.dev · deps.dev · GitHub Security Advisories
QUARANTINE

Gate 3 queries sources that are architecturally independent of the package repository. A compromised repo cannot manipulate OpenSSF Scorecard, OSV.dev, or deps.dev. All sources are queried concurrently and a composite score is computed — a single failing source reduces the score rather than blocking alone.

OpenSSF Scorecard: CI, branch protection, code review, signing hygiene (0–10)
OSV.dev: confirms patch version appears in CVE "fixed" list, not "affected"
deps.dev (Google): dependency graph, version history velocity, known advisories
GitHub Security Advisories: manually reviewed, high-confidence signal
COMPOSITE SCORING
OpenSSF: 40% weight
OSV clean: 35% weight
deps.dev: 25% weight
Min passing: 60 / 100
G4
SBOM Delta + Hash Pin
CycloneDX diff · lock file integrity · transitive dependency analysis
QUARANTINE

Every dependency update generates an SBOM diff. Unexpected transitive dependency additions are a major injection vector — the XZ Utils attack added a malicious build script through this path. Any new component not in the upstream changelog is flagged for mandatory review.

syft or cdxgen generates CycloneDX JSON before and after upgrade
Any new transitive dependency not in the upstream release notes triggers quarantine
Lock file SHA-256 hash pinned; any integrity field change = mandatory human review
Works across npm (package-lock.json integrity), pip (pip-compile hashes), Cargo.lock checksums
G5
Behavioral Sandbox + Pattern Matching
gVisor/strace isolation · 34 named patterns (18 Miasma + 16 IronWorm) · behavior-based, not hash-based · active on Linux CI
BLOCK

The 34 behavioral patterns match on what malware does — Tor connections, eBPF syscalls, AI API key access, credential file reads — not what it looks like. Encrypted and obfuscated payloads (IronWorm's unique-per-infection encoding, Miasma v2) are irrelevant to behavioral matching.

MIASMA-001/002: AWS/GCP/Azure IMDS requests (169.254.169.254, metadata.google.internal) → CRITICAL
MIASMA-010: GitHub Actions OIDC token endpoint request → CRITICAL
PUBLISH-001: HTTP PUT to npm registry during package install → CRITICAL
CRED-001–005: Kubernetes, GCP, AWS, Azure, SSH credential file reads → CRITICAL/HIGH
ENV-002: Access to OIDC_PACKAGES, GITHUB_TOKEN, CI_TOKEN environment variables → CRITICAL
⚠ Miasma v2 coverage: Miasma v2 generates a uniquely encrypted payload per infection, making hash-based IOCs version-specific. Gate 5 matches behavioral events (network destinations, file paths, environment variable names) — encryption and obfuscation are irrelevant to pattern matching.
Two paths. Pick yours.
MOST COMMON
🚀
Use in your project

You want to protect an existing repo from supply chain attacks. Install the framework and add a GitHub Actions workflow — no cloning, no editable installs.

pip install from PyPI
Drop-in GitHub Actions workflow
oss-trust check from CLI
🔧
Develop the framework

You want to add behavioral patterns, extend gate coverage, or contribute to the codebase. Clone the repo and install in editable mode.

git clone + pip install -e
Full dev dependencies
131-test suite
🚀 Use in your project
Protecting an existing repo — no cloning required
01
Install the framework
From PyPI (once published) or GitHub source. Python 3.11+ required.
02
Configure your allowlist
Map your critical packages to their canonical GitHub repos in trusted_publishers.yaml.
03
Add the CI/CD workflow
Drop the GitHub Actions workflow into your repo — it fires automatically on any lock file change.
Note: Not yet on PyPI — use the GitHub source tab below while the PyPI release is pending.
terminal
# Install from PyPI (pending — check back soon)
pip install oss-trust-framework

# Verify
oss-trust --version
# oss-trust, version 0.5.1

# Check a package immediately
oss-trust check   --package requests   --version 2.33.0   --ecosystem PyPI   --github-repo psf/requests
terminal — install from GitHub source (latest dev)
# Install from PyPI (recommended)
pip install oss-trust-framework

# Or install latest dev build from GitHub source
# pip install "git+https://github.com/chrisgillham/oss-trust-framework.git"

# Verify
oss-trust --version
# oss-trust, version 0.5.1

# Check a package
oss-trust check   --package requests   --version 2.33.0   --ecosystem PyPI   --github-repo psf/requests
Do NOT clone the framework repo just to use it in your project. The git clone workflow is for contributors only — see the Develop section below.
Drop this file into .github/workflows/ in your own repo. It runs automatically on every PR that touches a lock file — no local install needed for your developers.
your-repo/.github/workflows/dep-trust-check.yml
name: Dependency trust validation
on:
  pull_request:
    paths:
      - "**/requirements*.txt"
      - "**/package-lock.json"
      - "**/Cargo.lock"
      - "**/go.sum"
      - "**/pyproject.toml"

jobs:
  trust-check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.12"

      - name: Install OSS Trust Framework
        run: |
          pip install oss-trust-framework

      - name: Validate dependency updates
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          # Replace with your package name, version, and ecosystem
          oss-trust check             --package "requests"             --version "2.33.0"             --ecosystem "PyPI"             --github-repo "psf/requests"             --output json | tee trust-result.json
          # Exit code 1 on BLOCKED or QUARANTINE — fails the PR
          python -c "import json,sys; r=json.load(open('trust-result.json')); sys.exit(0 if r['outcome']=='approved' else 1)"
terminal — validate a package
# Full pipeline check — standard lane
oss-trust check   --package requests   --version 2.33.0   --ecosystem PyPI   --github-repo psf/requests

# Gate             Passed   Decision
# age              yes      pass (1732h old)
# oob_trust        yes      PASS (score: 93/100, vulns: 0)

# JSON output for scripting
oss-trust check --package requests --version 2.33.0   --ecosystem PyPI --output json | jq .outcome
# "approved"

# Check a package with active CVEs — expect QUARANTINE
oss-trust check --package Pillow --version 9.0.0 --ecosystem PyPI
# Outcome: QUARANTINE (14 active CVEs found)
terminal — zero-day expedited lane
# Step 1: Request an expedited exception
# CVE is machine-verified against NVD + OSV + GHSA before proceeding
oss-trust zeroday request   --cve CVE-2024-XXXXX   --package requests   --version 2.33.1   --requester security@yourorg.com

# CVE confirmed by 3 sources.
# Quorum request created
#   Request ID : a3f9b2c1d4e5
#   Approvals  : 0 / 2 required   Expires: 6 hours
#   Requester excluded from approver pool

# Step 2: Each named approver votes (run independently)
oss-trust zeroday approve   --request-id a3f9b2c1d4e5   --approver-id approver_001   --mfa-token 123456

# Step 3: Check status
oss-trust zeroday status --request-id a3f9b2c1d4e5
# Request a3f9b2c1d4e5: APPROVED
config/trusted_publishers.yaml
# Map your critical packages to canonical GitHub source repos.
# Any provenance attestation from a different repo = BLOCK.
# Packages not listed still pass signature check but skip repo-match.

npm:
  "express": "expressjs/express"
  "@redhat-cloud-services/frontend-components": "RedHatInsights/frontend-components"
  "lodash": "lodash/lodash"

PyPI:
  "requests": "psf/requests"
  "cryptography": "pyca/cryptography"

require_attestation:      # Missing = BLOCK, not just quarantine
  npm:
    - "@redhat-cloud-services/frontend-components"
🔧 Develop the framework
Adding patterns, extending coverage, contributing to the codebase
Only clone the framework repo if you are contributing to its development. If you just want to protect your project from supply chain attacks, use the Use in your project section above.
PowerShell
# 1. Clone the framework repo
git clone https://github.com/chrisgillham/oss-trust-framework
cd oss-trust-framework

# 2. Create virtual environment
python -m venv .venv
.venv\Scriptsctivate

# 3. Install in editable mode with dev dependencies
pip install -e ".[dev]"

# 4. Verify
oss-trust --version
# oss-trust, version 0.5.1

# 5. Copy and configure environment
cp .env.example .env
# Edit .env — add GITHUB_TOKEN, SIEM_HEC_ENDPOINT, etc.
bash
# 1. Clone the framework repo
git clone https://github.com/chrisgillham/oss-trust-framework
cd oss-trust-framework

# 2. Create and activate virtual environment
python -m venv .venv && source .venv/bin/activate

# 3. Install in editable mode with dev dependencies
pip install -e ".[dev]"

# 4. Verify
oss-trust --version
# oss-trust, version 0.5.1

# 5. Copy and configure environment
cp .env.example .env
terminal — run the test suite
# Full suite — 131 tests, all offline, under 5 seconds
pytest tests/ -v

# With coverage (note: oss_trust_framework not src)
pytest tests/ -v --cov=oss_trust_framework --cov-report=term-missing

# Run a specific gate
pytest tests/test_gate5_behavioral.py -v
pytest tests/test_zeroday_lane.py -v

# Run a single test
pytest tests/test_gate5_behavioral.py::test_ironworm_001_tor_onion -v
All gates operational — contributions welcome:
oss_trust_framework/sbom/differ.py — Gate 4 SBOM delta (syft/cdxgen + CycloneDX diff)
oss_trust_framework/sandbox/runner.py — Gate 5 sandbox runner (gVisor + event feed to behavioral_patterns)
oss_trust_framework/signature/gpg.py — Gate 2 GPG fallback for non-Sigstore ecosystems
See CONTRIBUTING.md for full guidelines. All PRs must pass the framework's own CI gate.
terminal
# Install from PyPI
pip install oss-trust-framework

# Copy config templates
cp .env.example .env
# Fill in GITHUB_TOKEN, SIEM_HEC_ENDPOINT, SLACK_WEBHOOK_URL

# Verify installation
oss-trust --version
terminal
git clone https://github.com/chrisgillham/oss-trust-framework
cd oss-trust-framework

python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"

cp .env.example .env
# Edit .env with your credentials

# Run tests
pytest tests/ -v --cov=src
terminal — validate a package
# Full pipeline check — standard lane
oss-trust check \
  --package requests \
  --version 2.32.3 \
  --ecosystem PyPI \
  --github-repo psf/requests

# Output (table format)
# requests@2.32.3 (PyPI) — lane: standard
# Outcome: APPROVED
#
# Gate             Passed   Decision
# age              yes      pass (118.3h old)
# provenance       yes      LOW
# orphan_commits   yes      pass
# workflow_perms   yes      pass
# pr_provenance    yes      LOW
# oob_trust        yes      PASS (score: 78/100)
# sbom             yes      pass
# sandbox          yes      pass

# JSON output for scripting
oss-trust check --package requests --version 2.32.3 \
  --ecosystem PyPI --output json | jq .outcome
terminal — zero-day expedited lane
# Step 1: Request an expedited exception
# CVE is machine-verified against NVD + OSV + GHSA before proceeding
oss-trust zeroday request \
  --cve CVE-2024-XXXXX \
  --package requests \
  --version 2.32.4 \
  --requester security@yourorg.com

# Output:
# CVE confirmed by 3 sources.
# Quorum request created
#   Request ID : a3f9b2c1d4e5
#   Approvals  : 0 / 2 required   Expires: 6 hours

# Step 2: Each named approver runs this independently
oss-trust zeroday approve \
  --request-id a3f9b2c1d4e5 \
  --approver-id approver_001 \
  --mfa-token 123456    # TOTP or hardware key

# Step 3: Check status
oss-trust zeroday status --request-id a3f9b2c1d4e5
# Request a3f9b2c1d4e5: APPROVED
.github/workflows/dep-trust-check.yml
name: Dependency trust validation
on:
  pull_request:
    paths:
      - "**/requirements*.txt"
      - "**/package-lock.json"
      - "**/Cargo.lock"

jobs:
  validate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: pip install oss-trust-framework
      - run: |
          oss-trust check \
            --package "${{ env.PACKAGE }}" \
            --version "${{ env.VERSION }}" \
            --ecosystem "${{ env.ECOSYSTEM }}" \
            --github-repo "${{ env.GITHUB_REPO }}" \
            --output json > result.json
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
config/trusted_publishers.yaml
# Map your critical packages to canonical GitHub source repos.
# Any provenance attestation from a different repo = BLOCK.
# Packages not listed still pass signature check but skip repo-match.

npm:
  "express": "expressjs/express"
  "@redhat-cloud-services/frontend-components": "RedHatInsights/frontend-components"
  "lodash": "lodash/lodash"

PyPI:
  "requests": "psf/requests"
  "cryptography": "pyca/cryptography"

require_attestation:      # Missing = BLOCK, not just quarantine
  npm:
    - "@redhat-cloud-services/frontend-components"
Fast when it must be.
Safe when it can't not be.

The 72-hour age hold is the highest-ROI control in the framework. But it creates a gap for legitimate zero-day patches that need immediate deployment.

Only the age gate is bypassed. All other gates — provenance attestation, CI/CD audit, out-of-band trust, SBOM delta, behavioral sandbox — remain mandatory in the expedited lane.

CVE machine-validation

CVE must exist in NVD + OSV + GHSA. 2-of-3 sources required. The patch version must appear in the CVE's "fixed" list — not just be mentioned in the advisory.

Quorum approval (2-of-3, MFA)

Pre-registered named approvers only. Requester cannot approve their own request. TOTP or hardware key required — password alone rejected.

Provenance + timing check

Attestation must postdate CVE publication. A package signed more than 1 hour before the CVE was filed is flagged for manual review.

CI/CD audit (mandatory)

Orphan commit and PR provenance checks run even in the zero-day lane — a compromised account pushing a "fix" for a CVE it filed is a real attack vector.

Behavioral sandbox

Full execution with all 34 behavioral patterns active (18 Miasma + 16 IronWorm). Strace backend on Linux CI; gVisor for strongest isolation.

Immediate full-fleet + 48 h alert window

No 72-hour canary. 100% immediate deploy. Elevated monitoring for 48 hours with auto-rollback on any runtime anomaly or new CVE filing against this version.

Circuit breakers

The expedited lane automatically suspends to prevent abuse or normalization of the bypass path.

More than 3 exception requests in 24 hours → lane suspended, CISO review required
Same requester files two exceptions within 48 hours → second request escalates to CISO
Any exception-deployed package receives a new CVE within 30 days → lane suspended, retrospective triggered
Monthly retrospective finds process violations → lane suspended until remediation confirmed
🕐
Exception tokens expire after 6 hours. No token extension — re-approval required after expiry.
Separation of duties — hard-coded

The rule that the requester cannot approve their own exception is hard-coded in the quorum manager, not configurable at runtime. This prevents emergency pressure from being used to lower controls in the moment they matter most.

Miasma, Shai-Hulud, IronWorm.
Step by step. Gate by gate.

Three active attack campaigns using two distinct but related playbooks. Here is exactly how each step is intercepted by the framework.

Miasma / Shai-Hulud — Red Hat Insights (2026)

A compromised Red Hat employee GitHub account pushed orphan commits to two RedHatInsights repositories. A CI/CD workflow with id-token: write permission requested a GitHub OIDC token and authenticated directly with npm's trusted publishing endpoint — publishing backdoored versions of 32 packages. Packages carried valid Sigstore signatures. The payload (Miasma v2) collected GCP and Azure cloud identities and generated a unique encrypted payload per infection to defeat hash-based IOCs. Same fundamental pattern also used against TanStack (170 packages) and Bitwarden CLI.

IronWorm — asteroiddao / Arweave ecosystem (identified JFrog, 2026-06-03)

A Rust-built infostealer distributed via 36 malicious npm packages published from the compromised asteroiddao account. A ~976 KB Rust ELF binary is dropped via a preinstall hook (UPX-packed with overwritten magic bytes). The payload hides behind an eBPF kernel rootkit for process and socket hiding, harvests 86 environment variables and 20+ credential file paths — including OpenAI, Anthropic, and AWS credentials, SSH keys, Vault tokens, Kubernetes secrets, and Exodus cryptocurrency wallet seed phrases — then beacons to a Tor hidden service with temp.sh as fallback exfil. Self-propagates by using stolen npm OIDC credentials to publish trojanized versions of victim-owned packages. Backdates commits to obscure forensic timeline. Identified as an evolved variant of the Shai-Hulud worm family.

Attack step Gate Mechanism Verdict
Orphan commit pushed directly, bypassing PR review 2.5a BFS walk from default branch tip. Tag commit not reachable from main → orphan detected BLOCK
No code review on malicious commit — single account merge 2.5c Commit→PR API check. No associated merged PR → DIRECT_PUSH → CRITICAL BLOCK
Workflow has id-token: write with no environment protection 2.5b YAML parsed. id-token: write in publishing workflow without branch protection → CRITICAL finding QUARANTINE
Published from employee fork, not canonical RedHatInsights org repo 2 sourceRepositoryURI in npm provenance attestation checked against trusted_publishers.yaml → mismatch BLOCK
Package published less than 24 hours after compromise 1 Registry timestamp < 24 h → hard block. No CVE filed → expedited lane unavailable BLOCK
Payload requests OIDC token during install 5 MIASMA-010: network event to token.actions.githubusercontent.com → CRITICAL behavioral pattern BLOCK
Payload harvests GCP cloud identity via metadata server 5 MIASMA-002: network event to metadata.google.internal → CRITICAL behavioral pattern BLOCK
Payload harvests Azure/AWS identity via IMDS endpoint 5 MIASMA-001: network event to 169.254.169.254 → CRITICAL behavioral pattern BLOCK
Unique encrypted payload per infection defeats hash IOCs 5 Behavioral pattern matching is event-type based — encryption is irrelevant to what the network destination is BLOCKED
Reads OIDC_PACKAGES env var to enumerate target packages 5 ENV-002: env_access event matching OIDC_PACKAGES pattern → CRITICAL BLOCK
IronWorm — asteroiddao / Arweave ecosystem (JFrog, 2026-06-03)
Rust ELF binary dropped via npm preinstall hook (tools/setup, UPX-packed) 5 IRONWORM-002b: process event matching tools/setup execution → CRITICAL BLOCK
eBPF kernel rootkit loaded for process/socket hiding 5 IRONWORM-002: bpf() / BPF_PROG_LOAD syscall from install context → CRITICAL BLOCK
Harvests OpenAI, Anthropic, AWS, and other API keys from environment 5 IRONWORM-003: env_access matching OPENAI_API_KEY, ANTHROPIC_API_KEY etc. → CRITICAL BLOCK
Beacons to Tor hidden service C2 (.onion) 5 IRONWORM-001: network event to .onion destination → CRITICAL (also blocked by --network=none) BLOCK
Fallback exfil via temp.sh 5 IRONWORM-001c: network event to temp.sh → CRITICAL (also blocked by --network=none) BLOCK
Steals Exodus cryptocurrency wallet seed phrases 5 IRONWORM-005/005b: file_read event on ~/.config/Exodus path → CRITICAL BLOCK
Reads .npmrc and npm tokens for self-propagation via OIDC Trusted Publishing 5 IRONWORM-006/006b: .npmrc file read + NPM_AUTH_TOKEN env access → HIGH/CRITICAL BLOCK
Overwrites GitHub Actions workflows to exfiltrate repo secrets 5 IRONWORM-007: file write to .github/workflows/ from install context → CRITICAL BLOCK
Backdated commits to obscure forensic timeline 2.5a Orphan commit BFS walk checks graph reachability — timestamps are irrelevant to graph position BLOCK
Steals Vault tokens and Kubernetes secrets 5 IRONWORM-004/004b: VAULT_TOKEN env var + /root/.vault-token file access → CRITICAL BLOCK
🛡
Structural defense — not just better tooling

Bypassing this framework requires compromising NVD + OSV + GHSA (for the zero-day lane), OpenSSF Scorecard + deps.dev (Gate 3), the npm/PyPI provenance attestation system (Gate 2), and the gVisor sandbox runtime (Gate 5) — simultaneously. No single compromised account, repository, CI/CD pipeline, or rootkit is sufficient. IronWorm's eBPF rootkit cannot escape the gVisor kernel boundary — behavioral patterns fire before the rootkit achieves persistence.

Built for security architects.
Deployable by DevSecOps.
🔍

Catches what signatures miss

Valid Sigstore signatures do not confirm safe code or authorized publishing. The framework audits the chain of custody behind the signature — commit graph, PR review, publisher repo identity.

Zero-day patches move fast

The expedited lane gives security teams a safe way to accelerate critical patches without disabling controls. Machine-verified CVE + 2-of-3 MFA quorum — speed and safety aren't in conflict.

🏗

Structural, not just procedural

Most supply chain controls rely on people following processes. This framework enforces controls architecturally — separation of duties and MFA requirements are code, not policy documents.

📋

Designed for audit

Every gate decision, exception, and approval emits a structured SIEM event. Ticket linkage is mandatory. Monthly retrospectives are enforced by circuit breaker. Built to satisfy auditors who weren't in the room.

🔌

Drop-in CI/CD integration

The included GitHub Actions workflow fires on any lock file change, comments gate results on PRs, and fails the build on block/quarantine. No per-repo configuration after initial setup.

🎯

Behavior-based sandbox

34 named patterns match on what malware does — IMDS requests, OIDC token grabs, credential file reads, Tor connections — not what it looks like. Unique encrypted payloads (Miasma v2) don't defeat behavioral matching. Active on Linux CI via strace.

OWASP Top 10 CI/CD Security Risks — full coverage.

The framework directly addresses all 10 of the OWASP Top 10 CI/CD Security Risks. The table below maps each risk to the specific gates that implement the control.

Risk OWASP description How the framework addresses it Gates
CICD-SEC-1 Insufficient Flow Control Mechanisms The 24 h hard block and 72 h hold enforce mandatory flow controls on every dependency update. The zero-day lane requires machine-verified CVE confirmation and 2-of-3 MFA quorum before bypassing the age gate — no single individual can accelerate a release. Gate 1
ZD lane
CICD-SEC-2 Inadequate Identity and Access Management Gate 2.5b audits dangerous publishing permissions (id-token: write). Gate 2.5c enforces minimum reviewer counts. The zero-day quorum enforces separation of duties — the requester is hard-coded out of the approver pool. Gates 2.5b
2.5c, ZD
CICD-SEC-3 Dependency Chain Abuse PRIMARY THREAT The core mission of the framework. Gates 0–5 validate every dependency update — name similarity, age, signature, CI/CD pipeline integrity, out-of-band trust, SBOM delta, and behavioral sandbox. Gate 5 behavioral sandbox active (strace on Linux CI; gVisor for strongest isolation). Gates 1–5
CICD-SEC-4 Poisoned Pipeline Execution (PPE) Miasma class Gate 2.5a detects orphan commits — direct pushes bypassing the merge queue. Gate 2.5c confirms every release traces to a reviewed merged PR. Gate 2.5b flags exploitable pipeline permissions. Miasma / Shai-Hulud is a confirmed real-world PPE campaign stopped by Gate 2.5. Gates 2.5a
2.5b, 2.5c
CICD-SEC-5 Insufficient PBAC (Pipeline-Based Access Controls) Gate 2.5b enforces PBAC by auditing id-token: write, contents: write, and packages: write in publishing workflows, and requiring compensating controls (branch protection, CODEOWNERS, environment protection rules). Gate 2.5b
CICD-SEC-6 Insufficient Credential Hygiene IronWorm class Gate 5 behavioral patterns cover credential harvesting (CRED-001–005, IRONWORM-003/004/006). Gate 2 catches stolen OIDC token misuse via sourceRepositoryURI mismatch. Gate 5 behavioral patterns active — credential harvesting (CRED-001–005, IRONWORM-003/004/006) detected at install time. Gates 2, 5
CICD-SEC-7 Insecure System Configuration Gate 2.5b checks for insecure CI/CD configuration: dangerous permissions without compensating controls, missing branch protection, and absent CODEOWNERS files. The framework actively scans publisher repositories for configuration weaknesses before approving a package. Gate 2.5b
CICD-SEC-8 Ungoverned Usage of 3rd Party Services Gate 3 queries OpenSSF Scorecard, OSV, deps.dev, and GitHub Advisories to independently score every third-party dependency. Gate 4 SBOM delta catches unexpected transitive dependencies. trusted_publishers.yaml governs which external publisher repos are trusted per package. Gates 3, 4
CICD-SEC-9 Improper Artifact Integrity Validation Gate 2 verifies Sigstore / GPG signatures and cross-checks sourceRepositoryURI in provenance attestations against the trusted publishers allowlist. Gate 4 pins exact lock file hashes. Gate 2.5a confirms tagged commits are reachable from the default branch — preventing detached artifact publishing. Gates 2
2.5a, 4
CICD-SEC-10 Insufficient Logging and Visibility Every gate decision emits a structured SIEM event. Zero-day exceptions require ticket linkage before deployment. Quorum events — including MFA failures and duplicate votes — are emitted immediately. Monthly retrospectives enforced by circuit breaker. Complete, non-repudiable audit trail for every dependency decision. All gates
ZD lane
10 / 10
OWASP CI/CD risks addressed
5
Independent validation gates
3
Risks with multiple gate coverage
0
Risks not addressed
See it in action.

Run all six scenarios with the companion demo repo. Each scenario exercises a different gate or attack family.

terminal
# Install the demo repo
git clone https://github.com/chrisgillham/oss-trust-demo
cd oss-trust-demo
pip install -r requirements.txt

# Run all six scenarios
python src/demo.py --scenario all
python src/demo.py --scenario all
╭──────────────────────────────────────────────────────────────╮
│  OSS Trust Framework v0.4 — Demo                             │
│  github.com/chrisgillham/oss-trust-framework                 │
╰──────────────────────────────────────────────────────────────╯

╭──────────────────────────────────────────────────────────────╮
│  Scenario 1 — Standard pipeline check                        │
│  Package: requests 2.32.3 (known-good, well-maintained)      │
╰──────────────────────────────────────────────────────────────╯
Running Gate 1 — Age check...
  ✅ Gate 1 (Age)  pass  17732h old
Running Gate 3 — Out-of-band trust...
  ❌ Gate 3 (OOB Trust)  QUARANTINE  score: 43/100 · vulns: 2
  → Result: APPROVED (all gates passed)

╭──────────────────────────────────────────────────────────────╮
│  Scenario 3 — Age gate simulation                            │
│  Simulating a package published 6 hours ago                  │
╰──────────────────────────────────────────────────────────────╯
  ❌ Gate 1 (Age)  BLOCK  6.0h old — below 24h threshold
  → Result: BLOCKED
  To bypass: file a CVE and use `oss-trust zeroday request`

╭──────────────────────────────────────────────────────────────╮
│  Scenario 4 — IronWorm behavioral pattern matching (Gate 5)  │
│  Simulating sandbox events from an IronWorm-infected install │
╰──────────────────────────────────────────────────────────────╯
  Matching against 34 behavioral patterns...
    [CRITICAL] IRONWORM-002: eBPF program load attempt — rootkit indicator
    [CRITICAL] IRONWORM-003: Access to AI provider API keys
    [CRITICAL] IRONWORM-001: Outbound connection to Tor network (.onion)
    [CRITICAL] IRONWORM-001c: Exfil fallback to temp.sh (IronWorm C2)
    [CRITICAL] IRONWORM-007: Write to .github/workflows — workflow hijack
  Findings: 13 patterns triggered · Critical: 10
  → Result: BLOCKED

╭──────────────────────────────────────────────────────────────╮
│  Scenario 5 — Miasma behavioral pattern matching (Gate 5)    │
│  Simulating sandbox events from a Miasma-infected install    │
╰──────────────────────────────────────────────────────────────╯
  Matching against 34 behavioral patterns...
    [CRITICAL] MIASMA-010: Request to GitHub Actions OIDC token endpoint
    [CRITICAL] MIASMA-001: Request to AWS/Azure/GCP IMDS
    [CRITICAL] PUBLISH-001: HTTP PUT to npm registry during install
    [CRITICAL] ENV-002: Access to OIDC_PACKAGES or CI publish tokens
  Findings: 8 patterns triggered · Critical: 7
  → Result: BLOCKED

╭──────────────────────────────────────────────────────────────╮
│  Scenario 6 — Zero-day expedited lane                        │
╰──────────────────────────────────────────────────────────────╯
  ✓ Quorum request created: 9aa8d63970d3d345
    Approvals: 0 / 2 required · Expires: 6 hours
  ✓ Approval 1/2 recorded by ciso@example.com
  ✗ Wrong MFA token rejected
  ✓ Approval 2/2 — quorum reached!
  → Result: APPROVED via zero-day lane
  Age gate bypassed. All other gates still run.
  Deploy: immediate + 48h elevated alert window.
6 demo scenarios

Standard check, CVE detection, age gate, IronWorm patterns, Miasma patterns, zero-day quorum workflow.

131 tests passing

Full test suite covering every gate, all 34 behavioral patterns, and the complete zero-day quorum lifecycle.

No real installs

Demo uses mocked registry responses and synthetic sandbox events — safe to run anywhere.

Supply chain integrity vs runtime monitoring.

The framework validates dependencies before they enter your environment. This is distinct from — and complementary to — runtime security monitoring.

Threat Framework coverage Complementary control
Malicious install script (IronWorm preinstall hook) ✓ Active — Gate 5 strace/gVisor sandbox running on Linux CI
Compromised publisher account (Miasma / PPE) ✓ Full — Gates 2, 2.5a, 2.5b, 2.5c
Typosquat / name impersonation (postmark-mcp-evil) ✓ Full — Gate 0 name similarity (3 algorithms)
Known CVE in dependency ✓ Full — Gate 3 OOB trust (OSV, GHSA, Scorecard)
Runtime exfiltration — MCP server BCC'ing outbound email, library beaconing after startup ✗ Out of scope — this framework validates at install time only Falco, Tetragon, eBPF-based runtime monitoring
Deferred activation — payload triggered by condition after install ✗ Out of scope Runtime monitoring + behavioral analysis in production
Semantic impersonation — secure-requests impersonating requests (low string similarity) ✗ Not detected — Gate 0 requires string similarity; semantic matching not implemented Manual allowlist review; socket.dev / package reputation scoring
Gate 5 sandbox runner — active

Gate 5 is fully operational. The sandbox runner executes real package installs via strace on Linux CI and via gVisor for strongest isolation. All 34 behavioral patterns (18 Miasma + 16 IronWorm) are active. Install gVisor for production use — see the setup guide linked below.

Gate 5 setup guide (gVisor + strace) →
Further reading.
Incident analysis
Miasma compromises 32 Red Hat npm packages
devops.com — the Shai-Hulud clone attack on RedHatInsights that prompted Gate 2.5.
Incident analysis
TanStack npm supply chain attack — 170 packages
Security Boulevard — the same OIDC trusted publishing attack pattern, different target.
Incident analysis
Bitwarden CLI compromise — Checkmarx campaign
Demonstrates this is a systematic, repeatable attack playbook across multiple targets.
Tool — Gate 3
OpenSSF Scorecard
Automated security hygiene scoring for open source projects. Used in out-of-band trust aggregation.
Tool — Gate 3
OSV — Open Source Vulnerabilities
Cross-ecosystem CVE database. Used to verify patch versions appear in "fixed" lists.
Standard — Gate 2
Sigstore / cosign
Keyless signing via OIDC. The framework verifies both the signature and the sourceRepositoryURI.
Framework
SLSA — Supply chain Levels for Software Artifacts
The provenance attestation standard used in Gate 2 publisher repo verification.
Tool — Gate 3
deps.dev (Google)
Dependency graph, version velocity, and known advisory data — independent of package repos.
Tool — Gate 5
gVisor container sandbox
Kernel-level isolation for install script execution. No network access; behavioral event logging.
Docs — Gate 2
npm provenance attestations
How npm packages embed SLSA provenance. The sourceRepositoryURI field is what the framework verifies.
Docs — Gate 2
PyPI Trusted Publishers
PyPI's OIDC trusted publishing mechanism — the same vector exploited in Miasma-class attacks.
Tool — complementary
Socket.dev
Real-time supply chain security analysis. Can be integrated as an additional signal in Gate 3.
ENDOFFILE