supply-chain-attack-response

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Supply Chain Attack Response

软件供应链攻击响应

Software supply chain attacks target the dependencies, build systems, and distribution channels that developers trust implicitly. When a package on PyPI, npm, or crates.io is compromised, every downstream consumer inherits the malicious payload. This skill provides detection techniques, emergency response playbooks, and hardening strategies to protect your software supply chain end to end.

软件供应链攻击针对开发者默认信任的依赖项、构建系统和分发渠道。当PyPI、npm或crates.io上的某个包被攻陷时,所有下游使用者都会继承恶意负载。本技能提供检测技术、应急响应手册和加固策略,端到端保护你的软件供应链。

1. When to Use This Skill

1. 何时使用本技能

Invoke this skill when any of the following apply:
  • A dependency you consume has been flagged as compromised (e.g., advisories on OSV.dev, GitHub Advisory Database, or vendor disclosure).
  • You observe suspicious behavior from a dependency: unexpected network calls, file system writes outside its scope, or new post-install scripts.
  • You are conducting a periodic supply chain security audit.
  • A CI/CD pipeline is behaving unexpectedly after a dependency update.
  • You are onboarding a new third-party dependency and want to verify its provenance.
  • You need to respond to an incident such as a typosquatted package or registry account takeover.
  • You are implementing SLSA compliance or need to generate build provenance.

出现以下任意情况时,调用本技能:
  • 你使用的某个依赖项被标记为已攻陷(例如OSV.dev、GitHub Advisory Database上的公告,或供应商披露)。
  • 你观察到依赖项的可疑行为:意外的网络调用、超出其范围的文件系统写入,或新增的安装后脚本。
  • 你正在进行定期供应链安全审计。
  • 更新依赖项后,CI/CD流水线出现异常行为。
  • 你正在引入新的第三方依赖项,需要验证其来源。
  • 你需要响应诸如仿冒包(typosquatted package)或注册表账户被接管等事件。
  • 你正在实施SLSA合规要求,或需要生成构建来源信息(build provenance)。

2. Detection

2. 检测

2.1 npm Audit

2.1 npm Audit

bash
undefined
bash
undefined

Full audit of installed packages

对已安装包进行全面审计

npm audit
npm audit

JSON output for programmatic processing

输出JSON格式结果用于程序化处理

npm audit --json | jq '.vulnerabilities | to_entries[] | select(.value.severity == "critical")'
npm audit --json | jq '.vulnerabilities | to_entries[] | select(.value.severity == "critical")'

Fix automatically where possible

自动修复可修复的问题

npm audit fix
npm audit fix

Check for known malicious packages via Socket.dev CLI

通过Socket.dev CLI检查已知恶意包

npx socket scan --package-lock package-lock.json
undefined
npx socket scan --package-lock package-lock.json
undefined

2.2 pip Audit

2.2 pip Audit

bash
undefined
bash
undefined

Install pip-audit (maintained by Google/OSSF)

安装pip-audit(由Google/OSSF维护)

pip install pip-audit
pip install pip-audit

Audit current environment against OSV.dev

对照OSV.dev审计当前环境

pip-audit
pip-audit

Audit a requirements file directly

直接审计requirements文件

pip-audit -r requirements.txt --output json
pip-audit -r requirements.txt --output json

Check for typosquatting with bandersnatch or custom script

使用bandersnatch或自定义脚本检查仿冒包

pip-audit --strict --desc on
undefined
pip-audit --strict --desc on
undefined

2.3 Cargo Audit

2.3 Cargo Audit

bash
undefined
bash
undefined

Install cargo-audit

安装cargo-audit

cargo install cargo-audit
cargo install cargo-audit

Run audit against RustSec Advisory Database

对照RustSec Advisory Database运行审计

cargo audit
cargo audit

JSON output for CI integration

输出JSON格式结果用于CI集成

cargo audit --json
cargo audit --json

Check for yanked crates

检查已撤回的crates

cargo audit --deny yanked
undefined
cargo audit --deny yanked
undefined

2.4 Sigstore / Cosign Verification

2.4 Sigstore / Cosign 验证

bash
undefined
bash
undefined

Verify a container image signature with cosign

使用cosign验证容器镜像签名

cosign verify
--certificate-identity "https://github.com/myorg/myrepo/.github/workflows/build.yml@refs/heads/main"
--certificate-oidc-issuer "https://token.actions.githubusercontent.com"
ghcr.io/myorg/myimage:latest
cosign verify
--certificate-identity "https://github.com/myorg/myrepo/.github/workflows/build.yml@refs/heads/main"
--certificate-oidc-issuer "https://token.actions.githubusercontent.com"
ghcr.io/myorg/myimage:latest

Verify an artifact with sigstore-python

使用sigstore-python验证工件

pip install sigstore python -m sigstore verify identity
--cert-identity "release@example.com"
--cert-oidc-issuer "https://accounts.google.com"
artifact.tar.gz
undefined
pip install sigstore python -m sigstore verify identity
--cert-identity "release@example.com"
--cert-oidc-issuer "https://accounts.google.com"
artifact.tar.gz
undefined

2.5 SLSA Provenance Checks

2.5 SLSA 来源信息检查

bash
undefined
bash
undefined

Install slsa-verifier

安装slsa-verifier

go install github.com/slsa-framework/slsa-verifier/v2/cli/slsa-verifier@latest
go install github.com/slsa-framework/slsa-verifier/v2/cli/slsa-verifier@latest

Verify provenance of a binary

验证二进制文件的来源信息

