A dozen live apps with no consistent way of knowing whether a vulnerability had been introduced.
Situation
An agency maintained many client applications, each built quickly with AI-assisted development. Security reviews happened when someone remembered.
Dependency vulnerabilities, database configuration drift and coding mistakes could all sit unnoticed for months.
What was built
- Established a static security baseline for every application, covering authentication, tenant isolation, injection, data exposure and secrets handling.
- Scheduled recurring sweeps: code scanning, database advisor checks, and a software bill of materials matched nightly against known vulnerabilities.
- Routed every finding into a security-tagged ticket, and set up an agent that drafts a fix as a pull request for a human to review and merge.
What held up
- Security issues surface within a day rather than at the next manual review.
- Fixes arrive as reviewed pull requests, not emergencies.
- The same process now runs for every new application the agency ships.
What I would do differently
- Build the database advisor sweep before the static ruleset. It was the highest return for the least effort and I did it second.
- Enrich vulnerability matches with known-exploited and exploit-likelihood data from the first night, so priority is driven by risk rather than severity labels.
- Schedule the adversarial pass at the same time as the scanning, not as a later idea. Scanning finds patterns; the logic flaws need the other exercise.
Stack
Semgrep, Supabase advisors, OSV vulnerability data, GitHub Actions, Claude Code