| name | pentest-supply-chain |
| description | Pentest de supply chain, CI/CD e infraestrutura — SCA/CVE, typosquatting, malicious postinstall,
GitHub Actions (pinning por SHA, permissões, script injection, pwn-request), Docker (imagem base,
rootless, secrets em layer), lockfile poisoning, SBOM, gestão de secrets e GitOps.
TRIGGERS: supply chain, sca, cve, github actions security, docker security, sbom, dependabot, codeql, typosquat, postinstall malicious, lockfile, pin dependencies, renovate, secret management
|
🔗 pentest-supply-chain — Auditoria Ofensiva de Supply Chain & CI/CD
Supply chain é o vetor de crescimento mais rápido (ex: SolarWinds, event-stream, xz-utils). Foco: código que roda antes do seu código.
Required Reading
package.json (raiz + todas as libs)
pnpm-lock.yaml / package-lock.json
.github/workflows/*.yml
.github/dependabot.yml, renovate.json
Dockerfile*, docker-compose*.yml
.npmrc, .yarnrc.yml, .pnpmfile.cjs
.env*, .envrc
.gitignore
1. Dependências (SCA)
CVE scanning
pnpm audit --audit-level=moderate --json > .pentest/audit.json
pnpm dlx osv-scanner --lockfile pnpm-lock.yaml --format json --output .pentest/osv.json
pnpm dlx retire --outputformat json --outputpath .pentest/retire.json
Typosquatting / packages maliciosos
pnpm dlx npq install --dry-run || true
pnpm dlx socket-security < package.json
Red flags manuais:
- Pacote muito novo (< 30 dias) com nome parecido com lib conhecida (
lodaash, react-natve)
- Autor diferente do mainline (
@types/xxxx oficial é @types)
postinstall/preinstall scripts em libs que não deveriam executar nada
rg -l "\"postinstall\"|\"preinstall\"" node_modules/**/package.json 2>/dev/null | head -30
Lockfile integrity
cat .npmrc 2>/dev/null
rg -n "_authToken|_auth" .npmrc .yarnrc .yarnrc.yml 2>/dev/null
Version pinning
rg -n '"[\^~][0-9]' package.json libs/*/*/package.json apps/*/package.json
2. GitHub Actions
Pinning por SHA
rg -n "uses: .+@v[0-9]" .github/workflows/
rg -n "uses: .+@(main|master|develop)" .github/workflows/
Permissions
rg -n "permissions:" .github/workflows/ -A 8
Script Injection (pwn-request, issue/PR titles)
rg -n "\$\{\{\s*github\.event\." .github/workflows/
Padrão perigoso:
- run: echo "${{ github.event.pull_request.title }}"
Fix:
env:
TITLE: ${{ github.event.pull_request.title }}
run: echo "$TITLE"
pull_request_target
rg -n "pull_request_target" .github/workflows/ -A 20
Secrets
CodeQL / Security scanning
ls .github/workflows/ | rg -i "codeql|security|scorecard"
3. Docker / Containers
rg -n "FROM " Dockerfile* apps/*/Dockerfile*
rg -n "USER " Dockerfile* apps/*/Dockerfile*
rg -n "ADD " Dockerfile*
Imagem base
User / Filesystem
Secrets
cat .dockerignore 2>/dev/null
rg -n "^ENV\s+.*(SECRET|KEY|TOKEN|PASSWORD)" Dockerfile*
rg -n "COPY \.env" Dockerfile*
Scan
docker scout cves <image> || true
pnpm dlx @anchore/syft <image> -o spdx-json > .pentest/sbom.json || true
pnpm dlx @anchore/grype <image> -o json > .pentest/grype.json || true
trivy image --severity HIGH,CRITICAL <image> || true
4. SBOM (Software Bill of Materials)
pnpm dlx @cyclonedx/cyclonedx-npm --output-file .pentest/sbom.cdx.json
5. Secret Management
Gitleaks / detect-secrets
gitleaks detect --source . --no-git --report-format json --report-path .pentest/gitleaks.json
pnpm dlx @secretlint/secretlint --format json '**/*' > .pentest/secretlint.json
Regex patterns adicionais
rg -n "AKIA[0-9A-Z]{16}" .
rg -n "ASIA[0-9A-Z]{16}" .
rg -n "ghp_[A-Za-z0-9]{36}" .
rg -n "github_pat_[A-Za-z0-9_]{82}" .
rg -n "xox[baprs]-[A-Za-z0-9-]+" .
rg -n "-----BEGIN (RSA |EC |OPENSSH )?PRIVATE KEY-----" .
rg -n "sk_live_[A-Za-z0-9]{24,}" .
rg -n "SG\.[A-Za-z0-9_-]{22}\.[A-Za-z0-9_-]{43}" .
rg -n "AIza[0-9A-Za-z_-]{35}" .
Runtime secret manager
Se encontrar secret vivo
🚨 Sempre instruir no relatório:
- Revogar no provider imediatamente (AWS: IAM; GitHub: settings/tokens; Stripe: dashboard)
- Rotacionar com novo valor
- Auditar logs do provider buscando uso não-autorizado
- Remover do histórico git com
git filter-repo (não git filter-branch)
- Force-push com aviso à equipe; considerar repositório comprometido
6. Git History
git log --all --source --full-history -p --diff-filter=D -- '**/.env*' 2>/dev/null | head -100
git log --all -S'BEGIN RSA PRIVATE KEY' --oneline 2>/dev/null
7. Branch Protection / GitOps
8. Outros
.env local em node_modules publicado
Libs internas publicadas em registry privado devem ter files: no package.json limitando o que vai no tarball.
rg -n "\"files\":" libs/*/*/package.json apps/*/package.json
Prebuild scripts
rg -n "\"(pre|post)?(install|build|test|publish)\":" package.json
Scripts que rodam durante pnpm install devem ser auditados — são vetor de RCE.
Output Snippet
### 🔗 Supply Chain & CI/CD — N findings
| ID | Sev | CWE | File:Line | Issue |
|----|---|---|---|---|
| S-001 | 🔴 Critical | CWE-798 | .github/workflows/deploy.yml:42 | Secret `AWS_ACCESS_KEY_ID` em log (`echo ${{ secrets.X }}`) |
| S-002 | 🟠 High | CWE-829 | .github/workflows/ci.yml:14 | Action `foo/bar@main` sem SHA pinning |
| S-003 | 🟠 High | CWE-937 | package.json | lodash 4.17.19 — CVE-2021-23337 (command injection) |
| S-004 | 🟡 Medium | CWE-693 | Dockerfile | Runtime como root (falta `USER`) |
Anti-patterns a SEMPRE reportar
uses: x/y@main|@master em workflow
pull_request_target + checkout de branch do PR
${{ github.event.*.title }} / .body direto em run:
ENV SECRET= / COPY .env em Dockerfile
- Rodar container como
root em prod
:latest em imagem base ou Compose
.npmrc com token commitado
postinstall em dep direta nova/desconhecida
- Ausência de
dependabot.yml ou renovate.json
- Branch
main sem proteção