In the last article, I outlined a problem. Likelihood × impact had become bullshit squared. We accepted risks because exploiting them would take too much effort. Or because nobody would bother. I spent years arguing about those decisions, while living with the fact that we couldn't fix everything.
My dad, of course, commented: "How do we fix this?"
Fair question, and thanks Dad.
This is my answer. Most of it isn't new. Segmentation, least privilege and short-lived access have been on every roadmap for twenty years. The problem was never the ideas. It was running them without grinding operations to a halt, and that is where I want to end up.
At the end, I'll say what I think you should do from your own lens, whether you sit on a board, run security or technology, or operate the systems. I'll also offer something I've been building to make the hard part of this easier, and ask for help breaking it. The argument first.
Low meant too much effort
When we rated a risk low, we were really answering two questions. How hard would this be? And who would bother?
Those were honest questions. They were also effort estimates. Finding the weak account, mapping what it reached, learning what our traffic looked like, staying quiet long enough to matter: all of that took a skilled person time. The rating was a bet that most attackers wouldn't spend it.
That bet is what AI has changed. Reconnaissance, config reading and path mapping are the parts of an attack that machines do well, and the tools to do them are getting cheaper every quarter. I'm not claiming attacks run themselves end to end. I'm claiming we can no longer assume that what is expensive for us to investigate is expensive for an attacker to exploit.
The rating didn't become wrong overnight. The assumption underneath it did.
Here are three acceptances I argued about more than once. I suspect you've signed at least one of them.
Every estate has one. A service account created for an integration that no longer exists, still used by a job nobody wants to touch, with more permissions than anyone can explain. We rated it low because working out where it was used and what it could reach would take someone weeks of trawling logs and configs.
The effort protecting it was ours. We couldn't afford the trawl, so we assumed the attacker couldn't either.
Give an attacker access to our documentation, config repositories and naming conventions, and much of that trawl can be automated. Those sources describe the paths better than our architects can.
The second one is about the network.
Lower-tier systems on a shared network, lightly separated from each other, because an attacker landing there would still need to know which hosts mattered and how to reach them.
I remember wrestling with host-based firewalling in the DSD Top 35 days. Managing iptables and network rules across an estate fifteen years ago was hard. We applied that level of restriction around privileged areas and accepted the rest.
A lower-tier system can hold nothing interesting and still provide a route to something that matters. We knew that. We rated the route low because finding it was work. It is less work every year.
The third is about detection.
We ran a tiered detection policy keyed to data sensitivity and system access. Strong coverage at the top, lighter coverage below. We built what we could afford, and the team was proud of it. So was I. I still am.
The assumption underneath it was that an attacker in the quiet tier would eventually do something loud enough to notice. On offence, DNS and ICMP tunnelling taught me how thin that was. Getting communications out was only part of it. Making them look like normal operations was the point, and it took craft.
Craft is what AI chips away at. Evading detection in a real estate is harder than reading a config repository, and I'm not claiming that's solved. But an attacker who can learn what normal looks like in the quiet tier has a better chance of staying there than they used to. A green dashboard tells us what our sensors and detection logic have surfaced. It does not establish that nobody is there.
None of this requires breaking anything. It requires the connections we never removed.
When I was defending critical infrastructure, we started with the assumption that somebody might already be inside. The concern wasn't always an attack happening today. It was someone keeping access until they needed it, and sometimes keeping the service running is exactly what they need. They may be using it to collect, to maintain access or to reach something else. Breaking it would interrupt what they came to do.
So the business and the attacker can both want the service up, for very different reasons. "It's still working" doesn't tell us who else it's working for.
What AI adds is speed at joining the dots. Standing credentials, flat reach and quiet corners were always there. They were tolerable because chaining them was slow. That is the part getting cheaper.
If effort isn't a control, what is?
Reach, and whether we've tested it.
If effort is no longer a control, then the rating has to come from something we can actually check: from a given foothold, what is reachable, and does the path still work? Three things follow from that, and none of them is new.
Remove unnecessary reach. Microsegmentation brings us back to the underlying question: which systems actually need to communicate? Host firewalling is one way to enforce the answer, not the whole of it. Restricting unnecessary reach is a minimum control in my book, not something reserved for systems labelled privileged. We need to get smarter at running it, not more selective about where.
Make the authority expire, not just the credential. Long-lived credentials with broad permissions made automation easier to run. They were never safe. The trade-off was tolerable while finding and exploiting the connections took effort. That is the assumption I'm no longer comfortable with.
This can't stop at administrator accounts. A monitoring agent that can run commands on every host has a path to customer data, however boring its own data might be. The controls need to follow the path.
The design goal is straightforward. Check that the requested action matches the approved change. Grant only the authority needed to perform it. Enforce that independently of the workflow or agent asking. And apply the same check to renewal. A five-minute credential that a compromised workflow can keep renewing has not interrupted anything. Fresh credentials issued on yesterday's approval are the old problem with a shorter lifetime.
The credential expiring isn't the result. The attacker losing useful authority is.
Here is the uncomfortable part. We knew all of this. The reason we didn't run it everywhere was operational, not intellectual. Removing access might break production, so nobody removed it. Exceptions granted during an incident never expired. Every new control added another approval queue, and people routed around it. If every routine action creates another approval queue, people will route around it, however correct the control is.
So the constraint I now put on any control is simple. It has to fit the work: automate the routine decisions and leave people with the exceptions. If the authority expires with the action, nobody has to schedule its removal. If the grant hangs off a change record or an approved operating policy that already exists, nobody fills in a second form. If the evidence falls out as a byproduct, assurance stops being a project. That is what makes least privilege something you operate rather than something you aspire to.
And test the path from an assumed foothold, then change the rating based on what the test shows. That is the part I want to spend the rest of this article on, because it is where the register stops being an opinion.
Let me show what I mean.
This example, including the dates, results and owner, is hypothetical.
Imagine the monitoring agent that runs on every server. Its job is to read health metrics and send them to a dashboard. When it was rolled out, it was given administrative access on every host so it could install, update and collect without friction. Three years on, that access is still there, and the platform can push scripts and updates to every agent. Its credentials rotate on schedule, and nobody will touch anything else about it, because it is critical to operations.
It has no business running commands on the hosts that hold customer data. But nothing stops its account from doing exactly that.
What the register says
Risk: Someone who takes over the monitoring platform could use its access to expose customer records.
Likelihood: Low. The platform is internal, it is monitored, and its credentials rotate every ninety days.
That sounds reassuring. Notice that the monitoring platform is monitored by itself. And none of it answers the question: once someone controls monitoring, what can they actually reach?
What the test shows
On 16 October, an authorised test starts from control of the monitoring platform, in a test environment with dummy customer data. No initial-access story is needed. The test says nothing about how likely that first compromise is. It shows what the compromise can achieve, and whether the controls we relied on actually stop it.
The agent's account can run commands on every host it monitors. That includes the hosts holding customer records. The tester uses it to pull those records out through the same channel the metrics travel on.
The test service stays available. Every health check passes. The dashboard is green. The attacker hasn't needed to falsify any of it, and the one system that might have noticed is the one they control.
The business sees a working estate. The attacker has what they came for.
Ninety-day rotation changed nothing. The attacker never needed the credential to last. They needed the authority it carried, and that was there on day one.
The "Low" rating is withdrawn. Success from the assumed foothold is rated High: the test demonstrated a working route from the monitoring platform to customer records. That is a qualitative assessment, not a calculated percentage.
What changes after the fix
The collection process keeps the access it needs for health metrics and nothing else. Installation, updates and other privileged actions move to a separate, narrowly scoped path.
Anything beyond collecting the approved metrics, whether a privileged command or a read of customer data, requires separately authorised access: issued per action, tied to an approved change or a previously approved operating policy, expiring when the action completes. The monitoring platform cannot issue that authority to itself, and obtaining a fresh credential does not bypass the check.
On 20 October, the team repeats the test from the same starting point.
Metrics still flow. The attempt to run a command on a data host fails. The blocked attempt reaches the person responsible for investigating it, through a channel the monitoring platform does not control.
Now there is evidence for reconsidering the rating: the route that worked before no longer works in the retest. Not because we added another control to a checklist, and not because the credentials rotate.
Alex, the service owner, now has evidence that this route is blocked under the tested conditions. Whether that supports a lower rating depends on the other routes and the assumptions still standing. That judgement is Alex's, and it can now be defended with the retest attached.
That is what I mean by managing likelihood. We found what made the harmful outcome possible, changed it, and tested whether the change actually stopped it.
The same pattern sits under the backup service, the nightly batch job, the CI runner and the integration account between two systems. And it sits under every AI agent being handed a standing token today, because that is the easiest way to make it reliable. The population is growing. The authority is being granted the same way it always was.
If likelihood is not a percentage, what goes in the register?
I record two things. The rating is still a judgement about likelihood and impact. Beside it I record the evidence that supports it, on a ladder:
- Untested. Treat the path as potentially reachable.
- Demonstrated open. A test reached the outcome.
- Tested and blocked. The path failed under the tested conditions.
- Blocked, with detection and response verified. The failure reached someone who acted.
And a date for when that evidence needs renewing.
Alex's risk sat at rung one, whatever the register said. On 16 October it moved to rung two. After 20 October it sits at rung four, until the renewal date passes.
The ladder doesn't calculate likelihood. It says what the rating rests on, and where we are still relying on assumptions. The evidence sets the rung. The accountable owner decides whether the remaining risk is acceptable.
Keep the decision connected to reality
Continuous assurance means current evidence that the controls behind a decision still work, and action when that evidence changes.
A configuration can stay exactly the same while an attacker finds another way around it. Does AI help them adapt around a defence we tested last quarter? Our assurance has to challenge that, not just confirm nothing in our environment changed.
So the retest needs triggers, not good intentions. Any change to the agent's permissions, the way it obtains credentials, the hosts it can reach or the detection coverage around it brings the risk back to Alex. No trigger, no change: it still runs on the agreed window, and the most critical paths run automatically alongside the deployment pipeline.
Start with two measures. What proportion of the critical paths we've identified has current test evidence? And how long from a blocked attempt to containment, not just to someone acknowledging the alert?
Record what was tested and what remains unknown. I kept a standing "known unknown" row in the register, and it stayed high. It wasn't a catch-all risk. It marked the limit of what the register could tell us. The mitigation was our defence-in-depth roadmap: people, practices, process and technology. It acknowledged that we had done the work and there could still be a way around it.
We could improve the defences. We couldn't make the uncertainty disappear by changing its colour.
A risk acceptance therefore needs to record the conditions supporting it, what invalidates them and who must respond. NIST CSF 2.0 organises that work well enough. It doesn't make the difficult decisions for us.
I had the technology owner sign for the controls and the remediation, because that belonged with the person running the system. Accepting the business consequences needed someone with the authority to accept them and fund the response. That split mattered. So did the uncomfortable reality that sometimes there was no money or capacity to fix it.
What had to survive the signature was the responsibility. Someone needs the skills and authority to act. The process must bring failed assumptions back to them. The technology must enforce the boundary and provide evidence. Leadership must fund the response or explicitly accept the changed exposure.
A signature doesn't end the responsibility.
What to do from where you sit
If you sit on a board: pick the three critical risks rated low likelihood. Ask when each was last tested from an assumed foothold, and what would change the rating. Then ask who funds the fix if the test fails. Treat "accepted" as conditional, with named conditions and a named owner.
If you run security or technology: run those three tests. Use the ladder to challenge the rating, and reassess likelihood and impact when the evidence changes. Set the triggers that bring a risk back for review. Give each one an owner who can act, and a window short enough to matter.
If you build or operate the systems: take one process identity. The monitoring agent, the backup service, the nightly job, the CI runner. Map what its account can reach and what it can obtain. Remove the standing rights it doesn't use. Make sensitive reads and privileged actions need their own authority, tied to the change or an approved policy. Test from the foothold. Fix. Test again.
None of that needs my code. It needs the question asked and the answer written down.
The engineer's list above is the hard one, and it is hard for the operational reasons I gave earlier. The authorisation work I started at KeyFlux and am continuing at Krnali is my attempt at the easier-to-run version: authority that expires with the action, grants tied to approved changes, enforcement outside the thing asking, and evidence produced as a byproduct rather than as extra work.
I'm happy to share the codebase with people interested in testing or using it. That testing will help me decide what is ready to release openly and what still needs work.
I especially want people challenging the awkward parts. Can the requesting agent bypass enforcement? Can compromised automation reacquire revoked authority? Can we trace an executed action back to the change that authorised it?
I'm not declaring that solved because the credentials expire.
We still have to make judgements. I made enough of them to know that.
But "we haven't seen it happen" and "we tested what stops it happening" are very different reasons to accept a risk.