Triage at 6,240 Results with Two Champions
After a three-week scan of a 1.1M-line .NET solution, CxSAST returns 6,240 results: 4,870 To Verify, 900 Confirmed, and 470 Not Exploitable, mostly from a legacy module. Two security champions support 25 developers across four feature teams. An audit of last quarter found that of 1,900 results closed as Not Exploitable with the comment false positive, 140 were genuine vulnerabilities, including 11 SQL injections. The new policy says every Not Exploitable needs a category (test code, unreachable, sanitized, third-party, other) plus a one-line proof, and a second reviewer for High and Critical. The release is in three weeks; the product owner wants a burn-down to zero and has asked the champions to clear To Verify in bulk by Friday. The champions have 60 person-hours available before the release.
1. Design a triage order for the 4,870 To Verify results and explain why severity-only ordering is insufficient.
Read the worked answer
Order by reachability and change, not severity alone. With 4,870 results and two champions, the only tractable scope is new and changed code in the release plus existing Critical/High in internet-facing components. Concretely:
- Filter results to files changed on the release branch and triage those first; that is the code that can introduce a new vulnerability this cycle.
- Among untouched code, rank by exposure: public endpoints, authentication, file upload, SQL sinks, deserialization. Use the result's source and sink and component ownership.
- Group by best fix location and root cause; 37 results in one helper method are one fix, not 37 reviews.
- Delegate component-specific triage to team leads with a one-page guide, with the champions reviewing High and Critical.
- Put known-noisy queries under query tuning only after sampling proves the noise is systemic and the decision is documented.
Severity-only fails because a Critical in an unreachable admin console is lower priority than a High on a public login path, and because 900 Confirmed results may include stale duplicates. It also ignores effort: a single sanitizer gap can explain hundreds of results.
2. The product owner wants To Verify cleared in bulk by Friday. What is wrong with that, and how would you handle the 470 existing Not Exploitable results?
Read the worked answer
Bulk-closing To Verify as Not Exploitable is not triage; it converts unknown risk into invisible risk and explains the audit failure. Not Exploitable should mean someone inspected the path and proved a blocker: the sink is unreachable, the data is constant, a recognized sanitizer runs on every path, or the code is test-only and not shipped.
For the 470 existing results, sample stratified by query, component, and age. Re-open any without a category and proof, and require the second reviewer for High and Critical. Check whether the 140 misses cluster in one query or one legacy module; if they do, re-open that cluster entirely. The legacy module can be marked unreachable only with evidence: no route, no scheduled job, no reflection entry point, and a review date. Do not re-open all 470 blindly without capacity, but do not let them stay closed without proof either. Track reopened Not Exploitable results as a quality metric for the triage process itself.
3. What metrics and reporting would you give the product owner instead of a burn-down to zero?
Read the worked answer
Replace the zero target with release-risk metrics:
- Untriaged new Critical and High results on changed files: target zero before release.
- Confirmed open findings by severity and age, with mean time to remediate.
- Not Exploitable audit pass rate from a 10% sample.
- Reopened Not Exploitable count by reviewer.
- Confirmed density per KLOC, trended across releases.
Report accepted risk explicitly: a short list of deferred items with owner, rationale, and expiry date, signed by the product owner. Zero is unattainable because false positives and accepted risks are legitimate states, and a zero target incentivizes bulk closing. Present the burn-down as new High/Critical triaged and fixed, plus legacy backlog aging, not total count. Also report scan coverage, including projects scanned and failed scans, because an empty result set can mean a broken scan rather than a clean application.