Scanning & correlation

How raw scanner output becomes one clean list of findings.

Semgrep (JSON) ─┐
                ├─► normalise ─► merge duplicates ─► group by fix ─► findings.json ─► triage
CodeQL (SARIF) ─┘

1. Two scanners, in parallel

SecureSense runs Semgrep (pattern rules, output as JSON) and CodeQL (semantic data-flow queries, output as SARIF, the standard format for static-analysis tools) at the same time as background processes. CodeQL's database is cached per project, so later scans are faster. If one scanner fails, the other's results are still used.

2. Normalise

The two formats describe findings differently. Each hit is converted into one common shape — file, lines, CWE number, severity, message, rule id — with paths made relative to the project and CWE labels parsed consistently (Semgrep writes CWE-89: Improper Neutralization…, CodeQL tags external/cwe/cwe-089).

3. Merge duplicates

Two hits become one finding when they are:

"Same kind" uses CWE families, because the scanners label one bug differently — CodeQL may call an eval of user input CWE-94 (code injection) where Semgrep says CWE-95 (eval injection):

FamilyIncludes
Command injection (CWE-78)CWE-77, CWE-88
Code injection (CWE-94)CWE-95
Cross-site scripting (CWE-79)CWE-80
SQL injection (CWE-89)CWE-564
Path traversal (CWE-22)CWE-23, CWE-36
XXE (CWE-611)CWE-776

A merged finding keeps every scanner that reported it. Two scanners means cross-scanner agreement, which raises the finding's priority. Merging also folds away Semgrep firing several rules on the same line. On the sample app, 17 raw hits become 7 findings. When scanners disagree on severity, the higher one is kept.

4. Group findings that share a fix

Findings on the same statement but of different kinds share a correlation group. pickle.loads(request.data) is both unsafe deserialization (CWE-502) and cross-site scripting (CWE-79): one fix resolves both. The dashboard's Approve all in this group (one fix) acts on these groups, and the panel can group by them.

5. Stable ids

A finding's id is a hash of its file, lines and category, not a random number. Re-scanning unchanged code gives the same ids, so your decisions and cached verdicts stay attached. (On the team server, ids are additionally scoped to the project, so two projects never collide.)

The findings file

The result is written to .securesense/findings.json in the scanned project (git-ignored automatically). The triage agent reads it, and so can your own tools — its format is defined in agent/securesense_agent/schema.py (CanonicalFinding).

Something unclear or wrong? Edit these docs on GitHub.