Python Taint Integration with DefectDojo
Python Taint Integration with DefectDojo
Python Taint (PyT) is an open source static analysis tool for Python web applications, published by the python-security project on GitHub and installed from PyPI as python-taint. It builds control flow graphs and runs dataflow analysis to follow untrusted input from a source, such as a request parameter, to a dangerous sink, which lets it report classes of issues like command injection, SQL injection, cross-site scripting, server-side request forgery, and directory traversal. It writes its results as JSON with the -j flag. The project README states that it is no longer maintained.
Python Taint Integration with DefectDojo
We still run Python Taint on a few older Flask services because a source-to-sink trace is far more convincing than a pattern match, and DefectDojo is where those traces become assigned work. Importing the pyt JSON report into DefectDojo creates one Finding per flow, anchored on the sink line where the dangerous call happens, with the source, the sink, and every reassignment in between written into the description. A developer opening the Finding can follow the exact path the input took instead of re-deriving it from a rule name.
Why Python Taint Matters
Pattern-based scanners flag calls that look risky. Taint analysis asks a more useful question: can attacker-controlled data actually reach this call?
- Each result is a complete flow from an untrusted source to a sink, so the evidence is part of the finding.
- The propagation trace shows how the value moved through assignments, which speeds up both triage and the fix.
- It targets web application code, where request data is the usual source of injection bugs.
- The trade-off is maintenance. The upstream project is no longer maintained, so newer frameworks and Python versions may not be handled, and teams should plan accordingly.
Advantages of This Integration
What importing pyt results into DefectDojo adds:
- Every flow is High. pyt reports no severity, and the parser imports each completed source-to-sink flow as High, so these results receive the attention of an exploitable path.
- Precise location. The file path comes from the source or sink, and the line is the sink line, which is where a fix or sanitizer usually goes.
- Readable evidence. Source label, sink label, trigger words, and the reassignment trace are formatted in the description.
- Deduplication on flow, file, and line. DefectDojo hashes the flow identifier, file path, and line, so rescans recognize flows already being tracked.
- Lifecycle on reimport. Reimporting a new report into the same Test mitigates flows that disappeared after a fix and adds new ones.
- A path off pyt later. Because Findings live in DefectDojo, history is kept even if you replace pyt with another taint analyzer and import its results into the same Asset.
How This Integration Works
DefectDojo imports pyt results with the Python Taint Scan scan type, which reads the vulnerabilities array from the JSON output.
1. Produce a JSON report. Run pyt against your project directory:
pyt -j project/ > pyt.json
2. Import it. In the UI, open the Engagement, choose Import Scan Results, select Python Taint Scan, and upload pyt.json. Through the API, available in Community Edition and DefectDojo Pro:
curl "https://YOUR_INSTANCE/api/v2/import-scan/"
-H "Authorization: Token $DD_API_TOKEN"
-F "scan_type=Python Taint Scan"
-F "file=@pyt.json"
-F "product_name=legacy-portal"
-F "engagement_name=CI"
-F "auto_create_context=true"
DefectDojo Pro users can run the same import with Universal Importer:
universal-importer import
--defectdojo-url "https://YOUR_INSTANCE.cloud.defectdojo.com/"
--scan-type "Python Taint Scan"
--report-path "./pyt.json"
--product-name "legacy-portal"
--engagement-name "CI"
--auto-create-context
3. Reimport on each build. Send later reports to /api/v2/reimport-scan/ against the same Test, so fixed flows are mitigated and the history stays together.
Data Granularity: What Gets Imported
| DefectDojo Field | Source in pyt Report | Notes |
|---|---|---|
| Title | source_trigger_word, sink_trigger_word |
Tainted flow: <source> to <sink> |
| Severity | Fixed | High for every flow |
| Description | Source, sink, and reassignment nodes | Each with file and line, plus the trigger words |
| File Path | source.path or sink.path |
Source path first |
| Line | sink.line_number |
Anchors on the dangerous operation |
| Vuln ID From Tool | rule, or source -> sink |
Trigger words are used when no rule is named |
| Finding type | Static | All pyt findings are marked static |
| Deduplication | Hashcode | Vuln ID from tool, file path, line |
pyt does not supply CWE, CVE, or remediation text, so those fields stay empty.
Use Cases
Maintaining a legacy Flask app: A team that inherited an older service runs pyt in CI and reimports into one Test. New flows show up as new High Findings while existing ones keep their owner and SLA.
Security review before a rewrite: Before porting a service, the security team imports a pyt report to get a list of known injection paths, so the rewrite can be checked against it.
Comparing analyzers: A team evaluating a replacement taint tool imports both reports into the same Asset and compares which flows each one finds.
Audit trail: Flows imported from pyt keep their discovery date and remediation history, which helps show that injection paths found in older code were tracked to closure.
Operational Tips
- Treat the upstream maintenance status seriously. Use pyt where it already works and pair it with a maintained analyzer for new code.
- Because every flow imports as High, expect SLA pressure on first import. Triage false positives promptly and mark them so reimports respect the decision.
- When a flow is safe because of a sanitizer pyt does not recognize, record that in a note and mark the Finding false positive rather than deleting it.
- The line number is the sink line, and it is part of the dedupe hash. Refactors that move the sink can close the old Finding and open a new one.
- Tag imports with the service or repository name when several codebases share an Asset.
- Use findings assignment to send each flow to the owner of the file named in the File Path.