Why Better AI Models Make Bugs Harder to Catch
As AI coding assistants get better, the obvious bugs vanish and the structural ones hide inside code that looks too clean to question.
A year ago, AI coding assistants shipped obvious bugs. Undefined variables. Off-by-one loops. Calls to methods that never existed. Those are mostly gone now. The models got fluent. What they didn’t get is safe: Veracode’s State of Software Security 2026 still found that 45% of AI-generated code introduced at least one OWASP Top 10 vulnerability on first generation. The bugs didn’t leave. They went quiet.
The Obvious Bugs Are Already Gone
BrassCoders sees the same shift across AI-generated Python that the research describes: the easy mistakes are rare now, and the dangerous ones persist at a structural rate. Veracode measured 45% of generated samples carrying an OWASP Top 10 flaw on first generation, a figure that hasn’t fallen as the models improved.
Newer models clean up the cosmetic layer. They name variables well, follow framework idioms, and structure functions the way a senior engineer would. The Veracode 2026 report measured the security layer underneath, and it didn’t move: nearly half of generated samples still shipped an injection flaw or a broken access check. Fluency improved. Safety didn’t.
Why Cleaner Code Hides Worse Bugs
BrassCoders treats reviewer trust as part of the threat model. When AI-generated code reads clean and idiomatic, a human reviewer relaxes, and the one line that opens a vulnerability gets waved through with the ninety-nine lines that are fine.
The model that wrote the code can’t reliably catch the bug either. Liu et al.’s Lost in the Middle (2023) showed that language models attend strongly to the start and end of a long input while losing the middle. A bug whose logic spans the middle of a large file, or several files, sits in the model’s blind spot whether it’s generating or reviewing. The cleaner the output looks, the less anyone thinks to check.
The Bugs That Survive a Smarter Model
BrassCoders catches three defect classes that ride through AI review untouched: cross-file taint flows, imports of packages that don’t exist, and credentials hardcoded into config stubs. None of them depend on the model being weak. They depend on how the model reasons.
Cross-file taint is the clearest case. A flow that starts in an API route, passes through a helper, and reaches a database call lives in three files; no single-file context holds the whole path. BrassCoders runs Pyre/Pysa interprocedural taint analysis, which walks the call graph instead of reading a window of text.
Hallucinated imports are the supply-chain case. A USENIX Security 2025 study found 19.7% of AI-recommended packages don’t exist on the registry, which is enough for an attacker to register the invented name and wait for someone to install it. BrassCoders checks every import against the public registry before pip install runs.
Hardcoded secrets are the quiet one. Generated config stubs love to drop a real key into an example. GitGuardian’s State of Secrets Sprawl 2024 counted 12.8 million secrets exposed in public commits in a single year. BrassCoders bundles detect-secrets with custom patterns and flags credential-shaped strings at scan time.
Why a Newer Model Won’t Close the Gap
BrassCoders exists because a stronger model inherits the blind spots of the model that wrote the bug. The reviewer reasons over the same single-file window, produces the same confident prose, and runs no exhaustive search across known rules.
Capability keeps climbing, and it still falls short of the bar that matters. The ENAMEL benchmark (2024) measured how efficient LLM-generated code is against an expert reference and found that leading models reach only a fraction of expert-level efficiency even when their output passes every test. A model can be correct and still be wrong about scale or cost. Asking that same model to grade its own work doesn’t add a second opinion; it adds a louder version of the first one.
What a Deterministic Layer Adds
BrassCoders runs 12 static-analysis scanners — Bandit, Pyre/Pysa, Semgrep, detect-secrets, and custom detectors — and produces the same findings on the same code every time, no matter how polished the code looks. A scanner doesn’t get impressed by clean variable names.
That determinism is the point. The scanner has no context window to fall out of, no confidence to be swayed by, and no stake in defending code it just wrote. BrassCoders emits its findings as a YAML file your AI assistant reads directly, so the model spends its judgment fixing what the scanner found instead of grading itself. Every number in this post traces to a primary source in the BrassCoders research index.
The OSS core is free, Apache 2.0, and makes no outbound network calls. Point it at a repo your AI assistant has been writing:
pipx install brasscoders
brasscoders scan
The better your model gets, the more it’s worth having one layer in the stack that the polish can’t fool.
Frequently Asked Questions
Do better AI models reduce code vulnerabilities?
Not at the rate you'd expect. Veracode's State of Software Security 2026 found 45% of AI-generated code introduced an OWASP Top 10 vulnerability on first generation. Stronger models fix cosmetic mistakes faster than structural ones, so the security rate stays high even as fluency climbs.
What kinds of bugs survive AI code review?
Structural bugs that span more than one file. Liu et al. 2023 (Lost in the Middle) showed language models lose attention to the middle of a long input, so a taint flow that crosses three files slips past a model reviewing one file at a time. BrassCoders runs interprocedural taint analysis with Pyre/Pysa, which walks the call graph and has no context window.
Why is polished AI code more dangerous?
Because reviewers trust it more. When the surrounding code reads clean and idiomatic, a reviewer is less likely to question the one line that opens a SQL injection. BrassCoders flags the finding deterministically, regardless of how confident the code looks.
Does BrassCoders use AI to find the bugs?
No. BrassCoders is a deterministic layer: 12 static-analysis scanners including Bandit, Semgrep, Pyre/Pysa, and detect-secrets that produce the same findings on the same code every time. The Paid plan adds AI-powered enrichment to rank findings, but detection itself is rule-based.
Can't I just use a newer model to review the code?
A newer model shares the blind spots that produced the bug: a single-file context window, confident output, and no exhaustive rule search. BrassCoders complements the model instead of grading it, catching cross-file taint, hallucinated imports, and hardcoded secrets the model structurally misses.