12 October 2026

What to Do With a Security Finding You Are Not Going to Fix

What to Do With a Security Finding You Are Not Going to Fix
11 min. readBy Borg

A security queue has two halves. There is the work you are going to do, and there is everything else. Most advice covers the first half. The second half, the findings someone reads and decides not to act on, often has no process at all, and that is how the same issue gets raised on three consecutive pull requests, and how a decision made deliberately in March reads like an oversight in September.

Deciding not to fix something is a legitimate engineering decision. It mostly needs to be recorded as one.

Three decisions that look identical in a queue

When a finding is closed without a code change, one of three quite different things has usually happened, and teams often record all three the same way.

The first is that the finding is wrong. The behaviour described does not exist, or the code path is not reachable the way the report assumes. This is a claim about the finding itself.

The second is that the finding is right and the risk is being accepted. The behaviour is real, the team understands what it allows, and they have decided the exposure is tolerable relative to the cost of changing it. This is a claim about the business, not about the code.

The third is that the finding is right and it is not being done now. Nothing has been accepted. The work is queued behind other work.

These three need different records because they expire differently. A false positive is a durable statement: if the analysis was wrong today it is probably still wrong next quarter, unless the code changed. An accepted risk is a decision with a shelf life, because the thing that made it tolerable, low traffic, an internal-only endpoint, a small blast radius, can change without anyone revisiting the note. And "not now" is not a decision about risk at all; it is a scheduling position that should be visible as one, so it does not quietly turn into permanent acceptance through neglect.

Collapse them into a single "closed" state and you lose the ability to ask the only question that matters later: which of these should we look at again, and why.

What each decision should actually record

The useful test is whether someone who was not in the conversation can reconstruct it in six months.

For a false positive, record what specifically is wrong with the finding. "Not exploitable" is not a record, it is an assertion. "This route is behind an internal load balancer that does not accept external traffic, and the report assumes it is public" is a record, and it is one a reader can check and, importantly, notice has stopped being true when the route gets exposed.

For an accepted risk, record the condition that makes it acceptable rather than the conclusion. "Accepted" tells the next reader nothing. "Accepted because this endpoint is only reachable by staff accounts and there are eleven of them" names the fact the decision rests on, which means the decision has something to fail against.

For "not now", record what it is behind and roughly when it comes back. This is the weakest of the three records and the one most often skipped, and it is also the one that most reliably degrades into an accepted risk that nobody ever consciously accepted.

Two dimensions of the finding itself bear on which of the three you are in. One is how the issue was established, which is worth checking before reaching for the first option. Borg's docs describe three confirmation types on findings Mjolnir raises: Exploited, where the attack was run end to end and shown to work; Partial, where there is evidence the issue is real but no working exploit; and Static, where the issue was confirmed by reading source code without running an attack. A finding marked Exploited is a considerably harder thing to call a false positive than one marked Static, because the disagreement is no longer about interpretation of code, it is about an observed outcome. Findings raised by hand by Borg's analyst team carry no confirmation type at all.

The other dimension is severity, which the docs anchor to a CVSS base score across Critical, High, Medium and Low. Severity tells you how much the decision costs if it is wrong. It does not tell you which of the three decisions you are making, and the two get conflated often enough to be worth separating: a Low finding can still be a false positive, and a Critical one can still be an accepted risk if the team genuinely understands what they are accepting.

How the three map onto a finding's status

In Odin, a finding moves through a status lifecycle that is split deliberately between what Borg sets and what the customer's team sets. Per Borg's documentation, Borg sets Reported when a finding is published and awaiting triage, Needs Revision when a retest shows the fix is insufficient or has introduced something new, and Fixed & Retested when remediation has been verified. The team sets the rest: Mitigating while remediation is in progress, Open for Retest once a fix is applied and verification is wanted, and Acknowledged, which the docs define as having seen the finding and accepted the risk for now, without active remediation.

That split matters for the three decisions above. Acknowledged is the state that carries an accepted risk, and it is reversible: the documented transitions allow Acknowledged to move back to Mitigating, and allow a finding to be acknowledged from Reported, from Mitigating, or from Open for Retest. So the product treats acceptance as a position a finding can sit in and later leave, rather than as a closure.

