Review by sources and sinks, not top to bottom

Reading a large codebase line by line wastes time. Build two lists first: sources (request params, headers, queues, files, env) and sinks (query, exec, deserialize, file path, template, redirect). Then trace only paths that connect one to the other.

bash
# sinks across languages, one pass
grep -rEn "exec|system|popen|eval|unserialize|pickle|readObject|Runtime.getRuntime|child_process|Process(" --include=*.{php,py,java,js,ts,rb,go,cs} .

Then confirm reachability from a source with a call graph.

bash
semgrep --config p/owasp-top-ten --sarif -o out.sarif .
grep -RnE "req.(query|body|params)|request.(GET|POST|args)|$_(GET|POST|REQUEST)" src/

Pro note: a sink is only a bug if a source reaches it without a real sanitizer in between. Note the exact function that is supposed to neutralize the input and verify it actually does; broken or bypassable sanitizers are where the real findings live.