The Risk Rancher Field Manual, Ch. 8: Accepting Reality
Part of The Risk Rancher Field Manual, a hands-on guide to starting, scaling, and running a vulnerability management program.
Not every finding gets fixed, and not every finding gets fixed on time. Anyone who tells you otherwise is running a program on a slide, not inside a real company with deadlines and legacy systems and humans. The mark of a mature program is not zero unfixed findings. It is that every unfixed finding is unfixed on purpose, on the record, and on a clock.
There are two disciplined ways to say “not now.” The exception, for a thing that will not be fixed. The extension, for a thing that will, just later. We will file one of each, on findings from the queue you already built, and you will leave with an exception log that has two rows in it and the one rule that makes the whole practice honest: you do not sign.
The exception: accepting the risk
Look at F010 from your triage: TLS 1.0 on legacy-billing, a P2. You cannot meet the 14-day clock, because sample-assets.csv tells you the real fix is a six-month application refactor. The host is hardcoded to old cipher suites. This is not laziness; it is a genuine constraint, and it is exactly what an exception is for.
Two rules make that decision honest instead of a cop-out.
First, you do not get to accept it. You are the security person. You lay the risk out plainly, what it is, what could happen, how likely. The business owner, the person whose business runs on the asset and who will personally eat the consequences, is the one who signs. That is a different person from the owner in chapter two, who is whoever can change the asset; for legacy-billing the fixer is the Finance team’s engineers and the signer is the head of Finance. Not you. This is not you dodging responsibility; it is you refusing to quietly carry a risk that is not yours to carry.
Second, it goes in writing, with a reason and a date. Here is F010 filed in exception-log.csv, which ships with this one row so you can see the shape:
| field | value |
|---|---|
| id | F010 |
| asset | legacy-billing |
| finding | TLS 1.0 / weak ciphers enabled |
| priority | P2 |
| reason cannot fix now | Fix requires a six-month application refactor; cannot meet the 14-day SLA. |
| compensating control | Restrict the billing host to the internal finance VLAN; alert on any external connection attempt. |
| business owner | the head of Finance, whose invoicing runs on this host |
| approved date | 2026-10-14 |
| expiry date | 2027-04-14 |
| status | open |
As it sits in the file:
id,asset,finding,priority,reason_cannot_fix_now,compensating_control,business_owner,approved_date,expiry_date,status
F010,legacy-billing,TLS 1.0 / weak ciphers enabled,P2,Fix requires a six-month application refactor; cannot meet the 14-day SLA.,Restrict the billing host to the internal finance VLAN; alert on any external connection attempt.,Finance owner,2026-10-14,2027-04-14,open
Read the row. The reason is specific. The compensating control is the thing you do instead of the fix to shrink the risk while it stands. Here it is walling the billing host off on its own network segment, a VLAN, so only Finance can reach it, and alerting if anything else tries. If you cannot name one, the risk is probably too big to accept. The expiry is six months because that is when the refactor is due; an expiry should be tied to the reason, not picked from the air. An exception tracked in an email thread is how you fail an audit, because the day someone asks who accepted this and why, you are spelunking through Slack. An exception with an owner’s name, a reason, a compensating control, and an expiry is how you pass one.
Exceptions expire
Here is the detail that separates a program from a graveyard: an accepted risk is not a closed finding. It is a deferred one, and it gets an expiry. Notice the dates in the row above, approved today, expires in six months. When the timer runs out, F010 comes back onto the active queue and the Finance owner has to look at it again with fresh eyes. By hand that is a calendar reminder; in the tool it is a date on the finding, and the tool brings it back on that date.
The world changes. The patch that did not exist now exists. The app that could not be touched got refactored last quarter. An exception that never expires is just a vulnerability you agreed, in writing, to forget, and forgetting is the exact opposite of the job.
Not now, on the record, on a clock. The expiry is what keeps an accepted risk from becoming a forgotten one.
The extension: more time
The lighter cousin. IT is going to fix it, they just need more runway. Take F027, the SQL query built by string concatenation on customer-db, a P2 with a 14-day clock. Suppose the team says the fix is in the next sprint, which lands eight days late. That is not an exception, the fix is coming, they just need the time. Grant it, record it, set the new date: due pushed from day 14 to day 22, acknowledged and signed. Log it in the same file as the exception: the reason is the delay, the compensating control can be “none, fix in progress,” the expiry date is the new due date, and the status is extended. The only difference between an extension and simply blowing the SLA is that one is dated and the other is silence, and auditors can tell the two apart instantly. Cap them, too: a second extension on the same finding should take a harder conversation than the first, and a third should not exist.
Try it. File your own two. F010 is already in exception-log.csv; rewrite its compensating control to one you would actually stand behind, then pick one P2 or P3 from your queue, decide it needs two more weeks, and log it as a dated extension. If you cannot name a compensating control for the exception, that is a signal the risk may be too big to accept, which is the log doing its job.
In the tool, the owner asks from their link, for more time or for the risk to be accepted, with a reason; the business owner gets a link of their own and signs or refuses there. Extensions are counted against the cap in your policy and a request past it is refused, not quietly granted. An accepted risk is held in its own state with the signer’s name and the expiry next to it, and when the expiry passes the next upload or restart puts it back on the queue. Every step lands in the audit log, the tool’s record of who did what and when. You can do all of it by hand with the CSV above and a calendar reminder, and you should understand the process cold, because the discipline is what matters, not the thing that runs it.
The paper trail is the maturity
Exceptions and extensions are where your program meets reality, and, not coincidentally, where auditors meet your program. Done right, they turn “we did not fix it” from an embarrassing gap into a documented, owned, time-boxed decision. That is the difference between a team that is managing risk and a team that is hoping.
Look at what you have done with one sample file across three chapters: you triaged 29 raw findings into a ranked queue, turned the top one into a ticket with a verify step, and just deferred two more with an owner and an expiry, all of it on the record. That is the operating loop, by hand, start to finish. You know how every piece works because you ran each one yourself. Which means you have earned the right to stop doing the repetitive parts by hand. One short chapter first, to name every state a finding passes through, and then Part 4: scaling, and how to put the robot work down.