Write a unit test that sends the dangerous input from the scanner's data flow into the flagged function and asserts safe behaviour. If the test fails, the finding is real and you now have a regression test. If it passes for every hostile input you can think of, you have evidence for a false positive.
Why a test beats an argument
Debates about whether a finding is exploitable can run for days. A test settles it in minutes and stays in the repository. It also turns the fix into a normal code change that reviewers understand.
OWASP notes that with source code analysis tools it can be hard to confirm that a reported issue is an actual vulnerability. A test is the cheapest confirmation available to a developer who owns the code.
Steps
- Read the data flow. Most SAST reports show a source, where untrusted data enters, and a sink, where it does harm. If the terms are new, read what a source and a sink are in SAST.
- Find the entry point. Pick the function nearest the sink that you can call from a test, or the handler that receives the request.
- Choose hostile inputs. For injection, a quote and a comment marker. For path traversal, a parent directory sequence. For cross site scripting, markup characters. Keep the inputs harmless to your test environment.
- Assert the safe outcome. The query is parameterised, the path stays inside the base directory, or the output is encoded. Test the property, not the exact string.
- Run it. A failure confirms the finding. Record the test name in the finding.
- Fix and re-run. The same test should now pass, and the next scan should drop the finding.
What the result means
| Test result | Meaning | Next step |
|---|---|---|
| Fails with hostile input | True positive | Fix, keep the test |
| Passes, and you can name the control | Likely false positive | Suppress with the control and the test as evidence |
| Passes, but only because the setup is unrealistic | Unknown | Move the test closer to the real entry point |
| Cannot be tested in isolation | Unknown | Try an integration test or a DAST replay |
Cautions
A passing test shows only that those inputs were safe. Try several variants before you call something false. Do not weaken the test to make the build green. And avoid pointing hostile inputs at shared databases or live services. Use a local or throwaway instance.
Use the test in the suppression
If you decide the finding is false, the suppression comment can name the test, as described in writing a suppression comment that survives review. A later reader can run it instead of trusting your word.
Try it yourself
Open the demo and trace one finding from the flagged line back to where its input originates.
Click through it at your own pace, or open it full screen.
One factual note on Safeguard
Safeguard offers autonomous remediation with fix pull requests, off by default with every category on Manual. If you want a quick look at your own code, the free scan at gold.safeguard.sh/scan is a no-account place to start.
Quick check
Does a passing test prove a finding is false?
No, it only shows those inputs were handled. Try several hostile variants and name the control that protects the code.
What if I cannot call the flagged code from a test?
Test at the nearest callable entry point, or replay the request against a local instance.
Sources
Last reviewed: 19 October 2026.