To trace data in a code review, list every source of outside data in the change, follow each value through validation and processing, and check every sink where it lands, such as a query, a file path, a page or a log. A source with no check before its sink is a finding.
Definitions
- Source: a place untrusted data enters. The OWASP Secure Code Review Cheat Sheet lists user inputs, file uploads, API calls, database reads and environment variables.
- Sink: a place where data has an effect. OWASP lists database queries, file writes, output rendering, logging and external APIs.
- Trust boundary: where data crosses from a less trusted zone into a more trusted one. OWASP says to validate input and encode output at these boundaries.
The method in five steps
- Find the sources. Scan the diff for request parameters, headers, cookies, uploaded files, message queue payloads and anything read from a store another team writes.
- Name each value. Write it down:
search_term,file_name,account_id. - Follow it. At each function call, ask whether the value is checked, changed or passed through untouched.
- Find the sinks it reaches. Which queries, paths, commands or templates use it?
- Judge the gap. Is there a check that matches what the sink needs?
That last point is the heart of it. A length check does not protect a query. Output encoding does not protect a file path. The control has to fit the sink.
A worked example
Suppose a pull request adds an export feature:
def export(request):
name = request.args["report"]
path = "/data/reports/" + name
return send_file(path)
Source: the report argument. Value: name. It is concatenated into a path with no check, then reaches a file read sink. A reviewer tracing it would ask what happens when the value contains parent directory segments, and whether the caller is allowed to read that report at all.
The fix has two parts, because there are two gaps: restrict the name to a known set or resolve and verify the final path stays inside the reports directory, and check that the report belongs to the caller's account.
Checks to match sinks
| Sink | Control to look for |
|---|---|
| Database query | Bound parameters, not string building |
| File path | Allowlist or resolved path check, plus authorization |
| Page output | Context appropriate encoding |
| Log line | No secrets or personal data, no raw newlines |
| Outbound request | Allowlist of destinations |
| Shell command | No shell, argument lists, fixed commands |
OWASP's checklist covers each of these categories in more detail, including parameterised queries, allowlist validation and output encoding.
When the trace leaves the diff
Sometimes a source is in this change and the sink is in code you cannot see in the diff. Open the called function. If it belongs to another team, ask in the review. Do not assume the callee validates, because the callee's author may assume you did.
What tools add
Static analysis tools do a version of this trace automatically, which is why running them before manual review is sensible. OWASP suggests using tool findings to prioritise manual review areas and applying human judgment to validate them. The tool finds candidate paths, and you decide whether the check at the sink is adequate.
Try it yourself
Open the demo to see a code scan result with a source and sink listed. Pick one finding and try to explain it in your own words, as you would in a review comment.
Click through it at your own pace, or open it full screen.
Quick check
Do I need to trace every variable?
No. Trace values that come from outside the service, and values that reach dangerous sinks. Internal constants can be skipped.
Is validating at the source enough?
Not always. The right check depends on the sink, so a value validated for one use may still be unsafe in another.
Sources
Last reviewed: 19 October 2026.