Horusec Integration with DefectDojo
Horusec Integration with DefectDojo
Horusec is an open source static application security testing (SAST) orchestrator created by ZupIT. Its CLI runs its own engine (HorusecEngine) alongside third-party analyzers such as Bandit, Semgrep, and Trivy, and covers languages including Java, Kotlin, C#, Python, Ruby, Go, JavaScript, TypeScript, PHP, and Dart, plus Terraform, Kubernetes manifests, and hard-coded secrets. Results from every analyzer are merged into a single report that can be written as JSON for import into DefectDojo. The most recent release on the ZupIT GitHub repository is v2.8.0 from 2022, so check the project's maintenance status before adopting it for new pipelines.
Horusec Integration with DefectDojo
We picked Horusec because one command gave us coverage across a polyglot codebase without wiring up a separate scanner per language. The tradeoff is volume. A single run can produce hundreds of results from several analyzers at once, and the JSON file has no idea which of them we already triaged last sprint. Importing Horusec output into DefectDojo gives each result a home on the right Asset, matches it against earlier runs, and puts an owner and an SLA on the ones that matter.
Why Horusec Matters
Polyglot repositories are hard to cover with single-language tools, and maintaining five scanner configurations in CI costs real time.
- One CLI invocation runs several analyzers and normalizes their output into one schema, so downstream tooling only needs to understand one format.
- It looks for leaked credentials as well as code flaws, which catches a class of issue that language linters miss.
- Each result carries a file, line, code snippet, severity, and confidence, which is enough for an engineer to open the right file and start working.
- Without a platform behind it, the merged report is a flat list. There is no record of what was fixed, what was accepted, or how long a Critical has been open.
Advantages of This Integration
What we got from sending Horusec results through DefectDojo:
- Deduplication across runs. DefectDojo hashes Horusec findings on title, description, file path, and line, so a nightly scan of an unchanged branch doesn't create a fresh copy of every issue.
- Confidence preserved. Horusec's LOW, MEDIUM, and HIGH confidence values map to DefectDojo's scanner confidence (Tentative, Firm, Certain), so reviewers can sort low-confidence results to the bottom of the queue.
- Scan health on the Test. The parser records the Horusec version and writes the run status and any analyzer errors into the Test description, which makes a partially failed scan visible instead of silently thin.
- A reimport lifecycle. Reimporting into the same Test mitigates findings that disappeared, adds new ones, and reactivates any that returned.
- Ticketing and SLAs. Findings can be assigned, risk-accepted, or pushed to Jira, and severity-based SLAs apply the same way they do for every other scanner on the Asset.
How This Integration Works
DefectDojo imports Horusec output with the Horusec Scan scan type.
1. Produce a JSON report. Run the Horusec CLI against the project directory with JSON output:
horusec start -p . -o json -O horusec-report.json
Use -i to ignore paths such as test fixtures or vendored code if they add noise.
2. Import it. In the UI, open the Engagement, choose Import Scan Results, select Horusec Scan, and upload the JSON file. For automation, use 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=Horusec Scan" \
-F "file=@horusec-report.json" \
-F "product_name=billing-service" \
-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 "Horusec Scan" \
--report-path "./horusec-report.json" \
--product-name "billing-service" \
--engagement-name "CI" \
--auto-create-context
3. Reimport on each run. For a repository you scan repeatedly, send later reports to /api/v2/reimport-scan/ against the same Test so the history stays in one place.
Data Granularity: What Gets Imported
| DefectDojo Field | Source in Horusec Report | Notes |
|---|---|---|
| Title | First line of details |
Usually the rule name, such as a hard-coded password check |
| Description | Last line of details, plus code |
The flagged code snippet is added in a fenced block labeled with the language |
| Severity | severity |
Title-cased: CRITICAL becomes Critical, HIGH becomes High, and so on |
| Scanner Confidence | confidence |
HIGH is Certain, MEDIUM is Firm, LOW is Tentative |
| File Path | file |
Path relative to the scanned directory |
| Line | line |
Set only when Horusec provides a numeric line |
| Date | Report createdAt |
Every finding carries the scan date |
| Test version and description | version, status, errors |
Recorded on the Test, not on each finding |
| Deduplication | Hashcode | Title, description, file path, line |
The parser does not import Horusec's securityTool field, commit metadata, or vulnHash, and it does not set CWE or CVE fields. CWE references often appear inside the description text instead.
Use Cases
In a CI/CD pipeline: Each merge to the main branch runs Horusec and reimports the report into a Test named for the repository. Developers see what changed since the last run, and a pipeline step can query the DefectDojo API for new Critical findings before a release.
For a monorepo with many languages: A platform team scanning a repository that mixes Go services, a TypeScript frontend, and Terraform modules gets one Test per repository instead of one per language tool, with every finding hashed on its file and line.
When cleaning up leaked secrets: Hard-coded credential findings land with their file and line, so the security team can assign each one to the owning team, track rotation through notes, and close it when the next scan no longer reports it.
When evaluating scan quality: Because analyzer errors are written to the Test description, an AppSec lead reviewing a suspiciously small result set can see that, for example, a package manager audit step failed during that run.
Operational Tips
- Read the Test description after each import. If Horusec reports a status of error, some analyzers did not run and the finding count is incomplete.
- Use
minimum_severityon import to hold back Low results while you work through Critical and High, then lower it once the backlog is under control. - Filter on scanner confidence during triage. Tentative results are the best candidates for false positive review.
- Exclude test fixtures and sample data with Horusec's ignore option rather than marking each one as a false positive in DefectDojo.
- Because the line number is part of the hash, a finding can reappear as new when unrelated edits shift code. Reimport into the same Test so the old copy is mitigated, and review new findings with that in mind.
- Tag imports with the branch or release (for example
tags=main,v3.2) so findings can be filtered in metrics.