A status change can carry a comment, and the docs note that Borg sees the comment alongside the status change in the activity timeline. That comment is the natural place for the record described above, and it is worth treating as mandatory by team convention even though the product treats it as optional. A status change with no comment is the disposition without the reasoning, which is the thing that decays.

Worth knowing who can do this: the docs restrict status changes to Member, Admin and Owner roles, so a read-only account cannot move a finding. Status changes also show an undo action immediately afterwards, which is a small thing that matters when the wrong row gets clicked.

One honest limitation. Nothing above distinguishes "accepted risk" from "not now" at the level of the status itself, because Acknowledged is one state and those are two different intentions. That distinction has to live in the comment and in whatever review habit the team builds around it. If it matters to your team to tell them apart at a glance, the tracker you already push findings to is probably the better place to encode it, which is a reason to keep findings flowing into Linear, Jira or GitHub rather than managing the whole lifecycle in one tool.

A recurring pattern is a different problem from a single finding

Everything above concerns one finding and one decision. There is a second case that looks similar and needs a different instrument: a pattern that is going to be raised again and again, correctly, because it genuinely exists and the team has decided it is fine.

The usual examples are unglamorous. Raw HTML rendering in a static site generator, which is the entire point of the component. Weak crypto in test fixtures that exist to exercise the weak path. A legacy directory nobody is going to refactor this year. In each case, marking individual findings as acknowledged works, and it works badly, because the same judgement gets re-litigated on every pull request that touches those files.