slsa-verifier verify-artifact my-binary
--provenance-path my-binary.intoto.jsonl
--source-uri github.com/myorg/myrepo
--source-tag v1.2.3

---
slsa-verifier verify-artifact my-binary
--provenance-path my-binary.intoto.jsonl
--source-uri github.com/myorg/myrepo
--source-tag v1.2.3

---

3. Emergency Response Playbook

3. 应急响应手册

When a dependency is confirmed compromised, execute these steps in order.
确认依赖项被攻陷后,按以下顺序执行步骤。

Step 1: Contain -- Pin and Freeze

步骤1:遏制 -- 固定版本并冻结

bash
undefined
bash
undefined

Pin the last known-good version immediately in package.json

立即在package.json中固定最后一个已知安全的版本

npm install <package>@<safe-version> --save-exact
npm install <package>@<safe-version> --save-exact

For pip, pin with hash verification

对于pip,使用哈希验证固定版本

pip download <package>==<safe-version> --require-hashes -d ./vendor/
pip download <package>==<safe-version> --require-hashes -d ./vendor/

For cargo, pin in Cargo.toml

对于cargo,在Cargo.toml中固定版本

Replace: some_crate = "^1.2" with:

将: some_crate = "^1.2" 替换为:

some_crate = "=1.2.3"

some_crate = "=1.2.3"

cargo update -p some_crate --precise 1.2.3
undefined
cargo update -p some_crate --precise 1.2.3
undefined

Step 2: Audit Exposure

步骤2:审计暴露范围

bash
undefined
bash
undefined

Determine which versions you pulled and when

确定你拉取的版本和时间

npm

npm

npm ls <compromised-package> cat package-lock.json | jq '.packages | to_entries[] | select(.key | contains("<compromised-package>"))'
npm ls <compromised-package> cat package-lock.json | jq '.packages | to_entries[] | select(.key | contains("<compromised-package>"))'

pip

pip

pip show <compromised-package> pip cache list <compromised-package>
pip show <compromised-package> pip cache list <compromised-package>

Check git history for when the dependency version changed

检查git历史记录,查看依赖项版本何时变更

git log --all -p -- package-lock.json | grep -A2 -B2 "<compromised-package>"
undefined
git log --all -p -- package-lock.json | grep -A2 -B2 "<compromised-package>"
undefined

Step 3: Scan for Indicators of Compromise

步骤3:扫描入侵指标(IOC)

bash
undefined
bash
undefined

Search for known IOCs from the advisory

搜索公告中提到的已知入侵指标

grep -r "suspicious-domain.com" ./node_modules/<compromised-package>/ grep -r "eval(atob" ./node_modules/<compromised-package>/
grep -r "suspicious-domain.com" ./node_modules/<compromised-package>/ grep -r "eval(atob" ./node_modules/<compromised-package>/

Check for unexpected post-install scripts

检查意外的安装后脚本

cat node_modules/<compromised-package>/package.json | jq '.scripts'
cat node_modules/<compromised-package>/package.json | jq '.scripts'

For Python packages, inspect setup.py and init.py

对于Python包,检查setup.py和__init__.py

find ~/.local/lib/python*/site-packages/<compromised-package>/ -name "*.py"
| xargs grep -l "subprocess|os.system|exec(|eval("
undefined
find ~/.local/lib/python*/site-packages/<compromised-package>/ -name "*.py"
| xargs grep -l "subprocess|os.system|exec(|eval("
undefined

Step 4: Notify Stakeholders

步骤4:通知相关人员

text
SUBJECT: [SECURITY INCIDENT] Compromised dependency: <package-name>

SEVERITY: Critical
IMPACT: <package-name> versions <affected-range> contain malicious code.
AFFECTED SYSTEMS: <list of repos/services consuming this dependency>
STATUS: Contained -- pinned to safe version <safe-version>

ACTIONS TAKEN:
1. Pinned all repositories to last known-good version
2. Initiated audit of all systems that pulled affected versions
3. Scanning for indicators of compromise

RECOMMENDED ACTIONS:
- Do NOT deploy any build that consumed affected versions
- Review CI/CD logs for the timeframe <start> to <end>
- Rotate any secrets that were accessible to the build environment
text
主题:[安全事件] 已攻陷依赖项: <package-name>

严重程度:Critical
影响范围:<package-name>版本<affected-range>包含恶意代码。
受影响系统:<使用该依赖项的仓库/服务列表>
状态:已遏制 -- 固定到安全版本<safe-version>

已采取行动:
1. 将所有仓库固定到最后一个已知安全的版本
2. 启动对所有拉取过受影响版本的系统的审计
3. 扫描入侵指标

建议行动:
- 不要部署任何使用过受影响版本的构建产物
- 审查<start>至<end>时间段内的CI/CD日志
- 轮换构建环境可访问的所有密钥

Step 5: Replace or Fork

步骤5:替换或复刻

bash
undefined
bash
undefined

If the package maintainer account was compromised, fork the last safe version

如果包维护者账户被攻陷,复刻最后一个安全版本

git clone https://github.com/original-author/<package>.git cd <package> git checkout v<safe-version>
git clone https://github.com/original-author/<package>.git cd <package> git checkout v<safe-version>

Publish to your private registry or vendor directly

发布到你的私有注册表或直接作为供应商包使用

For npm, point to your fork via package.json

对于npm,在package.json中指向你的复刻版本

"dependencies": { "<package>": "git+https://github.com/yourorg/<package>.git#v1.2.3" }

"dependencies": { "<package>": "git+https://github.com/yourorg/<package>.git#v1.2.3" }


---

---

4. Lockfile Auditing

4. 锁文件审计

