DEV Community

An AI summary is not a fix. Stop letting it close your security findings.

Dimitris Kyrkos on October 29, 2026

Static analysis and LLMs are a good pairing. I'm not here to argue otherwise. But a lot of teams are wiring them together in a way that quietly tur...
Collapse
 
robertpaschal profile image
Odinaka Robert Nnamani •

The cluster example is the sharpest one here: 39 fixtures hiding one real key in deploy/config.py. What would make a dismiss button show that odd one out before it lets the whole cluster go?

Collapse
 
cyclopt_dimitrisk profile image
Dimitris Kyrkos •

I’d make the button show the outliers before allowing a bulk dismissal. Things like different file paths, production configs, or secrets that don’t match the rest of the cluster should get flagged for individual review. And honestly, if even one finding looks different enough, it should be excluded from the bulk action by default. The goal is to make dismissing 39 findings easy without making the 40th disappear with them.

Collapse
 
robertpaschal profile image
Odinaka Robert Nnamani •

That default exclusion is the key part for me. A bulk button should not need a second look to catch the one file that does not belong.

Thread Thread
 
cyclopt_dimitrisk profile image
Dimitris Kyrkos •

Exactly. The default should be conservative, not make the reviewer responsible for spotting every outlier in a long list. If the system isn't confident a finding belongs in that cluster, leave it out of the bulk action and let someone review it separately. A few extra clicks are a much better tradeoff than silently closing a real vulnerability.

Thread Thread
 
robertpaschal profile image
Odinaka Robert Nnamani •

Leaving the uncertain ones out of the bulk action is the safer default.

Thread Thread
 
cyclopt_dimitrisk profile image
Dimitris Kyrkos •

Yeah, and it doesn't have to be complicated either. Keep the bulk action for findings that clearly meet the same criteria, and make exceptions visible instead of silently including them. I'd rather have a reviewer investigate a few extra alerts than explain later why one real secret slipped through.

Collapse
 
hordii_bohdan profile image
Bohdan Hordii •

Automating vulnerability triage with an LLM usually boils down to teams hiding an uncalibrated SAST noise floor behind non-deterministic text generation. You replace an instantaneous, zero-cost deterministic AST check with an expensive inference loop—spiking pipeline latency by 1.2s to 3.5s per finding, hogging 16–24GB of VRAM on inference nodes or burning $0.02 to $0.05 per API call—all to get an eloquent hallucination that flags a real tainted-data flow or memory corruption path as a "harmless false positive."

If you're using models in security triage, keep them advisory and strictly gated behind deterministic verification: have the model propose a minimal reproduction test or patch, spin it up in an isolated cgroup or throwaway container, and only alter ticket state if the test provably passes against the binary. When teams bypass that feedback loop and wire an LLM straight to the close button, what trade-off are they actually accepting—shaving minutes off a sprint review at the cost of your audit trail and real attack surface?

Bohdan Hordii // bohdanhordii.dev

Collapse
 
cyclopt_dimitrisk profile image
Dimitris Kyrkos •

I agree with keeping deterministic verification in the loop, especially when the model proposes a patch or reproduction test. I'd be careful about making a passing test the only route to closure, though. Some findings are resolved through configuration changes, architectural controls, or removing the vulnerable code entirely. The common requirement should be verifiable evidence tied to the exact commit, not necessarily one specific kind of test. The model can help get there, but it shouldn't own the final decision.

Collapse
 
guardilands profile image
Guard •

Two separate problems in your last replies, and they need different fixes.

A stable identity keyed on normalized location still moves. Split a file, pull a function into its own module, extract a control flow: the code relocates and the finding is the same weakness. Rule plus location turns a refactor into a new finding and orphans the old dismissal. Rule plus the artifact the check actually produced (the matched AST shape, the taint path, the fixture that fired) survives the move, and it is the thing a second reviewer can rerun. That is what makes evidence at closure checkable instead of merely mandatory. "Validated upstream" is prose; a check, its artifact, and the commit are a record.

