Skip to content
Satya Prakash Solanki

Finding vulnerabilities is the easy half of application security. Scanners are good at it, and a mature programme will find more issues than any team can fix in a sprint. The hard half is getting each real issue to an owner, fixed within a sensible time, proven fixed, and kept fixed.

Most programmes I have looked at measure the first half well and the second half poorly. Tickets are closed when a developer marks them done. Nobody checks whether the next scan agrees. Six months later the same issue returns under a new ticket number, and the dashboard counts it as a new success.

This article describes the remediation loop I design for an application security programme: routing, SLAs, verification, regression protection and the metrics that tell you whether the loop is working. I mark it “working” confidence because the metrics section in particular is still evolving in my practice.

  1. 01Detect
  2. 02Route to owner
  3. 03Fix within SLA
  4. 04Verify by re-scan
  5. 05Add regression test
  6. 06Report
Figure 1. The remediation loop. Verification is the step most programmes skip.

Ownership routing

A finding without an owner is a finding nobody will fix. Routing has to be automatic, because manual assignment does not scale past a few hundred findings.

I route on the most specific signal available:

  1. Code ownership files (for example CODEOWNERS) for SAST and secret findings, using the file path.
  2. Service catalogue entries for SCA, container and IaC findings, using the repository, image or infrastructure module.
  3. Endpoint-to-service mapping for DAST, API and penetration test findings, using the host and path.
  4. A named fallback owner per product area when none of the above match. The fallback owner’s job is to fix the mapping, not the vulnerability.

Shared components are the hard case. A vulnerable library in a base image used by forty services should be one finding owned by the platform team that maintains the image, not forty tickets. That depends on deduplication and correlation being done well first, which I cover in Making security findings comparable across tools.

Routing also needs a feedback path. If a team believes a finding is not theirs, they reassign it with a reason, and repeated reassignment of the same pattern triggers a fix to the routing rule.

SLAs by priority

SLAs turn “please fix this” into a commitment that can be measured. I set them on priority, not raw severity, so that exploit likelihood and exposure are already accounted for.

Priority Typical basis Example SLA
P1 Known exploited, or confirmed exploitable on an exposed asset 7 days
P2 High severity with meaningful exploit likelihood or exposure 30 days
P3 High severity with low likelihood, or medium on exposed assets 90 days
P4 Low risk, hygiene Next planned maintenance, tracked

These are example values. The right numbers depend on release cadence, team capacity and regulatory context. What matters more than the exact numbers:

  • The clock starts at first detection, not at triage. Otherwise slow triage hides in good SLA figures.
  • SLAs are visible to the owning team in the tools they already use, with warnings before breach.
  • Breach has a consequence, usually a release gate failure for that service or an escalation to the engineering lead. An SLA without consequence is a suggestion.
  • Exceptions are explicit: a risk acceptance with an approver, a reason and an expiry, not a quiet extension.

Verification: fixed means a scan agrees

The central rule of the loop is simple. A developer can mark a finding as fixed. Only evidence can mark it verified.

Verification is targeted. Re-running the full scanning suite for every fix is slow and expensive, so the pipeline re-runs only what can confirm or refute the specific finding:

  • SAST: re-scan the affected repository at the fix commit with the original rule. The finding’s fingerprint must be absent.
  • SCA and container: rebuild, regenerate the SBOM, and confirm the vulnerable package version is gone from the artefact actually deployed, not just from the lockfile.
  • IaC: re-evaluate the policy against the changed resource, and ideally against the deployed state.
  • DAST and API: replay the original request sequence against the fixed build in a test environment and confirm the vulnerable behaviour no longer occurs.
  • Penetration test findings: a short re-test by the tester, or by someone with access to the original reproduction steps, recorded with evidence.

If verification fails, the finding returns to the owner with the new evidence attached. If it passes, the finding moves to verified with a link to the scan that proved it. That link is what an auditor wants to see.