Lockfiles are your first line of defense. Tampered or inconsistent lockfiles indicate something is wrong.
锁文件是你的第一道防线。被篡改或不一致的锁文件表明存在问题。

4.1 Verify Lockfile Integrity

4.1 验证锁文件完整性

bash
undefined
bash
undefined

npm: ensure lockfile matches package.json (fails CI if out of sync)

npm: 确保锁文件与package.json匹配(如果不同步,CI会失败)

npm ci
npm ci

Yarn: check lockfile integrity

Yarn: 检查锁文件完整性

yarn install --frozen-lockfile
yarn install --frozen-lockfile

pip: generate a hash-locked requirements file

pip: 生成带哈希锁定的requirements文件

pip-compile --generate-hashes requirements.in -o requirements.txt
pip-compile --generate-hashes requirements.in -o requirements.txt

Verify no unexpected changes in lockfile during PR

在PR中检查锁文件是否有意外变更

git diff --name-only origin/main...HEAD | grep -E "(package-lock|yarn.lock|Cargo.lock|requirements.txt)"
undefined
git diff --name-only origin/main...HEAD | grep -E "(package-lock|yarn.lock|Cargo.lock|requirements.txt)"
undefined

4.2 Detect Typosquatting

4.2 检测仿冒包(Typosquatting)

bash
undefined
bash
undefined

Use the socket CLI to check for typosquatting risk

使用socket CLI检查仿冒风险

npx socket scan --package-lock package-lock.json
npx socket scan --package-lock package-lock.json

Python: check package names against popular packages

Python: 对照热门包检查包名

pip-audit -r requirements.txt 2>&1 | grep -i "typosquat"
pip-audit -r requirements.txt 2>&1 | grep -i "typosquat"

Custom check: compare package names to known popular packages

自定义检查:将包名与已知热门包对比

Flag anything with edit distance <= 2 from a top-1000 package

标记与前1000个热门包编辑距离<=2的包

python3 -c " import json, sys from difflib import SequenceMatcher with open('package-lock.json') as f: lock = json.load(f) popular = ['express','lodash','react','axios','chalk','debug','commander','inquirer'] for pkg in lock.get('packages', {}): name = pkg.split('node_modules/')[-1] if 'node_modules/' in pkg else pkg for p in popular: ratio = SequenceMatcher(None, name, p).ratio() if 0.75 < ratio < 1.0 and name != p: print(f'WARNING: {name} is suspiciously similar to {p} (similarity: {ratio:.2f})') "
undefined
python3 -c " import json, sys from difflib import SequenceMatcher with open('package-lock.json') as f: lock = json.load(f) popular = ['express','lodash','react','axios','chalk','debug','commander','inquirer'] for pkg in lock.get('packages', {}): name = pkg.split('node_modules/')[-1] if 'node_modules/' in pkg else pkg for p in popular: ratio = SequenceMatcher(None, name, p).ratio() if 0.75 < ratio < 1.0 and name != p: print(f'WARNING: {name} is suspiciously similar to {p} (similarity: {ratio:.2f})') "
undefined

4.3 Lockfile Diff in CI

4.3 CI中的锁文件差异检查

yaml
undefined
yaml
undefined

.github/workflows/lockfile-check.yml

.github/workflows/lockfile-check.yml

name: Lockfile Audit on: pull_request jobs: audit: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Check for lockfile changes run: | LOCKFILES="package-lock.json yarn.lock pnpm-lock.yaml Cargo.lock requirements.txt poetry.lock" for f in $LOCKFILES; do if git diff --name-only origin/main...HEAD | grep -q "$f"; then echo "::warning::Lockfile $f was modified -- review dependency changes carefully" git diff origin/main...HEAD -- "$f" | head -100 fi done - name: Run npm audit if: hashFiles('package-lock.json') != '' run: npm audit --audit-level=high

---
name: Lockfile Audit on: pull_request jobs: audit: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Check for lockfile changes run: | LOCKFILES="package-lock.json yarn.lock pnpm-lock.yaml Cargo.lock requirements.txt poetry.lock" for f in $LOCKFILES; do if git diff --name-only origin/main...HEAD | grep -q "$f"; then echo "::warning::Lockfile $f was modified -- review dependency changes carefully" git diff origin/main...HEAD -- "$f" | head -100 fi done - name: Run npm audit if: hashFiles('package-lock.json') != '' run: npm audit --audit-level=high

---

5. Package Pinning and Verification

5. 包固定与验证

5.1 pip Hash Checking

5.1 pip哈希检查

text
undefined
text
undefined

requirements.txt with hashes (generated by pip-compile --generate-hashes)

带哈希的requirements.txt(由pip-compile --generate-hashes生成)

requests==2.31.0
--hash=sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003eb
--hash=sha256:942c5a758f98d790eaed1a29cb6eefc7f0edf3fcb0fce8afe0f44546e1

```bash
requests==2.31.0
--hash=sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003eb
--hash=sha256:942c5a758f98d790eaed1a29cb6eefc7f0edf3fcb0fce8afe0f44546e1

```bash

Install with mandatory hash verification

强制使用哈希验证进行安装

pip install --require-hashes -r requirements.txt
pip install --require-hashes -r requirements.txt

Generate hashes for existing requirements

为现有依赖项生成哈希

pip-compile --generate-hashes requirements.in
undefined
pip-compile --generate-hashes requirements.in
undefined

5.2 npm Package Integrity

5.2 npm包完整性

bash
undefined
bash
undefined

npm automatically verifies integrity hashes in package-lock.json

npm会自动验证package-lock.json中的完整性哈希

