the numbers

figurewhat it measures
20.4%had at least one exposed-secret finding (~1 in 5)
26.8%had at least one critical or high security finding
14.9%had at least one critical finding
47.5%had at least one injection-category finding (2nd most-hit category)
42.6%used dangerouslySetInnerHTML, the single most common finding
97 / 89.0median score (an A) vs mean of 89.0. The median is inflated by tiny demo repos; 196 of 549 scored below A, including 14 at F

the same numbers, minus the toy repos (n = 467)

Substantive subset: repos with 15+ scannable files, dropping workshop demos and single-page toys. That's the more honest read of real projects, and it's what the pitch numbers use.

23.3%had at least one exposed-secret finding (~1 in 4)
30.2%had at least one critical or high security finding (~1 in 3)
48.8%had at least one injection-category finding
43.0%used dangerouslySetInnerHTML

the shape of the data

grade distribution (n = 549)
A
353
B
69
C
92
D
21
F
14
most common findings, by % of repos (n = 549)
dangerouslySetInnerHTML
42.6%
.gitignore misses .env
35.7%
no .gitignore at all
15.3%
wildcard CORS
11.3%
curl | sh install
9.8%
hardcoded password
9.3%

Charts are free to reuse with a link back to this page.

methodology

secure·vibes heuristic rules engine (no AI pass) run over 549 public GitHub repos that describe themselves as AI- or vibe-coded. The original 107-repo set from June 2026 grew to 577 candidates in July 2026.

Corpus selection: repos whose name, description, or README says AI- or vibe-coded. We took them at their word and didn't verify provenance. 577 candidates, 28 skipped as too large or unreachable, n = 549 analyzed.

Reporting caps at 10 findings per rule and 300 per repo, so counts for the messiest repos are floors. The Claude review that runs in a normal secure·vibes scan was off. Every number here is deterministic and re-runnable.

The downloadable per-repo rows carry anonymised repo IDs. These are public GitHub repos, and a file mapping named repos to their security findings would be a target list, so that join stays unpublished.

download the raw data

Check our numbers — every figure on this page recomputes from these files.