Regression tests for fixed vulnerabilities

A verified fix can still regress. Someone reverts a commit, copies an old pattern into a new module, or pins a dependency back to unblock a build.

For each verified fix above P4, I ask for one form of regression protection, chosen to fit the finding:

  • A unit or integration test that exercises the vulnerable path with a benign malicious-looking input (for example, a quote character in a field that previously caused SQL injection) and asserts safe behaviour.
  • A custom SAST rule for patterns specific to the codebase. Semgrep makes this cheap: a rule that flags the exact unsafe call pattern that was fixed.
  • A dependency policy that blocks versions below the fixed one.
  • A DAST or API test case added to the automated suite for the affected endpoint.

This is where a QA background helps. A security fix without a test is the same as any other bug fix without a test: it is fixed until it is not. The OWASP Web Security Testing Guide is a good source of test-case ideas per vulnerability class.

Metrics that show whether the loop works

Counting open findings tells you very little. A falling count can mean good remediation or a scanner that stopped running. The metrics I rely on describe flow through the loop.

  • Mean time to remediate (MTTR), per priority, measured from first detection to verification, not to the developer’s “fixed”. I report median alongside mean, because a few very old findings distort the mean.
  • SLA adherence: share of findings verified within their SLA, per priority and per team.
  • Reopen rate: share of verified findings whose fingerprint reappears. A small rate is normal; a rising one usually means fixes are addressing symptoms or regression tests are missing.
  • Backlog age: distribution of open finding ages by priority. The tail matters more than the average.
  • Verification lag: time from “fixed” to “verified”. If this grows, the verification pipeline is a bottleneck.
  • Exception volume and age: active risk acceptances, and how many have been renewed more than once.

Open findings by age band (example)

Open findings by age band (example)
0 to 30 days120 findings
31 to 90 days64 findings
91 to 180 days31 findings
Over 180 days18 findings
Figure 2. Illustrative data, not a measured result. A backlog-age view makes the long tail visible in a way a single open count cannot.

I am still refining how to weight these into a single view for leadership. My current position is that one composite score hides too much, and three or four trends with a sentence of interpretation each communicate better.

Reporting for leadership and auditors

The same data serves two audiences with different questions.

Leadership asks: are we getting safer, and where is the risk concentrated? A monthly view works best with:

  • trend of open P1 and P2 findings, and SLA adherence;
  • the services or teams carrying the most aged high-priority risk;
  • active risk acceptances, with owners and expiry dates;
  • one or two decisions needed, such as funding a base-image upgrade that would close many findings at once.

Auditors ask: can you prove your process operates as described? They need evidence per control:

  • the documented SLA policy and its version history;
  • for a sample of findings, the full lifecycle: detection scan, routing, fix commit, verification scan and timestamps;
  • exception records with approvals and expiry;
  • mapping of activities to recognised frameworks such as the NIST SSDF (SP 800-218), whose practices include identifying, analysing and remediating vulnerabilities, and the OWASP ASVS for verification requirements.

If the loop is instrumented properly, both reports are queries rather than projects. That is the real test of the design: when an auditor asks for evidence on twenty random findings, the answer should take minutes.

Where this loop tends to break

A few failure modes come up repeatedly:

  • Verification capacity. DAST replays and pen test re-tests need environments and people. If verification is slower than fixing, the “fixed but unverified” queue grows and teams stop caring about the distinction.
  • Ownership drift. Teams reorganise and services change hands. Routing data that is not maintained becomes the main cause of SLA breaches.
  • Scanner changes. A scanner upgrade that changes fingerprints makes every open finding look fixed and every finding look new. Normalisation fixtures in CI catch this before it reaches the dashboard.
  • Gaming SLAs. Downgrading priority to escape a deadline. Priority changes should be logged and reviewed like exceptions.

Further reading

Application security & DevSecOps

Try “evaluation”, “red-teaming”, “governance” or “agents”.