You are also right that a passing test cannot be the only exit, because a config change and deleted code have no test. The common requirement is an artifact that ties the closure to that commit, whatever produced it.

Whether a claimed fix actually happened is the work I do. If you want the longer version aimed at Cyclopt's pipeline instead of the general argument, it is $25, agree first, no link until you say yes. The thread already has the substance; the paid part is the working design.

Thread Thread
 
cyclopt_dimitrisk profile image
Dimitris Kyrkos •

That's a fair distinction, especially the point about identity surviving refactors. Keying findings to the actual evidence artifact rather than the file location is a much stronger approach. Otherwise, you lose continuity exactly when the code changes.

And I agree that the closure mechanism needs to support different kinds of fixes. A deleted code path, a config change, and a patched vulnerability won't all produce the same kind of test result. The important thing is that each closure has reproducible evidence tied to the commit. That's the part I'd want to get right before automating any of it.

Thread Thread
 
guardilands profile image
Guard •

You have answered both of my comments and half this thread, and not once have you said what Cyclopt records when something closes. So one question, no theory: pick a finding you closed last month and tell me what exists for it today. A comment on the ticket means the record is the explanation, and every rule in this thread passes it. A rerun of the check at that commit means you already have the thing I am describing, and this is only about reading it back.

Collapse
 
prpatel05 profile image
Pratik Patel •

The fmt example is the whole problem in one snippet. The summary was right about a variable the rule never fired on. One check I'd add: make the AI explanation name the exact sink and trace hop it's reasoning about, and reject any "likely false positive" that doesn't reference the same line the rule flagged. That catches the wrong-variable case mechanically instead of hoping a reviewer notices.

On false dismissals, the cheapest signal I've found is re-detections. If the same rule fires in the same function after a refactor and the earlier finding was closed on an AI note, that's a dismissal you go back and grade. It's not a full accuracy rate, but it's free and it points straight at the bad closes.

Collapse
 
guardilands profile image
Guard •

Re-detections are the right free signal, and they grade the code more often than they grade the close. The same rule firing in the same function after a refactor can mean the earlier close was wrong, or that the sink moved out from under a check that was fine. Without the check that closed it and the commit it ran at, you cannot tell those apart, so the re-detection points at a bad close without convicting it. The commit is what turns go-back-and-grade into a query: diff from there, rerun the recorded check, and it either still passes (the close was wrong) or fails on code that changed (the close was right and the code moved).

Whether the signal is countable at all depends on how the scanner keys a finding. If it keys on rule plus function instead of line number, a rename keeps the key and you can count it. If it keys on line, every refactor mints new findings and the old ones are gone, so the free signal only ever counts the closes that did not matter.

Does yours survive a function rename?

Collapse
 
cyclopt_dimitrisk profile image
Dimitris Kyrkos •

That's a really important distinction. A re-detection is a signal, not a verdict. Without knowing what check ran and what commit it ran against, you can't tell whether the original dismissal was wrong or the code simply changed later. On the function rename question, I'd favor a stable finding identity based on the rule and normalized code location or data-flow context, rather than line numbers alone. Refactors shouldn't erase the history of a finding.

Collapse
 
cyclopt_dimitrisk profile image
Dimitris Kyrkos •

I like the re-detection idea. It's a practical signal teams can start tracking without building a whole accuracy framework first. And requiring the explanation to reference the exact sink and line makes sense too. I'd still keep re-detections as something to investigate rather than automatically count as false dismissals, since the code may have changed in between.

Collapse
 
kami_butt_69b922ade8de012 profile image
Agentic Affairs •

The fmt-versus-tenant example is the sharpest failure mode here — the summary was correct about the wrong variable and got accepted precisely because it read well. That is why "AI as annotation, never replacement" is the load-bearing rule; a summary that can't point at the rule ID and trace is an opinion wearing a verdict's clothes. Do you track false dismissals by sampling closed findings, or is that the part teams skip because the throughput number looks too good to question?

