Skip to content

Security Incident Report: aquasecurity/trivy-action Supply Chain Compromise (2026-03-19) #1

@CybotTM

Description

@CybotTM

Security Incident Report: aquasecurity/trivy-action Supply Chain Compromise

Date of incident: 2026-03-19
Date of detection: 2026-03-19 (StepSecurity Harden-Runner)
Date of remediation: 2026-03-20 – 2026-03-21
Status: Resolved
Reference: netresearch/ofelia#535


1. Executive Summary

On March 19, 2026, the GitHub Action aquasecurity/setup-trivy was compromised via a tag force-push attack. Malicious code was injected that exfiltrated GitHub Actions runner memory (containing secrets) to an attacker-controlled domain. One workflow run in our org was affected. The exposure was limited to a short-lived, read-only GITHUB_TOKEN. No secret rotation was required.

In response, we hardened all 68 repositories across the netresearch GitHub organization with SHA-pinned actions, Dependabot configuration, and org-level enforcement — completing a comprehensive supply chain security overhaul within 48 hours.


2. Incident Details

2.1 What Happened

Detail Value
Compromised action aquasecurity/setup-trivy@v0.2.1 (tag force-pushed with malicious code)
Attack vector Tag force-push — mutable tag references resolved to attacker-controlled code
Malicious behavior Bundled runner worker memory into tarball, POST'd to scan.aquasecurtiy.org (typosquatted)
Compromise window ~18:07 – 18:11 UTC, March 19, 2026
Detection StepSecurity Harden-Runner (audit mode) logged DNS resolution and outbound connection to 45.148.10.212:443
Reference https://www.stepsecurity.io/blog/trivy-compromised-a-second-time---malicious-v0-69-4-release

2.2 Our Exposure

1 workflow run was compromised across the entire org:

Repo Run Branch Time (UTC) Evidence
netresearch/ofelia #23309867575 main 2026-03-19 18:11 Malicious curl to scan.aquasecurtiy.org confirmed in logs

Root cause of exposure: The workflow used trivy-action@915b19b... (v0.28.0) which internally referenced setup-trivy@v0.2.1 by tag (not SHA). When the tag was force-pushed, the malicious code executed.

All other repos were protected because they used trivy-action@57a97c7... (v0.35.0) which SHA-pins setup-trivy internally.

2.3 Secrets Exposure Assessment

Secret In scope? Permissions Risk
GITHUB_TOKEN Yes contents: read, security-events: write Low — short-lived, read-only on public repo
secrets.GITLEAKS_KEY No Different job, different runner None
Docker/GHCR credentials No Different job None
Cosign/OIDC signing tokens No Different job None
Org-level secrets No Not referenced in trivy job None

Verdict: No secret rotation required. Verified no malicious SARIF uploads occurred.


3. Remediation Actions

3.1 Org-Level Enforcement

Setting Before After
sha_pinning_required false true

GitHub's org-level sha_pinning_required setting enforces that all GitHub Actions must be referenced by immutable commit SHA. Reusable workflows (@main, @tag) are explicitly exempt from this enforcement, allowing internal shared workflows to continue using branch references.

3.2 Repository Hardening

81 pull requests were created across the org:

Category Count
Merged 71
Closed (forks not maintained) 9
Auto-merge pending 1

Merged PRs (71)

Repository PR Additional fixes
composer-patches-plugin #69
concourse-ci-skill #13
context7-skill #16
data-tools-skill #6
dcind #6
docker-development-skill #12
docker-ftp-server #80, #81 Initial trivy pin + full hardening
docker-mariadb #26
docker-validator-w3c #108 Merge conflict resolved
enterprise-readiness-skill #31
file-search-skill #6
git-workflow-skill #20
github-project-skill #40
go-cron #348 Updated trivy-action v0.31→v0.35 (v0.31 had unpinned internal deps)
go-development-skill #23
ldap-manager #502 Fixed go.sum for templ v0.3.1001 transitive deps
maint #16
matrix-skill #16
molecule_http_docker_demo #27
moodle-docker #28, #29 Initial trivy pin + full hardening
netresearch-branding-skill #17
netresearch.github.io #13
node-magento-eqp #503 Branch updated
node-red-contrib-magento-eqp #373 Branch updated
nr-landingpage #2 PHPStan fixes, CGL fixes, functional test fix (missing setUpBackendUser)
ofelia #536
pagerangers-skill #20
php-modernization-skill #20
pipeline-factory #20
postdirekt-autocomplete-monorepo #132
raybeam #174
sdk-api-central-station #18 Pinned unpinned actions in workflow
sdk-eu-vat #18 Pinned unpinned actions, bumped phpunit for CVE-2026-24765
skill-repo-skill #35
t3x-cowriter #109
t3x-nr-image-optimize #44 PHPStan fixes, migrated to shared PHP-CS-Fixer config
t3x-nr-image-sitemap #29 Migrated to shared PHP-CS-Fixer config, added labeler.yml, fixed allow-plugins
t3x-nr-saml-auth #76 Added labeler.yml
t3x-nr-temporal-cache #57 TYPO3 v12/v13/v14 compat (IconSize), PHPStan fixes, missing translation key, functional test fixes
t3x-nr-textdb #88 Migrated to shared PHP-CS-Fixer config, added labeler.yml
t3x-nr-xliff-streaming #7 Added labeler.yml
t3x-scheduler #26 Removed strict_types from ext_emconf.php, Rector fix (ThrowWithPreviousExceptionRector), inlined CGL config for TYPO3 12 compat
t3x-sync #37 Removed strict_types from ext_emconf.php, migrated CGL config, inlined for TYPO3 12 compat
t3x-universal-messenger #37 Migrated to shared PHP-CS-Fixer config, added labeler.yml
terraform-provider-ad #11
timetracker #265
ttefsl #49
typo3-ci-workflows #28
typo3-ckeditor5-skill #15
typo3-conformance-skill #26
typo3-core-contributions-skill #13
typo3-ddev-skill #22
typo3-docs-ci-workflows #2
typo3-docs-skill #27
typo3-extension-upgrade-skill #15
typo3-project-upgrade-skill #2 Trimmed SKILL.md, fixed plugin.json, composer.json license
typo3-testing-skill #30
typo3-typoscript-ref-skill #3 Dual license migration, README markdown lint, ruff formatting
agent-rules-skill #20 Condensed SKILL.md to 447 words
ansible-role-gitlab-runner #10
ansible-role-monitoring-server #45 Replaced ansible-lint action with direct pip install
ansible_role_client_base #95 Pinned remaining unpinned actions, added .yamllint.yml
ansible_role_docker_containers #13, #14 Fixed molecule DinD with storage-driver: vfs
assetpicker #54
automated-assessment-skill #15
claude-coach-plugin #14 Created composer.json, fixed plugin.json, 48 ruff fixes
cli-tools-skill #17
composer-agent-skill-plugin #31
composer-audit-responsibility #9

