mcpField
S
supply-chain-attack-response

supply-chain-attack-response

github.com/bagelhole安全1.2k308 次安装23 周前更新
代码仓库

关于 supply-chain-attack-response

面向开发与安全团队的供应链攻击检测和响应指南,涵盖依赖审计、事件处置及构建与分发加固。提供多种生态系统的命令示例,以及锁文件、容器和 CI/CD 的检查方法。

主要功能

  1. 01审计依赖并检测可疑行为
  2. 02验证包、容器签名与构建来源
  3. 03隔离受损依赖并检查入侵迹象
  4. 04检查锁文件并固定依赖版本
  5. 05加固 CI/CD 权限与运行器
  6. 06实施 SLSA 来源证明

适用场景

  1. 01响应已确认遭入侵的依赖项
  2. 02审计新引入的第三方包
  3. 03排查依赖更新后的 CI/CD 异常
  4. 04为发布物生成并验证来源证明

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/bagelhole/devops-security-agent-skills --skill supply-chain-attack-response

安装后在 Claude Code 中输入/supply-chain-attack-response确认已加载。

详细介绍

软件供应链攻击响应

软件供应链攻击的目标是开发者默认信任的依赖项、构建系统和分发渠道。当 PyPI、npm 或 crates.io 上的软件包遭到入侵时,所有下游使用者都会受到恶意载荷的影响。本技能提供检测技术、紧急响应手册和加固策略,帮助全面保护软件供应链。


1. 何时使用此技能

在以下任一情况适用时调用此技能:

  • 你使用的依赖项被标记为已遭入侵(例如 OSV.dev、GitHub Advisory Database 上的安全公告,或供应商披露)。
  • 你发现依赖项存在可疑行为:意外的网络调用、在其作用范围之外写入文件系统,或新增了安装后脚本。
  • 你正在进行定期的供应链安全审计。
  • 依赖项更新后,CI/CD 流水线出现异常。
  • 你正在引入新的第三方依赖项,并希望验证其来源。
  • 你需要响应诸如仿冒拼写软件包或注册表账户被接管等事件。
  • 你正在实施 SLSA 合规,或需要生成构建来源证明。

2. 检测

2.1 npm 审计
# Full audit of installed packages
npm audit

# JSON output for programmatic processing
npm audit --json | jq '.vulnerabilities | to_entries[] | select(.value.severity == "critical")'

# Fix automatically where possible
npm audit fix

# Check for known malicious packages via Socket.dev CLI
npx socket scan --package-lock package-lock.json
2.2 pip 审计
# Install pip-audit (maintained by Google/OSSF)
pip install pip-audit

# Audit current environment against OSV.dev
pip-audit

# Audit a requirements file directly
pip-audit -r requirements.txt --output json

# Check for typosquatting with bandersnatch or custom script
pip-audit --strict --desc on
2.3 Cargo 审计
# Install cargo-audit
cargo install cargo-audit

# Run audit against RustSec Advisory Database
cargo audit

# JSON output for CI integration
cargo audit --json

# Check for yanked crates
cargo audit --deny yanked
2.4 Sigstore / Cosign 验证
# Verify a container image signature with 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

# Verify an artifact with sigstore-python
pip install sigstore
python -m sigstore verify identity \
  --cert-identity "[email protected]" \
  --cert-oidc-issuer "https://accounts.google.com" \
  artifact.tar.gz
2.5 SLSA 来源证明检查
# Install slsa-verifier
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

3. 紧急响应手册

确认某个依赖项遭到入侵后,按顺序执行以下步骤。

步骤 1:遏制——固定版本并冻结
# Pin the last known-good version immediately in package.json
npm install <package>@<safe-version> --save-exact

# For pip, pin with hash verification
pip download <package>==<safe-version> --require-hashes -d ./vendor/

# For cargo, pin in Cargo.toml
# Replace: some_crate = "^1.2" with:
# some_crate = "=1.2.3"
cargo update -p some_crate --precise 1.2.3
步骤 2:审计影响范围
# Determine which versions you pulled and when
# npm
npm ls <compromised-package>
cat package-lock.json | jq '.packages | to_entries[] | select(.key | contains("<compromised-package>"))'

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

# Check git history for when the dependency version changed
git log --all -p -- package-lock.json | grep -A2 -B2 "<compromised-package>"
步骤 3:扫描入侵指标
# Search for known IOCs from the advisory
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'

# For Python packages, inspect setup.py and __init__.py
find ~/.local/lib/python*/site-packages/<compromised-package>/ -name "*.py" \
  | xargs grep -l "subprocess\|os.system\|exec(\|eval("
步骤 4:通知相关方
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
步骤 5:替换或分叉
# 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>
# Publish to your private registry or vendor directly

# For npm, point to your fork via package.json
# "dependencies": { "<package>": "git+https://github.com/yourorg/<package>.git#v1.2.3" }

4. 锁文件审计

锁文件是你的第一道防线。锁文件遭篡改或内容不一致,说明出现了问题。

4.1 验证锁文件完整性
# npm: ensure lockfile matches package.json (fails CI if out of sync)
npm ci

# Yarn: check lockfile integrity
yarn install --frozen-lockfile

# pip: generate a hash-locked requirements file
pip-compile --generate-hashes requirements.in -o requirements.txt