Ensure your lockfile contains integrity fields:

确保你的锁文件包含integrity字段:

cat package-lock.json | jq '.packages | to_entries[] | select(.value.integrity == null) | .key'
cat package-lock.json | jq '.packages | to_entries[] | select(.value.integrity == null) | .key'

Enable strict engine and audit checks in .npmrc

在.npmrc中启用严格引擎和审计检查

cat >> .npmrc << 'EOF' engine-strict=true audit=true audit-level=high EOF
undefined
cat >> .npmrc << 'EOF' engine-strict=true audit=true audit-level=high EOF
undefined

5.3 cargo-vet for Rust

5.3 Rust的cargo-vet

bash
undefined
bash
undefined

Install cargo-vet

安装cargo-vet

cargo install cargo-vet
cargo install cargo-vet

Initialize in your project

在项目中初始化

cargo vet init
cargo vet init

Certify a crate after review

审核后认证一个crate

cargo vet certify serde 1.0.193
cargo vet certify serde 1.0.193

Import audit results from trusted organizations

导入可信组织的审计结果

cargo vet trust --all mozilla cargo vet trust --all google
cargo vet trust --all mozilla cargo vet trust --all google

Run verification in CI

在CI中运行验证

cargo vet check

---
cargo vet check

---

6. Container Image Verification

6. 容器镜像验证

6.1 Cosign Sign and Verify

6.1 Cosign签名与验证

bash
undefined
bash
undefined

Sign an image (keyless via Sigstore/Fulcio in CI)

签名镜像(在CI中通过Sigstore/Fulcio实现无密钥签名)

cosign sign ghcr.io/myorg/myimage@sha256:abc123...
cosign sign ghcr.io/myorg/myimage@sha256:abc123...

Verify with expected identity

使用预期身份验证

cosign verify
--certificate-identity-regexp "https://github.com/myorg/.*"
--certificate-oidc-issuer "https://token.actions.githubusercontent.com"
ghcr.io/myorg/myimage:latest
cosign verify
--certificate-identity-regexp "https://github.com/myorg/.*"
--certificate-oidc-issuer "https://token.actions.githubusercontent.com"
ghcr.io/myorg/myimage:latest

Verify and extract attestations

验证并提取声明

cosign verify-attestation
--type slsaprovenance
--certificate-identity-regexp "https://github.com/myorg/.*"
--certificate-oidc-issuer "https://token.actions.githubusercontent.com"
ghcr.io/myorg/myimage:latest | jq '.payload' | base64 -d | jq .
undefined
cosign verify-attestation
--type slsaprovenance
--certificate-identity-regexp "https://github.com/myorg/.*"
--certificate-oidc-issuer "https://token.actions.githubusercontent.com"
ghcr.io/myorg/myimage:latest | jq '.payload' | base64 -d | jq .
undefined

6.2 Kyverno Policy -- Require Signed Images

6.2 Kyverno策略 -- 要求签名镜像

yaml
undefined
yaml
undefined

kyverno-require-signed-images.yaml

kyverno-require-signed-images.yaml

apiVersion: kyverno.io/v1 kind: ClusterPolicy metadata: name: require-signed-images spec: validationFailureAction: Enforce background: false rules: - name: verify-image-signature match: any: - resources: kinds: - Pod verifyImages: - imageReferences: - "ghcr.io/myorg/" attestors: - entries: - keyless: subject: "https://github.com/myorg/" issuer: "https://token.actions.githubusercontent.com" rekor: url: https://rekor.sigstore.dev

```bash
apiVersion: kyverno.io/v1 kind: ClusterPolicy metadata: name: require-signed-images spec: validationFailureAction: Enforce background: false rules: - name: verify-image-signature match: any: - resources: kinds: - Pod verifyImages: - imageReferences: - "ghcr.io/myorg/" attestors: - entries: - keyless: subject: "https://github.com/myorg/" issuer: "https://token.actions.githubusercontent.com" rekor: url: https://rekor.sigstore.dev

```bash

Apply the policy

应用策略

kubectl apply -f kyverno-require-signed-images.yaml
kubectl apply -f kyverno-require-signed-images.yaml

Test: this unsigned image should be rejected

测试:这个未签名的镜像应该被拒绝

kubectl run test --image=ghcr.io/myorg/unsigned-image:latest
kubectl run test --image=ghcr.io/myorg/unsigned-image:latest

Expected: admission webhook denies the request

预期结果:准入webhook拒绝请求


---

---

7. CI/CD Pipeline Hardening

7. CI/CD流水线加固

7.1 Pin GitHub Actions by SHA

7.1 通过SHA固定GitHub Actions

yaml
undefined
yaml
undefined

BAD: mutable tag, can be hijacked

不推荐:可变标签,可能被劫持

  • uses: actions/checkout@v4
  • uses: actions/checkout@v4

GOOD: pinned to exact commit SHA

推荐:固定到确切的提交SHA

  • uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1

```bash
  • uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1

```bash

Use pin-github-action to automate pinning

使用pin-github-action自动完成固定