Closed PRs (9 — forks not maintained)

Repository PR Reason
containers #1 Fork of bitnami/containers
docker-node-webserver #18 Fork of tobilg/docker-mini-webserver
guides #2 Fork of phpDocumentor/guides
matrix-docker-ansible-deploy #1 Fork of spantaleev/matrix-docker-ansible-deploy
news_importicsxml #1 Fork of georgringer/news_importicsxml
orocommerce #1 Fork of mollie/orocommerce
pforum #2 Fork of jweiland-net/pforum
typo3-mcp-server #4 Fork, upstream PRs only
codesnippet #5 Fork, not maintained

3.3 Additional Fixes (resolved during hardening)

Beyond SHA-pinning and Dependabot, the following pre-existing issues were discovered and fixed:

Issue Repos affected Fix
ext_emconf.php with declare(strict_types=1) t3x-scheduler, t3x-nr-image-sitemap, t3x-sync Removed — TER cannot parse it
Local PHP-CS-Fixer config not excluding ext_emconf.php t3x-nr-image-sitemap, t3x-sync, t3x-nr-textdb, t3x-scheduler, t3x-nr-image-optimize, t3x-universal-messenger Migrated to shared config from typo3-ci-workflows
Missing .github/labeler.yml 9 t3x-* repos Added standard labeler config
CVE-2026-24765 in phpunit sdk-eu-vat Bumped phpunit to ^10.5.62
TYPO3 v12/v13/v14 IconSize compat t3x-nr-temporal-cache Added class_exists fallback
Missing translation key causing functional test failures t3x-nr-temporal-cache Added button.view_content to locallang
Functional tests missing backend user setup nr-landingpage Added setUpBackendUser(1)
Rector: ThrowWithPreviousExceptionRector t3x-scheduler Passed $exception as previous
Docker-in-Docker overlay mount failure ansible_role_docker_containers Switched inner Docker to vfs storage driver
typo3-ci-workflows composer dep incompatible with TYPO3 12 t3x-scheduler, t3x-sync Inlined CGL config, pinned phpstan-typo3 ^1.0

4. Prevention Measures

4.1 Implemented

Measure Scope Impact
sha_pinning_required=true Org-wide All actions must use immutable SHA refs; reusable workflows exempt
SHA-pinned all third-party actions 68 repos Tags/branches can no longer resolve to compromised code
Dependabot for github-actions All repos Automatic PRs for action version updates with SHA pins
StepSecurity Harden-Runner 19 repos (audit mode) Detects malicious outbound connections

4.2 Recommended Future Improvements

Measure Priority Impact
Switch Harden-Runner from audit to block mode with domain allowlists High Would have prevented the data exfiltration
Expand Harden-Runner to remaining repos Medium Broader detection/prevention coverage
Upgrade to GitHub Team plan Medium Enables org-wide rulesets for branch protection

5. Tools & Methodology

Tool Purpose
pin-github-action (npm) Batch SHA-pinning with --allow "netresearch/*" to preserve internal workflow refs
gh CLI PR creation, merge, status checks, API operations
StepSecurity Harden-Runner insights Malicious connection detection and forensics
GitHub org-level sha_pinning_required API Org-wide enforcement of immutable action references

6. Timeline

Time (UTC) Event
2026-03-19 ~18:07 aquasecurity/setup-trivy tags force-pushed with malicious code
2026-03-19 18:11 ofelia CI run executes compromised code; Harden-Runner logs malicious connection
2026-03-19 ~18:15 Compromised tags removed by aquasecurity
2026-03-20 08:33 ofelia workflow updated to safe trivy-action v0.35.0
2026-03-20 10:07 StepSecurity files issue #535
2026-03-20 ~19:30 Investigation complete: 1 compromised run, low-risk exposure
2026-03-20 19:32 sha_pinning_required=true enabled org-wide
2026-03-20 19:45–21:00 Batch hardening: 59 PRs created across org
2026-03-20 21:00–23:30 CI fixes: pre-existing issues resolved across 20+ repos
2026-03-21 00:00 68/68 repos green, all PRs merged
2026-03-21 00:03 Issue #535 closed
2026-03-21 ~00:30 Team notified via Matrix #it channel

Report generated 2026-03-21. Contact: Sebastian Mendel

Metadata

Metadata

Assignees

No one assigned

    Labels

    securitySecurity incidents and advisories

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions