The breach that started with
a trusted tool.

On March 30, 2026, Cisco confirmed what security researchers had been warning about for weeks: attackers had used credentials harvested during the Trivy supply chain compromise to breach Cisco's internal development environment. More than 300 GitHub repositories were cloned. Source code for Cisco's AI Assistant and AI Defense products was stolen, along with code belonging to corporate customers at banks, business process outsourcing firms, and US government agencies.

The Cisco breach was not the result of a vulnerability in Cisco's own code. It was not a phishing attack. It was not an insider threat. It happened because Cisco trusted Trivy — a widely used open-source security scanner — and Trivy had already been turned into a weapon.

To understand how a company of Cisco's size and security sophistication ended up with its source code on an extortion site, you need to understand the full attack chain. It did not start on March 30. It started on March 1.

Full attack timeline — TeamPCP campaign CVE-2026-33634 · CVSS 9.4
Mar 1
TeamPCP

Initial credential theft via misconfigured GitHub Action

Attackers exploited a misconfigured pull_request_target workflow in Trivy's GitHub repository — present since October 2025 — to steal a Personal Access Token with write permissions. Aqua Security discovered the breach and rotated credentials, but the rotation was incomplete.

Mar 19
TeamPCP

Trivy v0.69.4 backdoored — 75 of 76 version tags poisoned

Using credentials that survived the incomplete rotation, TeamPCP force-pushed malicious code to 75 of 76 version tags in trivy-action and all seven tags in setup-trivy. The Trivy binary itself was backdoored across GitHub releases, Docker Hub, GitHub Container Registry, and Amazon ECR. CVE-2026-33634 assigned, CVSS 9.4.

Mar 19
Every affected pipeline

Credential harvesting begins at scale across thousands of CI/CD pipelines

The malicious payload read directly from GitHub Actions Runner memory at /proc/<pid>/mem — bypassing log-masking entirely. AWS keys, GCP credentials, Azure tokens, Kubernetes secrets, Docker registry credentials, SSH keys, database passwords, and TLS private keys were harvested, AES-256-CBC encrypted, and exfiltrated. Any organization running Trivy that day lost their pipeline credentials.

Mar 23
TeamPCP

Checkmarx KICS and AST GitHub Actions compromised

Using credentials from the Trivy phase, TeamPCP moved to Checkmarx's KICS and AST repositories. The same credential harvesting payload was deployed. Malicious VSCode extensions were published simultaneously.

Mar 24
TeamPCP

LiteLLM PyPI compromised — 95 million monthly downloads affected

LiteLLM, an open-source AI gateway with approximately 95 million monthly PyPI downloads, was compromised through poisoned package versions 1.82.7 and 1.82.8. Every developer environment that auto-updated received the credential harvesting payload.

Mar 27
TeamPCP

Telnyx Python SDK compromised

The cascade continued with the Telnyx communications library on PyPI. The same infostealer payload. More credentials harvested from more developer environments.

Mar 30
TeamPCP using stolen Cisco credentials

Cisco development environment breached — 300+ repos cloned

Attackers used credentials harvested from Cisco's Trivy-enabled CI/CD pipeline to access Cisco's internal development environment. 300+ GitHub repositories were cloned including AI Assistant, AI Defense, and unreleased AI products. Source code belonging to banks, BPOs, and US government agencies was also stolen. Multiple AWS access keys were exfiltrated and used for unauthorized activities.

Mar 31
ShinyHunters

Extortion campaign launched — $13M demanded

ShinyHunters published an extortion post with an April 3 deadline claiming theft of 3+ million Salesforce records alongside the GitHub repositories and AWS assets. Cisco reportedly declined to pay. The group warned they would publish all data and contact every employee and client.

How the malware actually
read the credentials.

Most developers assume that GitHub Actions masks sensitive values in logs. If you add a secret to your repository's secrets store and use it in a workflow, GitHub replaces its value with asterisks in the log output. The assumption is that the secret is therefore safe even if logs are exposed.