npm install -g pin-github-action pin-github-action .github/workflows/*.yml
undefined
npm install -g pin-github-action pin-github-action .github/workflows/*.yml
undefined

7.2 Isolated Runners

7.2 隔离运行器

yaml
undefined
yaml
undefined

Use ephemeral self-hosted runners that are destroyed after each job

使用临时自托管运行器,作业完成后销毁

jobs: build: runs-on: self-hosted container: image: ghcr.io/myorg/build-env:latest@sha256:abc123... steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 - name: Build in isolated container run: | # No access to host filesystem or network beyond what's needed make build
undefined
jobs: build: runs-on: self-hosted container: image: ghcr.io/myorg/build-env:latest@sha256:abc123... steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 - name: Build in isolated container run: | # 仅访问所需的主机文件系统或网络 make build
undefined

7.3 OIDC for Cloud Authentication (No Long-Lived Secrets)

7.3 用于云认证的OIDC(无长期密钥)

yaml
undefined
yaml
undefined

GitHub Actions OIDC with AWS -- no static credentials stored

GitHub Actions与AWS的OIDC集成 -- 不存储静态凭证

jobs: deploy: runs-on: ubuntu-latest permissions: id-token: write contents: read steps: - uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4 with: role-to-assume: arn:aws:iam::123456789012:role/github-actions-deploy aws-region: us-east-1 - run: aws s3 cp build/ s3://my-bucket/ --recursive
undefined
jobs: deploy: runs-on: ubuntu-latest permissions: id-token: write contents: read steps: - uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4 with: role-to-assume: arn:aws:iam::123456789012:role/github-actions-deploy aws-region: us-east-1 - run: aws s3 cp build/ s3://my-bucket/ --recursive
undefined

7.4 Restrict Workflow Permissions

7.4 限制工作流权限

yaml
undefined
yaml
undefined

At the top of every workflow, use least-privilege permissions

在每个工作流顶部,使用最小权限原则

permissions: contents: read packages: read
permissions: contents: read packages: read

Never grant write permissions globally; scope them per job

不要全局授予写入权限;按作业分配权限

jobs: publish: permissions: contents: read packages: write

---
jobs: publish: permissions: contents: read packages: write

---

8. SLSA Framework Implementation

8. SLSA框架实施

8.1 SLSA Levels Overview

8.1 SLSA级别概述

LevelRequirement
SLSA 1Build process is documented and generates provenance
SLSA 2Provenance is generated by a hosted build service and is authenticated
SLSA 3Build platform is hardened, provenance is non-falsifiable
级别要求
SLSA 1记录构建流程并生成来源信息
SLSA 2由托管构建服务生成来源信息并进行身份验证
SLSA 3构建平台已加固,来源信息不可篡改

8.2 SLSA Level 1 -- Generate Provenance

8.2 SLSA级别1 -- 生成来源信息

yaml
undefined
yaml
undefined

.github/workflows/slsa-build.yml

.github/workflows/slsa-build.yml

name: SLSA Build on: push: tags: ["v*"] jobs: build: runs-on: ubuntu-latest outputs: digest: ${{ steps.hash.outputs.digest }} steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 - name: Build artifact run: | make build cp dist/my-binary ./my-binary - name: Generate digest id: hash run: | DIGEST=$(sha256sum my-binary | cut -d ' ' -f1) echo "digest=$DIGEST" >> "$GITHUB_OUTPUT" - uses: actions/upload-artifact@v4 with: name: my-binary path: my-binary
undefined
name: SLSA Build on: push: tags: ["v*"] jobs: build: runs-on: ubuntu-latest outputs: digest: ${{ steps.hash.outputs.digest }} steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 - name: Build artifact run: | make build cp dist/my-binary ./my-binary - name: Generate digest id: hash run: | DIGEST=$(sha256sum my-binary | cut -d ' ' -f1) echo "digest=$DIGEST" >> "$GITHUB_OUTPUT" - uses: actions/upload-artifact@v4 with: name: my-binary path: my-binary
undefined

8.3 SLSA Level 2-3 -- Use the SLSA GitHub Generator

8.3 SLSA级别2-3 -- 使用SLSA GitHub生成器

yaml
  provenance:
    needs: build
    permissions:
      actions: read
      id-token: write
      contents: write
    uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.0.0
    with:
      base64-subjects: |
        ${{ needs.build.outputs.digest }} my-binary
      upload-assets: true
yaml
  provenance:
    needs: build
    permissions:
      actions: read
      id-token: write
      contents: write
    uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.0.0
    with:
      base64-subjects: |
        ${{ needs.build.outputs.digest }} my-binary
      upload-assets: true

8.4 Verify SLSA Provenance

8.4 验证SLSA来源信息

bash
undefined
bash
undefined

Download the provenance and binary from the release

从版本发布中下载来源信息和二进制文件

gh release download v1.2.3 -p "my-binary" -p "my-binary.intoto.jsonl"
gh release download v1.2.3 -p "my-binary" -p "my-binary.intoto.jsonl"

Verify

验证

slsa-verifier verify-artifact my-binary
--provenance-path my-binary.intoto.jsonl
--source-uri github.com/myorg/myrepo
--source-tag v1.2.3
echo $? # 0 = verified successfully

---
slsa-verifier verify-artifact my-binary
--provenance-path my-binary.intoto.jsonl
--source-uri github.com/myorg/myrepo
--source-tag v1.2.3
echo $? # 0 = 验证成功

---

9. Dependency Firewall

9. 依赖防火墙

9.1 Artifactory Remote Repository with Allow List

9.1 带允许列表的Artifactory远程仓库

yaml
undefined
yaml
undefined

artifactory-remote-npm.yaml

artifactory-remote-npm.yaml

apiVersion: v1 kind: RemoteRepository metadata: name: npm-remote spec: packageType: npm url: https://registry.npmjs.org includesPattern: | express/** lodash/** react/** @types/** excludesPattern: | malicious typosquat xrayIndex: true blockMismatchingMimeTypes: true enableTokenAuthentication: true
undefined
apiVersion: v1 kind: RemoteRepository metadata: name: npm-remote spec: packageType: npm url: https://registry.npmjs.org includesPattern: | express/** lodash/** react/** @types/** excludesPattern: | malicious typosquat xrayIndex: true blockMismatchingMimeTypes: true enableTokenAuthentication: true
undefined

9.2 Nexus Repository Firewall Rules

9.2 Nexus仓库防火墙规则

bash
undefined
bash
undefined

Enable Nexus Firewall audit on a proxy repository

在代理仓库上启用Nexus Firewall审计

curl -u admin:$NEXUS_PASSWORD -X PUT
"https://nexus.internal/service/rest/v1/security/content-selectors"
-H "Content-Type: application/json"
-d '{ "name": "block-suspicious-pypi", "description": "Block packages with no maintainer history", "expression": "format == "pypi" and coordinate.age < 7" }'
undefined
curl -u admin:$NEXUS_PASSWORD -X PUT
"https://nexus.internal/service/rest/v1/security/content-selectors"
-H "Content-Type: application/json"
-d '{ "name": "block-suspicious-pypi", "description": "Block packages with no maintainer history", "expression": "format == "pypi" and coordinate.age < 7" }'
undefined

9.3 Verdaccio Private npm Registry

9.3 Verdaccio私有npm注册表

yaml
undefined
yaml
undefined

verdaccio config.yaml

verdaccio config.yaml

storage: /verdaccio/storage uplinks: npmjs: url: https://registry.npmjs.org/ cache: true maxage: 30m packages: '@myorg/*': access: $authenticated publish: $authenticated proxy: [] # never proxy internal packages '**': access: $authenticated publish: $deny # block publishing public package names proxy: npmjs

Block known malicious packages

'event-stream': access: $deny publish: $deny

---
storage: /verdaccio/storage uplinks: npmjs: url: https://registry.npmjs.org/ cache: true maxage: 30m packages: '@myorg/*': access: $authenticated publish: $authenticated proxy: [] # 绝不代理内部包 '**': access: $authenticated publish: $deny # 阻止发布公共包名 proxy: npmjs

阻止已知恶意包

'event-stream': access: $deny publish: $deny

---

10. Monitoring and Alerting

10. 监控与告警

10.1 Detect New Dependencies in Pull Requests

10.1 检测Pull Request中的新依赖项

yaml
undefined
yaml
undefined

.github/workflows/dependency-review.yml

.github/workflows/dependency-review.yml

name: Dependency Review on: pull_request permissions: contents: read pull-requests: write jobs: review: runs-on: ubuntu-latest steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 - uses: actions/dependency-review-action@4901385134134e04cec5fbe5ddfe3b2c5bd5d976 # v4 with: fail-on-severity: high deny-licenses: GPL-3.0, AGPL-3.0 comment-summary-in-pr: always warn-only: false
undefined
name: Dependency Review on: pull_request permissions: contents: read pull-requests: write jobs: review: runs-on: ubuntu-latest steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 - uses: actions/dependency-review-action@4901385134134e04cec5fbe5ddfe3b2c5bd5d976 # v4 with: fail-on-severity: high deny-licenses: GPL-3.0, AGPL-3.0 comment-summary-in-pr: always warn-only: false
undefined

10.2 OSV.dev Integration

10.2 OSV.dev集成

bash
undefined
bash
undefined

Install osv-scanner

安装osv-scanner

go install github.com/google/osv-scanner/cmd/osv-scanner@latest
go install github.com/google/osv-scanner/cmd/osv-scanner@latest

Scan a project directory (auto-detects lockfiles)

扫描项目目录(自动检测锁文件)

osv-scanner -r /path/to/project
osv-scanner -r /path/to/project

Scan a specific lockfile

扫描特定锁文件

osv-scanner --lockfile=package-lock.json
osv-scanner --lockfile=package-lock.json

Scan a Docker image

扫描Docker镜像

osv-scanner --docker myimage:latest
osv-scanner --docker myimage:latest

Output as JSON for CI processing

输出JSON格式结果用于CI处理

osv-scanner -r /path/to/project --format json | jq '.results[].packages[].vulnerabilities[] | .id'
undefined
osv-scanner -r /path/to/project --format json | jq '.results[].packages[].vulnerabilities[] | .id'
undefined

10.3 Dependabot Configuration

10.3 Dependabot配置

yaml
undefined
yaml
undefined

.github/dependabot.yml

.github/dependabot.yml

version: 2 updates:
  • package-ecosystem: "npm" directory: "/" schedule: interval: "daily" open-pull-requests-limit: 10 reviewers:
    • "security-team" labels:
    • "dependencies"
    • "security"

    Group minor/patch updates but keep major separate for review

    groups: production-dependencies: dependency-type: "production" update-types: ["minor", "patch"] dev-dependencies: dependency-type: "development" update-types: ["minor", "patch"]
  • package-ecosystem: "pip" directory: "/" schedule: interval: "daily"
  • package-ecosystem: "github-actions" directory: "/" schedule: interval: "weekly"
undefined
version: 2 updates:
  • package-ecosystem: "npm" directory: "/" schedule: interval: "daily" open-pull-requests-limit: 10 reviewers:
    • "security-team" labels:
    • "dependencies"
    • "security"

    合并次要/补丁更新,但将主要更新单独保留以便审查

    groups: production-dependencies: dependency-type: "production" update-types: ["minor", "patch"] dev-dependencies: dependency-type: "development" update-types: ["minor", "patch"]
  • package-ecosystem: "pip" directory: "/" schedule: interval: "daily"
  • package-ecosystem: "github-actions" directory: "/" schedule: interval: "weekly"
undefined

10.4 Custom Webhook Alert for New Dependencies

10.4 新依赖项的自定义Webhook告警

bash
#!/usr/bin/env bash
bash
#!/usr/bin/env bash

alert-new-deps.sh -- run in CI on PRs to detect newly added dependencies

alert-new-deps.sh -- 在CI的PR中运行,检测新增的依赖项

set -euo pipefail
BASE_BRANCH="${1:-origin/main}" LOCKFILE="package-lock.json"
NEW_DEPS=$(diff <(git show "$BASE_BRANCH:$LOCKFILE" 2>/dev/null | jq -r '.packages | keys[]' | sort)
<(jq -r '.packages | keys[]' "$LOCKFILE" | sort)
| grep "^>" | sed 's/^> //' || true)
if [ -n "$NEW_DEPS" ]; then echo "New dependencies detected:" echo "$NEW_DEPS"

Send to Slack

curl -s -X POST "$SLACK_WEBHOOK_URL"
-H "Content-Type: application/json"
-d "{ "text": "New dependencies added in PR #${PR_NUMBER}:\n```${NEW_DEPS}```", "channel": "#security-alerts" }" fi

---
set -euo pipefail
BASE_BRANCH="${1:-origin/main}" LOCKFILE="package-lock.json"
NEW_DEPS=$(diff <(git show "$BASE_BRANCH:$LOCKFILE" 2>/dev/null | jq -r '.packages | keys[]' | sort)
<(jq -r '.packages | keys[]' "$LOCKFILE" | sort)
| grep "^>" | sed 's/^> //' || true)
if [ -n "$NEW_DEPS" ]; then echo "New dependencies detected:" echo "$NEW_DEPS"

发送到Slack

curl -s -X POST "$SLACK_WEBHOOK_URL"
-H "Content-Type: application/json"
-d "{ "text": "New dependencies added in PR #${PR_NUMBER}:\n```${NEW_DEPS}```", "channel": "#security-alerts" }" fi

---

11. Post-Incident Response

11. 事件后响应

11.1 Forensics Checklist

11.1 取证清单

text
[ ] Identify the exact compromised package version(s)
[ ] Determine the time window of exposure (first install to detection)
[ ] List all repositories and services that consumed the package
[ ] Check CI/CD build logs for the exposure window
[ ] Inspect runtime logs for outbound connections to unknown hosts
[ ] Review process execution logs for unexpected child processes
[ ] Check for modifications to other files in node_modules/site-packages
[ ] Verify no additional packages were installed as transitive deps
[ ] Dump and analyze DNS query logs for the exposure period
[ ] Check for new cron jobs, systemd services, or scheduled tasks
[ ] Audit all secrets/tokens that were accessible to the build environment
text
[ ] 确定确切的已攻陷包版本
[ ] 确定暴露时间窗口(从首次安装到检测到攻击)
[ ] 列出所有使用该包的仓库和服务
[ ] 检查暴露时间窗口内的CI/CD构建日志
[ ] 检查运行时日志中是否有指向未知主机的出站连接
[ ] 审查进程执行日志中是否有意外的子进程
[ ] 检查node_modules/site-packages中其他文件是否被修改
[ ] 验证是否没有额外的包作为传递依赖被安装
[ ] 导出并分析暴露期间的DNS查询日志
[ ] 检查是否有新的cron任务、systemd服务或计划任务
[ ] 审计构建环境可访问的所有密钥/令牌

11.2 Blast Radius Assessment

11.2 影响范围评估

bash
#!/usr/bin/env bash
bash
#!/usr/bin/env bash

blast-radius.sh -- assess how widely a compromised package spread

blast-radius.sh -- 评估已攻陷包的传播范围

set -euo pipefail
COMPROMISED_PKG="$1" COMPROMISED_VERSIONS="$2" # comma-separated, e.g., "1.2.3,1.2.4"
echo "=== Blast Radius Assessment for $COMPROMISED_PKG ==="
set -euo pipefail
COMPROMISED_PKG="$1" COMPROMISED_VERSIONS="$2" # 逗号分隔,例如 "1.2.3,1.2.4"
echo "=== Blast Radius Assessment for $COMPROMISED_PKG ==="

Check all repos in the org

检查组织内的所有仓库

for repo in $(gh repo list myorg --json name -q '.[].name'); do echo "--- Checking $repo ---"

Check package-lock.json

LOCK=$(gh api "repos/myorg/$repo/contents/package-lock.json"
--jq '.content' 2>/dev/null | base64 -d 2>/dev/null || true)
if echo "$LOCK" | grep -q ""$COMPROMISED_PKG""; then VERSION=$(echo "$LOCK" | jq -r ".packages["node_modules/$COMPROMISED_PKG"].version // empty") if echo "$COMPROMISED_VERSIONS" | grep -q "$VERSION"; then echo "AFFECTED: $repo uses $COMPROMISED_PKG@$VERSION" fi fi done
undefined
for repo in $(gh repo list myorg --json name -q '.[].name'); do echo "--- Checking $repo ---"

检查package-lock.json

LOCK=$(gh api "repos/myorg/$repo/contents/package-lock.json"
--jq '.content' 2>/dev/null | base64 -d 2>/dev/null || true)
if echo "$LOCK" | grep -q ""$COMPROMISED_PKG""; then VERSION=$(echo "$LOCK" | jq -r ".packages["node_modules/$COMPROMISED_PKG"].version // empty") if echo "$COMPROMISED_VERSIONS" | grep -q "$VERSION"; then echo "AFFECTED: $repo uses $COMPROMISED_PKG@$VERSION" fi fi done
undefined

11.3 Secret Rotation After Compromise

11.3 攻陷后的密钥轮换

bash
undefined
bash
undefined

Rotate all secrets that were accessible during the exposure window

轮换暴露时间窗口内可访问的所有密钥

1. Rotate cloud provider credentials

1. 轮换云提供商凭证

aws iam create-access-key --user-name ci-deploy aws iam delete-access-key --user-name ci-deploy --access-key-id OLD_KEY_ID
aws iam create-access-key --user-name ci-deploy aws iam delete-access-key --user-name ci-deploy --access-key-id OLD_KEY_ID

2. Rotate GitHub tokens

2. 轮换GitHub令牌

gh auth refresh
gh auth refresh

3. Rotate database credentials

3. 轮换数据库凭证

kubectl create secret generic db-credentials
--from-literal=password="$(openssl rand -base64 32)"
--dry-run=client -o yaml | kubectl apply -f -
kubectl create secret generic db-credentials
--from-literal=password="$(openssl rand -base64 32)"
--dry-run=client -o yaml | kubectl apply -f -

4. Rotate npm/PyPI publish tokens

4. 轮换npm/PyPI发布令牌

npm token revoke <old-token> npm token create --read-only
npm token revoke <old-token> npm token create --read-only

5. Invalidate all active sessions/JWTs

5. 使所有活动会话/JWT失效

Application-specific -- trigger a key rotation in your auth service

特定于应用程序 -- 在你的认证服务中触发密钥轮换

undefined
undefined

11.4 Communication Templates

11.4 沟通模板

text
--- INTERNAL INCIDENT REPORT ---

Incident ID: SC-YYYY-NNN
Date Detected: YYYY-MM-DD HH:MM UTC
Package: <name>@<version>
Registry: npm / PyPI / crates.io
Advisory: <link to CVE or advisory>

Timeline:
  - YYYY-MM-DD HH:MM: Compromised version published to registry
  - YYYY-MM-DD HH:MM: First installation in our environment (from CI logs)
  - YYYY-MM-DD HH:MM: Compromise detected via <audit tool / advisory / manual review>
  - YYYY-MM-DD HH:MM: Pinned to safe version across all repos
  - YYYY-MM-DD HH:MM: Completed IOC scan -- no evidence of exploitation
  - YYYY-MM-DD HH:MM: All exposed secrets rotated

Blast Radius:
  - Repositories affected: N
  - Production deployments with compromised version: N
  - Secrets potentially exposed: <list>

Root Cause:
  <Maintainer account takeover / malicious maintainer / build system compromise>

Remediation:
  1. Pinned to safe version
  2. Rotated all potentially exposed secrets
  3. Deployed clean builds to production
  4. Added package to monitoring watch list

Preventive Measures:
  1. Enabled hash-pinning for all dependencies
  2. Added dependency-review-action to all repos
  3. Configured Artifactory proxy with allowlist
  4. Scheduled quarterly supply chain audits

text
--- 内部事件报告 ---

事件ID: SC-YYYY-NNN
检测日期: YYYY-MM-DD HH:MM UTC
包: <name>@<version>
注册表: npm / PyPI / crates.io
公告链接: <CVE或公告链接>

时间线:
  - YYYY-MM-DD HH:MM: 已攻陷版本发布到注册表
  - YYYY-MM-DD HH:MM: 我们环境中首次安装(来自CI日志)
  - YYYY-MM-DD HH:MM: 通过<审计工具/公告/人工审查>检测到攻陷
  - YYYY-MM-DD HH:MM: 在所有仓库中固定到安全版本
  - YYYY-MM-DD HH:MM: 完成IOC扫描 -- 无被利用迹象
  - YYYY-MM-DD HH:MM: 所有暴露的密钥已轮换

影响范围:
  - 受影响仓库数量: N
  - 使用已攻陷版本的生产部署数量: N
  - 可能暴露的密钥: <列表>

根本原因:
  <维护者账户被接管/恶意维护者/构建系统被攻陷>

修复措施:
  1. 固定到安全版本
  2. 轮换所有可能暴露的密钥
  3. 向生产环境部署干净的构建产物
  4. 将该包添加到监控观察列表

预防措施:
  1. 为所有依赖项启用哈希固定
  2. 为所有仓库添加dependency-review-action
  3. 配置带允许列表的Artifactory代理
  4. 安排季度供应链审计

Quick Reference

快速参考

TaskCommand
Audit npm
npm audit --json
Audit pip
pip-audit -r requirements.txt
Audit cargo
cargo audit
Scan with OSV
osv-scanner -r .
Verify cosign signature
cosign verify --certificate-identity-regexp ... <image>
Verify SLSA provenance
slsa-verifier verify-artifact ...
Pin GitHub Actions
pin-github-action .github/workflows/*.yml
Check lockfile drift
npm ci
(fails if lockfile is out of sync)
Generate pip hashes
pip-compile --generate-hashes requirements.in
Cargo vet check
cargo vet check
任务命令
审计npm
npm audit --json
审计pip
pip-audit -r requirements.txt
审计cargo
cargo audit
使用OSV扫描
osv-scanner -r .
验证cosign签名
cosign verify --certificate-identity-regexp ... <image>
验证SLSA来源信息
slsa-verifier verify-artifact ...
固定GitHub Actions
pin-github-action .github/workflows/*.yml
检查锁文件漂移
npm ci
(如果锁文件不同步则失败)
生成pip哈希
pip-compile --generate-hashes requirements.in
Cargo vet检查
cargo vet check