# Verify no unexpected changes in lockfile during PR
git diff --name-only origin/main...HEAD | grep -E "(package-lock|yarn.lock|Cargo.lock|requirements.txt)"
4.2 检测仿冒拼写
# Use the socket CLI to check for typosquatting risk
npx socket scan --package-lock package-lock.json

# Python: check package names against popular packages
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
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})')
"
4.3 在 CI 中比较锁文件差异
# .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

5. 固定和验证软件包

5.1 pip 哈希检查
# requirements.txt with hashes (generated by pip-compile --generate-hashes)
requests==2.31.0 \
    --hash=sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003eb \
    --hash=sha256:942c5a758f98d790eaed1a29cb6eefc7f0edf3fcb0fce8afe0f44546e1
# Install with mandatory hash verification
pip install --require-hashes -r requirements.txt

# Generate hashes for existing requirements
pip-compile --generate-hashes requirements.in
5.2 npm 软件包完整性
# npm automatically verifies integrity hashes in package-lock.json
# Ensure your lockfile contains integrity fields:
cat package-lock.json | jq '.packages | to_entries[] | select(.value.integrity == null) | .key'

# Enable strict engine and audit checks in .npmrc
cat >> .npmrc << 'EOF'
engine-strict=true
audit=true
audit-level=high
EOF
5.3 用于 Rust 的 cargo-vet
# Install cargo-vet
cargo install cargo-vet

# Initialize in your project
cargo vet init

# Certify a crate after review
cargo vet certify serde 1.0.193

# Import audit results from trusted organizations
cargo vet trust --all mozilla
cargo vet trust --all google

# Run verification in CI
cargo vet check

6. 容器镜像验证

6.1 使用 Cosign 签名和验证
# Sign an image (keyless via Sigstore/Fulcio in CI)
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

# 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 .
6.2 Kyverno 策略——要求镜像已签名
# 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
# Apply the policy
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
# Expected: admission webhook denies the request

7. CI/CD 流水线加固

7.1 按 SHA 固定 GitHub Actions
# BAD: mutable tag, can be hijacked
- uses: actions/checkout@v4

# GOOD: pinned to exact commit SHA
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
# Use pin-github-action to automate pinning
npm install -g pin-github-action
pin-github-action .github/workflows/*.yml
7.2 隔离运行器
# 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
7.3 使用 OIDC 进行云身份验证(不使用长期密钥)
# GitHub Actions OIDC with AWS -- no static credentials stored
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
7.4 限制工作流权限
# At the top of every workflow, use least-privilege permissions
permissions:
  contents: read
  packages: read

# Never grant write permissions globally; scope them per job
jobs:
  publish:
    permissions:
      contents: read
      packages: write

8. 实施 SLSA 框架

8.1 SLSA 级别概览
级别要求
SLSA 1记录构建流程并生成来源证明
SLSA 2由托管构建服务生成来源证明,并进行身份验证
SLSA 3加固构建平台,确保来源证明不可伪造
8.2 SLSA 级别 1——生成来源证明
# .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
8.3 SLSA 级别 2-3——使用 SLSA GitHub Generator
  provenance:
    needs: build
    permissions:
      actions: read
      id-token: write
      contents: write
    uses: slsa-framework/slsa-github-generator/.github/workflows/[email protected]
    with:
      base64-subjects: |
        ${{ needs.build.outputs.digest }} my-binary
      upload-assets: true
8.4 验证 SLSA 来源证明
# Download the provenance and binary from the release
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

9. 依赖项防火墙

9.1 配置带允许列表的 Artifactory 远程仓库
# 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
9.2 Nexus Repository 防火墙规则
# Enable Nexus Firewall audit on a proxy repository
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"
  }'
9.3 Verdaccio 私有 npm 注册表
# 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

10. 监控和告警

10.1 检测拉取请求中的新增依赖项
# .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
10.2 集成 OSV.dev
# Install osv-scanner
go install github.com/google/osv-scanner/cmd/osv-scanner@latest

# Scan a project directory (auto-detects lockfiles)
osv-scanner -r /path/to/project

# Scan a specific lockfile
osv-scanner --lockfile=package-lock.json

# Scan a Docker image
osv-scanner --docker myimage:latest

# Output as JSON for CI processing
osv-scanner -r /path/to/project --format json | jq '.results[].packages[].vulnerabilities[] | .id'
10.3 Dependabot 配置
# .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"
10.4 新增依赖项的自定义 Webhook 告警
#!/usr/bin/env bash
# alert-new-deps.sh -- run in CI on PRs to detect newly added dependencies
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

11. 事后响应

11.1 取证检查清单
[ ] 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
11.2 影响范围评估
#!/usr/bin/env bash
# blast-radius.sh -- assess how widely a compromised package spread
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 ==="

# 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
11.3 入侵后的密钥轮换
# Rotate all secrets that were accessible during the exposure window

# 1. Rotate cloud provider credentials
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
gh auth refresh

# 3. Rotate database credentials
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
npm token revoke <old-token>
npm token create --read-only

# 5. Invalidate all active sessions/JWTs
# Application-specific -- trigger a key rotation in your auth service
11.4 沟通模板
--- 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

快速参考

任务命令
审计 npmnpm audit --json
审计 pippip-audit -r requirements.txt
审计 cargocargo 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

评论

支持 Markdown