The Trivy payload bypassed log-masking entirely.

Instead of reading from environment variables or workflow outputs, the malicious GitHub Action read directly from the GitHub Actions Runner process memory — specifically from /proc/<pid>/mem on Linux runners. This file provides direct access to a process's virtual memory space. The runner process holds all environment variables, including secrets, in memory. The masking in logs does not affect what lives in the process's memory space.

The attack mechanism

The runner process holds your secrets in memory whether or not they appear masked in logs. Any code with access to the runner's process memory — including a compromised GitHub Action — can read them directly. Log masking is a display feature. It is not a security boundary.

Once collected, the harvested credentials were encrypted with AES-256-CBC and wrapped with RSA-4096, making network-layer inspection ineffective. The payload then exfiltrated the encrypted bundle to TeamPCP's C2 infrastructure. The encryption was not to protect the data in transit — it was to prevent security tools from detecting the stolen credential patterns in network traffic.

What was stolen from every affected pipeline

Cloud credentials

  • AWS access keys and secret keys
  • GCP service account credentials
  • Azure service principal credentials
  • AWS STS session tokens

Infrastructure secrets

  • SSH private keys
  • Kubernetes service account tokens
  • Docker registry credentials
  • TLS private keys and certificates

Developer credentials

  • GitHub Personal Access Tokens
  • npm authentication tokens
  • PyPI API tokens
  • Database connection strings

Application secrets

  • API keys for third-party services
  • Webhook secrets
  • Signing keys
  • OAuth client secrets

For Cisco specifically, the stolen AWS keys were confirmed to have been used for unauthorized activities across a small number of Cisco AWS accounts. The breach impacted dozens of developer and lab workstations. The company's CSIRT, Unified Intelligence Center, and Emergency Operations Center teams were all engaged in the response.

Cisco expects continued fallout. The same Trivy credentials that opened Cisco's environment were also used to compromise LiteLLM and Checkmarx. Each wave of the campaign used credentials stolen in the previous phase to reach further into the ecosystem.

Why Cisco's secrets manager
did not help.

This is the question worth sitting with. Cisco is one of the world's largest cybersecurity companies. They make security products. They have a dedicated CSIRT team. They were not storing secrets in plaintext files or pushing them to public GitHub repositories. They had secrets management. It did not help.

Here is why. Every secrets manager — HashiCorp Vault, AWS Secrets Manager, GitHub Secrets, Doppler, Infisical — follows the same model. Encrypt the secret at rest. Retrieve it via API when the pipeline needs it. The secret becomes an environment variable or an in-memory string in the running process.

Step three is the blind spot. The moment the secret is retrieved and placed into the runner's environment, it exists as a plaintext string in process memory. That is exactly where the Trivy malware looked. Not in the vault. Not in the encrypted storage. In the memory of the running process that had just retrieved the secret to use it.

How every CI/CD pipeline works — and why it failed VULNERABLE
# Standard GitHub Actions workflow — Cisco's setup looked similar
# Step 1: Vault or GitHub Secrets retrieves the key (encrypted)
# Step 2: Key is decrypted and injected as environment variable
# Step 3: Runner process holds it in memory

env:
  AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
  AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
  OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}

steps:
  - name: Run security scan
    uses: aquasecurity/[email protected]  # ← reads /proc/<pid>/mem
    # Secrets are now in runner memory. Malicious action reads them.
    # Log masking is irrelevant. Memory access bypasses it entirely.
    # Stolen. Encrypted. Exfiltrated. Done.
"The Cisco breach did not happen because of a flaw in Cisco's own security practices in isolation. It happened because a widely trusted open-source security tool was turned into a weapon."

This is not unique to Cisco. Any organization that ran Trivy between March 19 and March 24, 2026, with secrets present in the runner environment is a potential victim of this credential harvest. The tooling that was supposed to protect the pipeline became the attack vector into the pipeline.

What would have stopped
the credential theft.