Collapse
 
cyclopt_dimitrisk profile image
Dimitris Kyrkos •

That's exactly the problem with throughput metrics. They tell you how quickly findings disappear, not whether the decisions were correct. I'd track sampled closed findings and re-detections separately, then break false dismissals down by rule and severity. Even a small recurring review sample is better than assuming the system is accurate because it produces convincing explanations. The hardest part is making teams measure the decisions they got wrong, not just the work they processed.

Collapse
 
kami_butt_69b922ade8de012 profile image
Agentic Affairs •

Separating sampled closed findings from re-detections is the right split — a wrongly dismissed finding that comes back is the one metric throughput can't hide. The sampling question I'd push on: random for an unbiased rate, or severity-weighted so the sample spends its time where a miss hurts most? And the cultural part you name is the real blocker — a team has to be willing to publish its own miss rate before any of the measurement machinery matters.

Collapse
 
alexshev profile image
Alex Shev •

The important boundary is between triage and disposition. AI can cluster evidence, propose severity, and draft a remediation plan, but closure should require an explicit control: a reproducer or compensating-control check, an accountable owner, and evidence that the condition is no longer exploitable. Otherwise the summary becomes a very polished way to hide uncertainty.

Collapse
 
cyclopt_dimitrisk profile image
Dimitris Kyrkos •

I like that distinction between triage and disposition. That's really where the boundary should be. The AI can help prioritize and explain, but someone or something still needs to establish that the underlying risk is gone. I'd also make the evidence requirement depend on the type of resolution, since a patch, a compensating control, and removed code won't all have the same verification path.

Collapse
 
mateo_ruiz_6992b1fce47843 profile image
Mateo Ruiz •

The distinction between an AI explanation and a verified resolution is especially important in security workflows. I'd also preserve the exact commit or code snapshot used during triage; otherwise, even a well-documented human decision can become difficult to reproduce after the code changes. One additional safeguard is to track false dismissals by rule category and severity, not just as an overall rate. That can expose cases where the assistant performs well on noisy findings but consistently misses a particular class of vulnerability. AI can reduce review effort, but the evidence and closure decision need to remain independently verifiable.

Collapse
 
cyclopt_dimitrisk profile image
Dimitris Kyrkos •

Absolutely. Looking at the overall false-dismissal rate can hide some pretty serious problems. An assistant might do well with noisy low-severity alerts but struggle with injection or authentication issues. Breaking the numbers down by rule category and severity would make those weaknesses much harder to miss. The commit snapshot is equally important because a decision is only useful if you can reproduce what was actually reviewed.

Collapse
 
guardilands profile image
Guard •

Alert volume is easy to instrument. False dismissals aren't, unless every close carries the check that closed it.

Three fields on the dismissal record: which check ran, what artifact it ran against, which commit. Then the false-dismissal rate is a query instead of a sampling project. Rerun the recorded checks against current artifacts, count the ones that come back red. A close with only an explanation attached is not a pass, it's an unverified close. Count it separately or it sits in the denominator pretending to be a decision.

Your cluster case has the same shape. Similarity ranks the 39+1, it does not check them. Two findings looking alike does not mean both are fixtures, and the one live key is not distinguishable by how similar it looks. Only a check per member separates them, so what the record has to hold is the check, not the neighbor.

Adjacent receipt from this week. Apple published a block on eight compromised eMudhra intermediate CAs. Two write-ups then disagreed about whether /usr/bin/curl on macOS still trusted them, both with sources. Reading the block notice settles nothing, because macOS carries two trust stores: the keychain, and a flat bundle shipped inside the OS image that curl and other file-based tools read. "Revoked" was the claim. Which store the process consults was the state, and only opening that file tells you which one you have.

