We Scanned Our AI Stack with Trivy — Here's What We Found

By Prahlad Menon 2 min read

29 million secrets were leaked on public GitHub last year. That number is from GitHub’s own data — passwords, API keys, tokens committed and pushed before anyone noticed.

We decided to stop assuming our stack was clean and actually check. Here’s what a real scan found in real production repos — and what we fixed.

The Setup

We scanned five repos using Trivy — Aqua Security’s open-source scanner:

  • menonpg/agent-validator — FastAPI service running live on Cloud Run
  • menonpg/menonlab-blog — this blog (Astro, deployed on Railway)
  • menonpg/stockscout4 — AI trading desk (Railway)
  • menonpg/soul.py — PyPI package
  • menonpg/monica-workspace — agent workspace

Install is one line:

# macOS
brew install trivy

# Linux
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin

Then scan:

trivy fs --scanners secret,vuln --format table .

What We Found

agent-validator — 2 HIGH, live public service

The most serious findings were in the agent-validator service — a FastAPI app running on Cloud Run that validates AI agent repositories. It’s publicly accessible.

python-multipart 0.0.9 → 2 HIGH vulnerabilities
├── CVE-2024-53981  Severity: HIGH  Fixed: 0.0.18
│   DoS via deformed multipart/form-data boundary
└── CVE-2026-24486  Severity: HIGH  Fixed: 0.0.22
    Arbitrary file write via path traversal ⚠️

The second one is the serious one. CVE-2026-24486 is an arbitrary file write vulnerability — a crafted multipart request could write to arbitrary paths on the server. That’s a full server compromise vector on a public endpoint.

The fix was one line in requirements.txt:

- python-multipart==0.0.9
+ python-multipart==0.0.22

Pushed, Cloud Run redeployed. Total time to fix: under 5 minutes once we knew it existed.

menonlab-blog — 11 vulnerabilities in npm/pnpm lockfiles

The Astro blog had more findings, mostly in transitive dependencies:

pnpm-lock.yaml: 10 vulnerabilities (HIGH: 4, MEDIUM: 2, LOW: 4)
package-lock.json: 1 vulnerability (HIGH: 1)

The HIGH findings:

PackageCVEWhat It Does
rollup 4.57.1CVE-2026-27606RCE via path traversal — fix: 4.59.0
h3 1.15.5CVE-2026-33128SSE injection via unsanitized newlines — fix: 1.15.6
fast-xml-parser 5.3.6CVE-2026-33036Numeric entity expansion DoS — fix: 5.5.6
svgo 4.0.0CVE-2026-29074XML entity expansion DoS — fix: 4.0.1

The rollup RCE is the notable one — remote code execution via path traversal in the build tool. Fixed:

npm audit fix  # patches what it can
git add package-lock.json && git push

One finding — fast-xml-parser HIGH — had no available fix at scan time. It’s a transitive dependency of Astro waiting on an upstream patch. It’s logged; we’ll update when the fix ships.

stockscout4, soul.py, monica-workspace — all clean

StockScout v4:   ✅ 0 secrets, 0 vulnerabilities
soul.py:          ✅ 0 secrets, 0 vulnerabilities
monica-workspace: ✅ 0 secrets, 0 vulnerabilities

Worth noting: StockScout v4 was clean because we found and removed hardcoded API keys from it the day before scanning. Trivy would have caught those too — but we got lucky that we fixed them first. More on that in a moment.

The Secret Scanning Story

Running secrets scan across the repos:

trivy fs --scanners secret .

Everything came back clean. But this is where context matters.

We had just spent a session auditing StockScout v4 for hardcoded values and found:

  • FRED_KEY = "4b10e4313ff2d2784d439bee0bb58893" hardcoded at module level
  • FRED_API_KEY with a hardcoded default in config.py
  • trump_v3.py pointing to a dead URL (not a secret, but dead code)

We fixed those before running Trivy. If we’d run the scan first, it would have flagged all of them. The lesson: secrets scanners work on what’s currently in the code. If you’ve already committed and pushed a secret, it’s in git history even if you remove it from the current file — and that requires git filter-repo to fully clean.

Running Trivy in CI — The Right Way

Finding vulnerabilities after deployment is better than not finding them. Finding them before merge is better still.

# .github/workflows/security.yml
name: Security Scan
on: [push, pull_request]

jobs:
  trivy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Run Trivy
        uses: aquasecurity/trivy-action@master
        with:
          scan-type: 'fs'
          scan-ref: '.'
          scanners: 'vuln,secret'
          severity: 'HIGH,CRITICAL'
          exit-code: '1'   # Fail the build on HIGH/CRITICAL
          format: 'table'

This runs on every PR and fails the build if HIGH or CRITICAL findings exist. We’re adding this to agent-validator and stockscout4 now.

The Honest Summary

RepoSecretsVulnsStatus
agent-validator02 HIGH✅ Fixed (python-multipart → 0.0.22)
menonlab-blog04 HIGH, 7 lower✅ Mostly fixed (1 pending upstream)
stockscout400✅ Clean
soul.py00✅ Clean
monica-workspace00✅ Clean

One live public service had an arbitrary file write vulnerability. The blog had a build tool RCE. Neither was obvious — both were in dependency versions that looked fine at a glance.

Two commands. Under ten minutes to scan everything. A path traversal CVE in a public Cloud Run endpoint found and fixed before anyone else found it.

brew install trivy and run it on your stack before someone else does.

github.com/aquasecurity/trivy