Clear distinction before this section: VaultProof does not prevent supply chain attacks. The Trivy compromise would still have happened. TeamPCP would still have injected malware into the GitHub Action. The malicious code would still have run in every affected pipeline.

What VaultProof addresses is the consequence — the credential theft.

If the secrets in Cisco's CI/CD pipeline had been protected using split-key architecture and a proxy approach, the Trivy payload would have found nothing to steal. Here is why.

VaultProof splits API keys and credentials into cryptographic shares. Individual shares are mathematically useless — knowing any subset below the threshold reveals zero information about the complete key. The shares are distributed across separate storage. Your application, your CI/CD runner, your developer workstation — none of them hold the full credential. Only the VaultProof proxy does, and only for milliseconds.

With VaultProof — what the malicious Trivy action would have found PROTECTED
# Pipeline environment with VaultProof
# The runner holds shares, not complete credentials

env:
  VAULTPROOF_PROJECT_ID: vp-proj-abc123  # non-secret identifier
  # No AWS keys. No API keys. No secrets.
  # Shares are distributed. No single location holds the complete key.

steps:
  - name: Run security scan
    uses: aquasecurity/[email protected]  # runs malicious payload
    # Payload reads /proc/<pid>/mem
    # Finds: project ID (not a secret) and cryptographic shares
    # Shares alone are useless without the other share
    # Credential theft consequence: eliminated

  - name: Make API calls via VaultProof proxy
    # SDK sends request to proxy
    # Proxy collects shares, reconstructs key for ~200ms
    # API call made. Key zeroed from proxy memory.
    # The complete credential never existed in the runner.
The principle

You cannot steal what does not exist. The Trivy malware read from runner memory and found complete credentials — because those credentials had been retrieved from the vault and placed into memory as plaintext strings. If the complete credential never existed in the runner's memory space, the attack harvests nothing of value.

What about the AWS keys specifically?

The AWS keys stolen from Cisco's pipelines were the credentials that gave attackers access to Cisco's AWS accounts — enabling the unauthorized activity confirmed in the breach disclosure. AWS credentials in CI/CD pipelines are among the highest-value targets in any supply chain attack.

AWS supports OIDC authentication for GitHub Actions — a mechanism that issues short-lived tokens rather than static keys. If Cisco had used OIDC for AWS authentication, the stolen credentials would have been ephemeral tokens with limited validity windows, significantly reducing the blast radius.

But OIDC only works for cloud provider credentials. AWS, GCP, and Azure support it. Third-party API keys — OpenAI, Anthropic, Stripe, database connection strings, webhook secrets — do not support OIDC. Those static keys still need to exist somewhere in the environment. That is the gap split-key architecture addresses.

If you ran Trivy between
March 19 and 24, do this.

The safe versions of Trivy are v0.69.3 or earlier, [email protected], and [email protected]. If your pipelines ran any other version during the window, treat all pipeline credentials as compromised.

Immediate triage checklist:

If you ran affected Trivy versions

Rotate all AWS access keys immediately. Rotate all GitHub Personal Access Tokens. Rotate all Kubernetes service account tokens. Rotate all Docker registry credentials. Check your GitHub organization for any repositories named tpcp-docs — this indicates successful exfiltration. Block scan.aquasecurtiy[.]org and 45.148.10.212 at network level. Check developer machines for sysmon.py or pgmon systemd services. Treat all secrets that were present in affected pipeline environment variables as fully compromised.

Going forward: pin all GitHub Actions to full commit SHA hashes, not version tags. Version tags like @v0.28.0 are mutable pointers. The commit hash they point to can be silently changed by anyone with repository access. A SHA hash cannot be moved. This single change would have prevented the tag-poisoning phase of this attack from affecting pinned pipelines.

The broader lesson from the Cisco breach is not that organizations need better secret rotation policies, though they do. It is that the entire paradigm of secrets-as-environment-variables in CI/CD pipelines is structurally vulnerable to the supply chain attack class. As long as the complete credential must exist as a plaintext string somewhere in the runner's memory, a sufficiently motivated attacker with code execution in that environment will find it.