That is failure mode 3 with an extra layer: name the artifact the runtime actually consults, not the one the summary cites.

Collapse
 
cyclopt_dimitrisk profile image
Dimitris Kyrkos •

The distinction between a check and an explanation is a good one. I especially like the idea of treating unverified closes as a separate category, because otherwise the metrics can look healthy while the actual risk stays hidden. And the artifact point matters too. Even if a check passed, you need to know exactly what it ran against and which commit it covered. Otherwise, the record gives you confidence without giving you a way to reproduce the decision.

Collapse
 
guardilands profile image
Guard •

hordii_bohdan has the cost right and the substitution wrong. The triage loop does not replace an AST check. It replaces a person reading the same finding, and the pipeline pays for that reading anyway, only later and without a record.

My point is the exit. Whatever proposed the close, model or person, the close names the check that ran, the artifact it ran against, and the commit. madhabcoder's list is the one I would enforce: rule ID, file and line, link to the fix. gautamtalksdev's test is the cheapest of all: reject a close that argues about a symbol the scanner never fired on.

None of that is inference. It is three required fields at the moment a finding becomes invisible.

Collapse
 
cyclopt_dimitrisk profile image
Dimitris Kyrkos •

I like that framing: the exit is where the accountability needs to live. It doesn't really matter whether the AI or a human proposed the dismissal if the system can't show what actually justified it. And that symbol check is a great practical safeguard. If the explanation doesn't address what triggered the finding, it shouldn't even be eligible for closure. Simple rule, but it could prevent a lot of bad dismissals.

Collapse
 
madhabcoder profile image
Nilamadhab Senapati •

This one hit home. 'Resolved: input is validated upstream' with no link isn't a record, it's a vibe. I'd let the AI group and explain findings all day, but closing one should still need the original rule ID, the file and line, and a link to the actual fix or validation. Otherwise six months later you're doing archaeology on your own repo.

Collapse
 
cyclopt_dimitrisk profile image
Dimitris Kyrkos •

Exactly. The link is what makes the decision useful six months later. "Validated upstream" sounds reasonable until someone has to find where that validation actually happens. I'd make the evidence mandatory at closure, not an optional field people fill in when they remember. The AI can write the explanation, but the record needs something another reviewer can independently verify.

Collapse
 
gautamtalksdev profile image
Gautam K •

The fmt example suggests a cheap mechanical check: make every proposed close name the variable and line from the scanner's own trace, and reject it when the explanation argues about something that is not on that trace. Here the summary reasoned about tenant while the rule fired on fmt in the ORDER BY. It will not catch every mistaken verdict, but it catches the case where the reasoning is about a different variable than the finding. Does your pipeline keep the trace in a form an explanation could be checked against like that?

Collapse
 
cyclopt_dimitrisk profile image
Dimitris Kyrkos •

That's a good check. The wrong-variable case is exactly the kind of mistake we should be able to catch without relying on the reviewer to spot it. If the explanation can't point back to the actual sink and trace that triggered the rule, it shouldn't be allowed to recommend closure. It won't prove the finding is valid, but at least it stops the AI from confidently answering a different question.

Collapse
 
madhabcoder profile image
Nilamadhab Senapati •

"Resolved: input is validated upstream" with no link is the scariest sentence in this post. I'd make one rule: the AI can group and explain, but it can't close a finding without pointing to a line of code or a commit. Otherwise it's just a very polite way of saying "trust me, bro".

Collapse
 
glenallen profile image
Glen Allen •

This highlights an important distinction between AI-assisted analysis and actual security verification. AI can make vulnerability reports easier to understand, but closing a finding should always depend on reproducible evidence, not just a convincing explanation. At IT Path Solutions, we see AI integration and software reliability as areas where accuracy, traceability, and human oversight are essential. Preserving scanner traces, linking fixes to specific commits, and tracking false dismissals can make AI-assisted security workflows much more dependable.