Check your GitHub Actions workflows right now. Count how many third-party actions you’re pulling in. Each one ran inside your build job last time with full access to every secret in $GITHUB_ENV and every value you passed as ${{ secrets.* }}.
That’s not a hypothetical threat. In March 2026, attackers hijacked 75 Trivy GitHub Action tags overnight. They swapped legitimate steps with malicious ones that did one thing: read every secret in the CI environment and ship it out. Thousands of pipelines ran the compromised action before anyone noticed. Teams woke up to AWS keys, Docker Hub tokens, and Stripe credentials in attacker hands.
No zero-day. No exploit. Just shell commands reading environment variables you put there.
What Actually Happened
Trivy is a popular open-source vulnerability scanner. Teams use it in CI to check container images and filesystems for known CVEs. The attack didn’t require a zero-day in Trivy’s code. The attackers compromised the repository itself, pushed malicious commits, and re-tagged releases so pipelines pinned to version tags like v0.18.3 would silently pull the poisoned version.
The injected steps were simple. Read environment variables, scan for anything resembling a token or key, ship the data out. No exploits. No obfuscation tricks. Plain shell commands reading secrets already sitting in the environment.
That’s the part worth sitting with.
Why It Worked So Well
GitHub Actions passes secrets into your workflow as environment variables. When you write ${{ secrets.MY_API_KEY }} in a workflow file, that value lands in the process environment for every step in the job, including third-party actions you pull in.
A hijacked action has the same access to your environment as your own build scripts. There’s no sandboxing between steps. The malicious Trivy action didn’t need to escalate privileges or break out of anything. It just read the environment and printed it to an outbound HTTP call.
Most teams have AWS keys, Docker Hub tokens, NPM publish tokens, and deployment credentials sitting in GitHub Secrets. Long-lived ones. Keys created once, rotated rarely, and scoped broadly because it was easier at setup time.
That’s the exact setup this attack exploited.
The Real Problem: Durable Secrets
The attack was bad. But the breach wasn’t just “Trivy got compromised.” The breach was that a one-time compromise of a single GitHub Action gave attackers credentials with no expiry.
Long-lived API keys have a compounding failure mode. Once stolen, they keep working. Days later. Weeks later. Sometimes months before anyone rotates them. The attacker doesn’t need to maintain access to your pipeline. They already have the keys. They can use them at their leisure, from anywhere, without triggering anything in your GitHub audit log.
Short-lived credentials flip this dynamic. If a token is valid for 15 minutes, an attacker who steals it at minute 10 of your build has 5 minutes of access, maybe less if the job finishes first. There’s nothing to stockpile.
This isn’t a new idea. It’s just one most CI pipelines skip because long-lived keys are simpler to configure once and forget.
Stop putting permanent keys in CI environments
API Stronghold issues scoped, short-lived proxy tokens at job start. Even if a hijacked action reads them, they expire before an attacker can use them.
No credit card required
The Fix: Inject Credentials at Job Time
The pattern that actually addresses this is short-lived, scoped token injection. Instead of storing a permanent key in GitHub Secrets and passing it as an env var, your pipeline requests a credential at the start of each job. The credential is scoped to exactly what that job needs and expires when the job completes.
Here’s what that looks like in practice.
OIDC token exchange is the cleanest option for AWS, GCP, and Azure. GitHub Actions can generate an OIDC token for a job, which your cloud provider exchanges for a temporary set of credentials. No static key ever touches your environment. AWS calls this assuming a role via web identity; GCP calls it Workload Identity Federation.
permissions:
id-token: write
contents: read
steps:
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/GitHubDeployRole
aws-region: us-east-1
role-duration-seconds: 900
That role-duration-seconds: 900 is 15 minutes. The credentials AWS returns are valid for 15 minutes, then gone. A hijacked action that reads AWS_ACCESS_KEY_ID from the environment gets something that expires before the attacker can do anything useful with it.
Vault injection at build time is the approach for secrets that don’t have cloud-native OIDC support. HashiCorp Vault, AWS Secrets Manager, and similar tools can issue dynamic credentials: database passwords, API tokens, and certificates that are generated on request and revoked automatically. Your pipeline authenticates to the vault using a short-lived bootstrap token, often itself obtained via OIDC, pulls the secret, uses it, and the dynamic credential is gone.
Least-privilege scopes are what make short-lived tokens actually safe, not just shorter-lived. A 15-minute AWS credential that can do anything in your account is still dangerous. A 15-minute credential that can only push to one S3 bucket is nearly useless to an attacker. Narrow the scope first, then shorten the TTL. Both matter.
Where API Stronghold Fits
OIDC works well when your cloud provider supports it natively. It helps less when your pipeline needs to call third-party APIs: payment processors, analytics platforms, internal tooling, anything that hands out traditional API keys.
That’s where a credential proxy changes the model. Instead of putting your real Stripe API key in GitHub Secrets, your pipeline authenticates to API Stronghold at the start of each job and gets a scoped proxy token. That token can only call the specific endpoints the job needs, expires when the job ends, and every request is logged. Even if a hijacked action reads the token and tries to use it, the blast radius is contained: scoped, time-bounded, and auditable.
The Trivy attack would have been much less interesting to the attackers if they’d pulled a 10-minute proxy token instead of a permanent API key.
Getting Started
If you want to reduce your exposure today, the order of operations looks like this:
- Audit what’s in your GitHub Secrets. Flag anything with no expiry or no scope constraints.
- For AWS, GCP, and Azure: set up OIDC and eliminate static cloud credentials from your secrets entirely.
- For third-party APIs: route calls through a credential proxy with short TTLs and narrow scopes.
- Pin your GitHub Actions to commit SHAs, not tags. Tags can be repointed, as the Trivy attack demonstrated. A SHA cannot.
- Review what each third-party action in your workflows actually needs. If an action doesn’t need database access, make sure it can’t get it.
Supply chain attacks on CI pipelines are real, practical, and not going away. The teams who limit the value of what an attacker can steal are the ones who treat an incident as an inconvenience rather than a crisis.
Ready to try short-lived, scoped credentials for your CI/CD pipelines? API Stronghold handles credential proxying and token injection so your pipelines don’t need permanent keys in environment variables. Start your free trial and see what a cleaner secrets model looks like.