For PR review specifically, Borg documents suppression rules for this. A rule stops the PR review agent raising a given pattern, and the documented fields are a scope, either a single repository or the whole organisation, a vulnerability category such as injection or authorisation, a specific vulnerability type within it such as sql-injection or idor, an optional file glob such as tests/**, and a reason. The reason field is required, and the docs say it gets shown to teammates reviewing the rule, which makes it the closest thing in the product to an enforced version of the record-keeping argued for above.

Rules can be created by hand, or learned. The docs describe auto-learned rules: when a team dismisses the same suggestion across multiple pull requests and auto-suppression has been enabled in the Mjolnir configuration, a rule is created automatically once a threshold is reached. Each rule shows its source, so manual and auto-learned rules are distinguishable in the list. Rules can be filtered by source and status, disabled without being deleted, or deleted outright, after which matching findings are raised again on the next pull request.

Two of Borg's own documented recommendations are worth repeating because they are the ones teams skip. Prefer a narrow scope: a repository-scoped rule with a file pattern, suppressing sql-injection in tests/** rather than everywhere, keeps the same pattern flagged in production code. And prefer disabling a rule to deleting it when you are unsure, because a disabled rule can be switched back on.

Note the boundary. Suppression rules apply to the PR review agent, which reviews the diff. They are not a general mute button across every finding in the platform, and a full-application assessment is a different surface with a different review path. If you want the distinction between those two surfaces in detail, it is covered in full pentest versus PR security review.

Comparing the four routes

RouteWhat it claimsWhat it should recordWhen to revisitHow it fails
Dispute as false positiveThe finding is wrongThe specific assumption that does not holdWhen the relevant code or exposure changesUsed as a shortcut for "I do not want to deal with this", especially on findings that were actually exploited
Acknowledge, accepting the riskThe finding is right, the exposure is tolerableThe condition the tolerance depends onOn a fixed cadence, and whenever that condition changesThe condition changes quietly and nobody re-reads the note
Acknowledge, deferring the workThe finding is right, other work is ahead of itWhat it is behind and when it returnsAt the next planning cycleIndistinguishable from acceptance after a few months
Suppression rule (PR review)This pattern will keep appearing and is intentional hereScope, type, file pattern and a written reasonPeriodically, and the docs specifically flag auto-learned rulesScoped too broadly, so it hides real instances in production code

Borg's own row is the suppression rule, and its failure mode is real rather than hypothetical: an organisation-wide rule with no file pattern will suppress the pattern everywhere, including the code you care about most. The narrow-scope recommendation in the docs exists because of exactly that.

The failure mode that is worth naming

The risk in all of this is not that a team suppresses too little. It is that dismissal becomes the path of least resistance and the queue gets quieter for reasons unrelated to the software getting safer.

Borg's documentation is unusually direct about one version of this. On auto-learned suppression rules, it advises reviewing them periodically, on the grounds that they are created from real dismissal patterns but can encode bad habits if a team is over-dismissing. That is worth sitting with, because it describes a mechanism rather than a personal failing: a feature that learns from behaviour will faithfully learn from careless behaviour too, and the output looks identical to a well-tuned configuration from the outside.

The practical guard is a review habit rather than a control. Some teams re-read acknowledged findings at a fixed interval. Others tie the review to a change in the thing the acceptance depended on, which is more precise but only works if the condition was written down in the first place, which is the argument this whole piece rests on. Either is better than the common state, which is that nobody has looked at the acknowledged list since it was created.

One more thing worth watching. If a finding is acknowledged and the underlying code later changes, the acceptance may no longer describe reality in either direction: the issue may be gone, or it may have become considerably easier to reach. A fix that lands for unrelated reasons can be verified through the normal path, since an automatic retest reviews the merged change when a finding is linked to the pull request, but a finding sitting in Acknowledged is not waiting on a retest, so nothing prompts that check. It is worth a look whenever the surrounding code moves.

Where this does not help

This is a record-keeping and review argument, and it has clear limits.

It does not tell you whether a given risk should be accepted. That judgement depends on what the system does, who uses it and what the organisation is prepared to carry, and none of that is a security-tooling question. What the practice above does is make the judgement legible later, and make it possible to notice when its basis has expired.

It also does nothing about findings nobody has read. A disposition process operates on findings that reached a human and got a decision. If findings are arriving faster than anyone is triaging them, the queue will keep growing whatever the disposition hygiene looks like, and that is a capacity or a routing problem rather than a process-design one.

And it is not a substitute for fixing things. Every route described here leaves the behaviour in place. Three of the four leave it in place deliberately and with a record, which is better than leaving it in place by accident, but a well-documented accepted risk is still an accepted risk.

Frequently asked questions

What is the difference between a false positive and an accepted risk?
They are claims about different things. Calling something a false positive says the finding itself is wrong: the behaviour is not present, or the code cannot actually be reached in the way described. Accepting a risk says the finding is correct and the team is choosing to live with the exposure. The practical consequence is that they age differently. A wrong analysis stays wrong until the code changes, whereas an acceptance rests on some condition holding, so it can quietly stop being true without anyone touching the finding.
Should a finding be acknowledged or suppressed?
Acknowledging suits a specific finding you have judged and decided to live with for now. A suppression rule suits a pattern you expect to be raised repeatedly and correctly, such as weak crypto inside test fixtures. The distinguishing question is whether you are ruling on one instance or on a class of them. Note the scope difference too: suppression rules in Borg apply to the pull-request review agent rather than acting as a general mute across the platform.
What should we write down when we decide not to fix something?
Write the condition the decision depends on, not the conclusion. A note saying a finding was accepted tells a later reader nothing they can act on, while a note saying it was accepted because the endpoint is reachable only by a handful of staff accounts gives them something that can visibly stop being true. Borg's docs allow an optional comment on a status change and show it to Borg in the finding's activity timeline, and it is worth treating that comment as compulsory by team convention.
Can a finding that has been accepted be picked up again later?
Yes. Borg documents Acknowledged as a position a finding occupies rather than a closure, and the permitted transitions let it move back into active remediation. A finding can also be acknowledged from several earlier states, including while remediation is already under way. Permissions are limited: only members, admins and owners may change a status, and read-only accounts cannot. An undo action appears straight after any change.
How do we stop the same pattern appearing on every pull request?
That is what suppression rules are for. Borg's documentation describes rules scoped to one repository or the whole organisation, targeting a vulnerability category and type, with an optional file glob and a mandatory written reason that teammates can read. Rules can also be learned automatically from repeated dismissals once that setting is switched on. Borg's own guidance is to keep the scope narrow, so a rule covering a test directory does not also hide the same pattern in production code.

Borg on
Social Media

Borg specializes in securing complex, high-risk digital systems.