Scanners find what’s syntactically wrong. The interesting issues live in assumptions – and assumptions don’t have signatures.

Not scanning, not fuzzing. Just reading code the way you’d read it if you were about to own it in production. Entry points, data flows, where input meets trust.

Missing headers, outdated dependencies – that’s the baseline, scanners handle it fine. The interesting issues live a layer deeper. A path that’s protected in one subsystem but wide open in another. A parse-time operation that nobody thought to bound. Code that was correct when it was written but the system grew around it.

Those aren’t in any scanner’s database because they’re not patterns yet. They’re the gap between what the developer intended and what the code actually does. You only see that gap if you understand what the code was trying to do in the first place.

It’s the same skill as debugging production systems. Trace the data, find where reality diverges from the mental model, understand why. The only difference is you’re looking for the divergence instead of being woken up by it.