What Happened
TeamPCP compromised the CI/CD pipeline for Trivy, a widely-used vulnerability scanner, by stealing publishing credentials. They used these credentials to push malicious versions of both the Trivy package and its GitHub Actions workflow to PyPI. The attack succeeded because the pipeline relied on long-lived credentials for authentication, similar to outdated deployment practices.
The compromised packages went live, and Trivy's GitHub Action was already integrated into thousands of repositories. The malicious code executed in those CI/CD environments, accessing secrets, source code, and deployment credentials.
This wasn't an isolated event. Last year, attackers compromised tj-actions/changed-files and exposed secrets across more than 23,000 repositories. The pattern is clear: your CI/CD system is now a primary attack vector.
Timeline
Initial compromise: Attackers obtained static PyPI publishing credentials for the Trivy project. The exact method is unclear, but the credentials provided persistent access to the package repository.
Malicious package publication: TeamPCP published compromised versions of Trivy to PyPI, containing code designed to execute in CI/CD environments.
GitHub Actions compromise: The attackers published malicious versions of Trivy's GitHub Actions workflow. This was critical because GitHub Actions run automatically in thousands of repositories when developers push code or create pull requests.
Widespread execution: The malicious Actions executed across repositories that had integrated Trivy for security scanning, accessing GITHUB_TOKEN and any configured secrets.
Detection and response: The compromise was eventually detected, but not before the malicious packages were downloaded and executed across numerous environments.
Which Controls Failed or Were Missing
Static credential management: The Trivy project used long-lived PyPI tokens for package publishing. Once stolen, these credentials remained valid indefinitely. There was no rotation policy, no detection of anomalous use, and no way to limit their scope beyond "can publish packages."
Insufficient access controls: The compromised credentials had broad publishing rights, allowing attackers to push new versions, modify existing packages, and update metadata.
Lack of identity federation: The pipeline didn't use workload identity or federated credentials tied to specific repositories or branches. Any system with the token could publish packages.
Missing runtime integrity checks: Downstream consumers had no verification that the packages they were pulling matched expected cryptographic signatures or came from trusted build environments.
No secrets scanning in CI/CD: The pipelines didn't detect when malicious code attempted to exfiltrate secrets or make unauthorized API calls during the build process.
What the Relevant Standards Require
NIST 800-53 Rev 5 addresses this directly in IA-5(2): "The organization employs automated mechanisms to support the management of information system authenticators." Static tokens in CI/CD violate this control. The standard requires automated rotation, strength requirements, and protection mechanisms. Your PyPI tokens, npm tokens, and Docker Hub credentials should rotate automatically and be scoped to the minimum necessary permissions.
ISO/IEC 27001:2022 covers this in A.9.4.3 (password management systems) and A.9.2.1 (user registration and de-registration). Publishing credentials are privileged access. They require the same controls you apply to production database access: time-bound, audited, and revocable.
PCI DSS v4.0.1 Requirement 8.3.2 states: "Strong cryptographic authentication is implemented for all access to the cardholder data environment." If your CI/CD pipeline can deploy code that touches payment data, this applies. Long-lived tokens don't meet the "strong authentication" bar. You need short-lived credentials tied to specific identities.
SOC 2 Type II CC6.1 (logical and physical access controls) requires that access is "restricted to authorized users and programs." A stolen token that works from anywhere fails this control. Your auditor should be asking: How do you ensure that only authorized build jobs can publish packages? How do you detect when credentials are used from unexpected locations or contexts?
The gap isn't that these standards don't cover CI/CD—it's that most organizations haven't mapped their CI/CD architecture to these requirements. You're running the equivalent of production infrastructure with development-grade access controls.
Lessons and Action Items for Your Team
Replace static tokens with OIDC federation. GitHub Actions, GitLab CI, and CircleCI all support OIDC. PyPI, npm, and major cloud providers accept OIDC tokens. Configure your workflows to request short-lived tokens scoped to specific repositories and branches. The token lives for minutes, not months. Example: GitHub Actions can authenticate to AWS using aws-actions/configure-aws-credentials with OIDC—no AWS access keys stored in secrets.
Implement package signing and verification. Sign every package you publish with Sigstore or equivalent. Configure your internal package repositories to reject unsigned packages. This won't prevent compromise, but it will make it detectable. When Trivy's signature suddenly changes, you know something is wrong.
Audit your existing CI/CD secrets. List every GITHUB_TOKEN, API key, and deployment credential in your CI/CD platform. For each one, document: What can it access? When does it expire? Who can modify workflows that use it? If you find tokens that are more than 90 days old or have broad permissions, those are your highest-risk items.
Enable secrets scanning in your CI/CD logs. Tools like GitHub's secret scanning, GitLab's secret detection, or TruffleHog can scan your build logs and artifacts for accidentally exposed credentials. Run these checks before artifacts leave your build environment.
Restrict workflow modification permissions. In GitHub, use CODEOWNERS to require review for changes to .github/workflows/. In GitLab, protect your .gitlab-ci.yml file. An attacker who can modify your CI/CD configuration can do anything—they don't need to steal credentials if they can just change the workflow to exfiltrate them.
Monitor package download patterns. If your package—like Telnyx with its 790,000 monthly downloads—suddenly shows unusual download spikes or geographic distribution changes, investigate. Set up alerts in your package registry for version publishes you didn't initiate.
Scope repository tokens to minimum necessary permissions. Don't give your CI/CD workflows repo:write if they only need repo:read. Don't give them packages:write if they only need packages:read. GitHub's fine-grained personal access tokens and repository-scoped tokens make this possible now.
Your CI/CD pipeline has the same privileges as your most sensitive production systems. It can deploy code, access secrets, and modify infrastructure. Treat it accordingly. The controls you'd never skip for production—MFA, short-lived credentials, audit logging, least privilege—apply here too.



