En bref. Vos analyseurs produisent plus de constats que l'équipe peut en lire, et la plupart sont des faux positifs. Un modèle d'IA peut trier, mais seulement s'il voit ce que l'analyseur ne voit pas : l'architecture, les modèles de menaces et vos décisions passées. Ajoutez une issue « à vérifier », un second modèle qui vérifie le premier, une personne avant chaque billet, et un seul billet par vulnérabilité.
The situation
- Static analysis on the code, dynamic scanning against the running app, maybe a third tool.
- Every pull request adds findings. The same issue shows up in two tools and on ten pull requests.
- Developers have learned to scroll past the report.
The noise is real. Ghost Security's 2025 study ran traditional static analysis tools across nearly 3,000 open-source repositories: 180 of the 2,116 flagged issues were real vulnerabilities. More than 91% were false positives.
Ignoring it is not safe either. In Verizon's 2025 Data Breach Investigations Report, exploiting a vulnerability was the initial access vector in 20% of breaches, up 34% on the year before.
Why a model on its own does not fix it
Handing scanner output to a model and asking "is this real?" produces confident guesses.
- It sees what the scanner sees. A request and a response. Whether a finding matters depends on what neither of them shows: is the endpoint exposed, what data sits behind it, is there a compensating control.
- Without that context, it has the scanner's blind spot, with better grammar.
- A wrong "false positive" is worse than noise. It closes a real vulnerability with a convincing explanation, and nobody looks again.
What to do
1. Test the running app, in a sandbox
- Deploy each pull request into a throwaway container in your CI pipeline.
- Run your dynamic scanners against that copy.
- Runtime findings appear before the merge, and nothing is tested against production.
2. Ground the triage model
Retrieve alongside every finding:
- your architecture documents
- your threat models
- the team's past decisions on similar findings
If those documents do not exist or are out of date, fix that first. Garbage in, garbage out.
3. Force three outcomes, each with a reason
- Real: goes to a person.
- False positive: closed with a written justification anyone can audit.
- Needs a human: the model says it is not sure.
Attach a confidence level to every verdict. A model that cannot say "I don't know" will guess.
4. Have a second model check the first
- Use a different model to review each verdict.
- Send disagreements to a person.
5. Keep a person before any ticket, and feed decisions back
- No ticket without human approval, at least until you have measured how often the verdicts match your team's.
- Every approval or correction goes into the knowledge base, so the next triage starts from it.
6. One ticket per vulnerability
- Check your tracker for an existing ticket before creating one.
- Put the same fields on every ticket: severity, a fix suggestion, an owner, and the confidence level.
Where to start
- One scanner, one repository.
- Two weeks in shadow mode: the model triages, people still decide, and you compare the two.
- Then add the second model and automatic tickets, once the verdicts match your team's often enough to trust.
How we did it
We built this in eight weeks for a team of 50+ developers: SonarQube, OWASP ZAP and Nuclei on every pull request, two models grounded in the architecture and threat models, and deduplicated Jira tickets after human review.
Want help putting this into practice?
We work alongside your team to design, build, and operate the controls described above.