We shipped a closed beta of Dockier in March. The first thing we did before sending invites was point it at the Dockier monorepo. If a vulnerability scanner can't survive being run on the code that wrote it, the marketing site shouldn't survive either.
Here's what we found on day one — every category, every finding, including the embarrassing one.
In the Dockier stack · The scanner is thecode-analysisservice in our Fastify + TypeScript backend (one of ten service modules selected viaSERVICE_NAME). Findings persist in Supabase Postgres with RLS scoped per-organisation. The repo it was scanning is the same pnpm workspace —backend/for Fastify services,frontend/for the Vite + React 19 app,migrations/as the single SQL source of truth.
The raw numbers
- 47 findings total across SAST, dependencies, and the schema-aware sensitive-data scanner.
- 3 we agreed were real and needed fixing.
- 1 was the kind of thing you tell people about over beer, not in a postmortem.
- 43 were noise, dupes, or "yes, and we accept that risk."
The three real ones
1. A dangerouslySetInnerHTML call rendering Markdown without sanitisation
Our changelog page rendered post bodies through marked and dropped the result straight into the DOM. The risk was real but bounded — only authors could write changelog entries — and we'd been treating it as a defence-in-depth item we'd "get to." The scanner found it on day one and we shipped DOMPurify the same afternoon.
2. A Postgres query concatenated with an untrusted ref string
The branch-comparison endpoint took a Git ref and used it inside a query that also templated table names. We'd pre-validated the ref against a regex but the regex allowed dots. main.commits wasn't a valid ref but we hadn't proven that to ourselves. Fix: parameterised query (Supabase exposes the same Postgres protocol, so the fix was a one-liner) plus an explicit allowlist of table targets.
3. A leaked GCP service-account key in an old commit
Buried in a commit from January. The key had already been rotated, but the commit was still public on a fork. We squashed-and-force-pushed and notified GitHub's secret-scanning team. The scanner flagged the original commit hash which made the cleanup deterministic.
The embarrassing one
The sensitive-data scanner flagged our own users table for storing plaintext API tokens. They were one-way hashed before storage — but the column was called api_token with no _hash suffix. The scanner couldn't tell. We renamed the column, added a comment to the migration, and wrote a rule that suppresses the finding when the column has a corresponding verify_* function within the same file.
That last bit is now an open rule in our public rule set. If you also store hashed tokens with naked names, the rule will save you from the same review.
The 43 we ignored
Worth being honest about: most findings on most repos aren't actionable. The breakdown:
We've since added a "scope" field to every rule that asks whether the finding is on production code paths. That cut the noise in half on the next run.
What this taught us about the product
Two things, both unsurprising in retrospect:
- Severity isn't the whole story. A "critical" SQL-injection finding on a script you run locally once a quarter is less urgent than a "medium" XSS on your billing portal. We've added a reachability signal that the rule can opt into.
- The team's first scan determines whether they'll do a second. 47 findings on a 200-file repo would have buried us. The first-scan view now groups by "real / probably real / context-required" — and lets you tag everything in the third bucket in one click.
If you want to do this on your own codebase, the early-access form is on the home page. We're prioritising teams who'll send us their day-one screenshot.