How to Write a Mitigation an Auditor Will Actually Accept

Open almost any risk register at the mitigation column and you will find the same handful of phrases: use TLS, validate input, improve logging, developers are aware of this, hardened per best practice. Every one of them is a reasonable thing for an engineer to write and none of them is a control. They describe an intention, a direction of travel, or a state of mind, and an auditor cannot test any of those.

The frustrating part is that the underlying security work is often genuinely done. Teams get findings written up as gaps not because the control is missing but because the sentence describing it cannot be verified, and the register gives the auditor nowhere to look. That is a writing problem sitting on top of a real control, and it is much cheaper to fix than the alternative diagnosis.

The short version: An auditor is not grading your security posture. They are testing a much narrower claim — that a control you asserted exists, works as described, and was operating for the whole period, with evidence. So write each mitigation as a fact in the present tense, name where it is enforced and which role owns it, say whether it prevents, detects, or corrects, and point at an artefact the control produces by running rather than one assembled the week before fieldwork. Then state what it does not cover, because a mitigation with no stated residual risk reads as one nobody has thought about.

What is actually being tested

The mental model that fixes most of these entries is understanding what the auditor's job is. They are not forming an opinion on whether your architecture is sound. They are taking a statement you made about your own system and testing whether it holds — which means your statement has to be the kind of thing that can hold or fail. "We take security seriously" cannot fail. "All administrative access requires a second factor, enforced at the identity provider" can, and that is what makes it acceptable.

Practically, they are asking four questions of every entry, in order, and stopping at the first one that has no answer:

  • Is there a control here at all, or a description of a hope?
  • Is it designed to address the risk it is attached to? A control can be entirely real and simply not close the threat it has been filed against.
  • Was it operating for the whole period, not just on the day someone looked?
  • Can you show me?

Most rejected mitigations fail at the first or the last. The middle two are where the interesting conversations happen, and a register built from a threat model has a structural advantage there, because the threat the control addresses is already written next to it rather than being reconstructed after the fact.

Design versus operating effectiveness

This one distinction explains more audit findings than anything else, and most engineers have never had it explained to them. Controls get tested twice, for two different properties:

  • Design effectiveness asks whether the control, working as described, would actually address the risk. This is a reading exercise. It happens once, and a well-written sentence can pass it.
  • Operating effectiveness asks whether it genuinely ran throughout the review period. This is an evidence exercise, and no sentence can pass it — only artefacts can.

A control with no recurring output is permanently capped at design effectiveness. That is the whole reason "we review access quarterly" gets a finding while the reviews really were happening: the reviewing left no trace, so there is nothing to sample. It is also why the fix is so often clerical rather than technical — the control was fine, the exhaust was missing.

The corollary is worth carrying into engineering conversations, because it is an argument that lands: automating a control lowers its audit cost. A manual control is tested by sampling instances across the period, so twelve months of monthly reviews means twelve sets of evidence to produce and defend. An automated, preventive control is largely tested by inspecting the configuration and demonstrating it could not be bypassed or silently switched off. That is one conversation instead of twelve, every year, forever. Engineers who will not automate something to please an auditor will frequently automate it to never speak to one again.

The six parts of a mitigation that survives

A usable entry is not long — two or three sentences — but it carries six specific things. Missing any one of them predicts exactly which question it will fall over on.

PartWhat it meansWhat its absence causes
The assertion What is true of the system now, in the present tense. Not planned, not recommended, not encouraged. Read as a roadmap item; the risk is treated as untreated.
The location Where it is enforced — the gateway, the identity provider, the pipeline stage, the database configuration. Nothing to inspect, so nothing can be confirmed.
The owner A role that owns the control operating, not a named individual. Ownership evaporates at the next reorganisation, and the control quietly stops.
The type Preventive, detective, or corrective — the classification that determines how it gets tested. Wrong evidence gets requested and supplied, and the entry stalls.
The evidence The artefact that shows it operated across the period, named specifically. Passes design, fails operating effectiveness. The single most common outcome.
The residual risk What the control does not cover, stated plainly. Reads as overclaiming; invites the auditor to go looking for the gap themselves.

That last one is counter-intuitive and worth dwelling on, because the instinct is to make the entry sound as strong as possible. It backfires. An auditor who finds an unstated limitation on their own now has a reason to doubt the rest of the register; one who reads the limitation in your own words is looking at a team that understands its own controls. Stating residual risk buys credibility at a price you were paying anyway.

Before and after

The rewrite is usually mechanical once you see the pattern. In each of these, the security work was already done — only the sentence changed.

As writtenWhy it failsRewritten
"Use TLS everywhere." An instruction with no subject, no scope, and no enforcement point. Everywhere is unverifiable. "All external traffic terminates at the load balancer, which accepts TLS 1.2+ only; plaintext listeners are absent from the Terraform module and the pipeline fails the deploy if one is introduced. Owner: Platform. Evidence: module source, and the pipeline's policy-check job on every deploy. Residual: internal service-to-service traffic inside the VPC is not encrypted in transit."
"Improve logging." Names an aspiration, not a state. Nothing is asserted to be true today. "Authentication events, privilege changes, and administrative actions are written to the central log store with a 400-day retention. Owner: Platform. Evidence: retention policy configuration and a query returning the event types for any sampled date."
"Developers are trained on secure coding." Awareness is not a control — it changes the probability of a mistake but gates nothing. "Annual secure-coding training is assigned to all engineers, and merges to protected branches require review by a second engineer. Owner: Engineering Manager. Evidence: training completion export, and the branch protection settings plus the merge history. Residual: review quality is not measured; training alone does not prevent the class of flaw."
"Access is reviewed regularly." "Regularly" is not a period, and reviewing leaves no artefact. "Access to production is reviewed quarterly by the system owner against the current role matrix; the review is recorded as a ticket with the reviewer, date, and the accounts removed. Owner: Head of Engineering. Evidence: four tickets per year with their attached exports."
"Mitigated by our security policy." Circular. The policy states the requirement; it does not implement it. Either name the technical control that enforces the policy, or record it as an accepted risk with an owner and a review date. A policy on its own is a statement of intent about the very thing in question.

Notice that the rewrites are barely longer than the originals and contain no new security work. They are the same controls, described so that someone outside the team could go and check.

Make the evidence a byproduct, not a task

This is the highest-leverage idea in the post, so it gets its own section. When you choose how to evidence a control, strongly prefer artefacts the control generates simply by operating over artefacts a human assembles to demonstrate it.

A pipeline job that fails a deploy produces a record every time it runs, whether or not anyone is watching. A ticket automatically opened by a scheduled job exists whether or not someone remembered. A configuration in version control carries its own change history with authorship and dates. None of these needs anybody to think about the audit.

A screenshot, by contrast, is a task. Tasks that exist only for audits get done once, late, under pressure, and the resulting folder of undated images with no visible scope is the most common form of evidence rejection there is. Worse, it tends to be produced for the wrong window: the auditor is testing a twelve-month period and receives proof about one Tuesday in March.

So when a control is designed, ask what it will leave behind, and if the honest answer is "nothing," change the design rather than the documentation. Adding a ticket, a log line, or a pipeline gate at design time costs almost nothing; reconstructing a year of evidence for a control that never emitted any is the expensive path, and it is the one teams find themselves on.

Preventive, detective, corrective

Classifying the control tells the auditor what to ask for and stops the mismatched-evidence stall. It also makes gaps in layered defence visible, because a register in which every entry is preventive is describing a system that cannot tell when a control has failed.

TypeWhat it doesWhat it has to show
Preventive Stops the action. Authorization checks, branch protection, network policy, a failing pipeline gate. The configuration, plus evidence it was in force for the period and that bypassing it is either impossible or itself logged and approved.
Detective Notices the action. Alerting, anomaly detection, log review, reconciliation. That it fired when it should have — including at least one real case, with the response — and that its absence of firing means absence of events rather than a broken pipeline.
Corrective Limits the damage afterwards. Revocation, rollback, restore, incident response. That it has actually been exercised: a real invocation or a documented test, with timings, not merely a written procedure.

Detective controls fail an audit in a specific and avoidable way. An alert that has never fired is indistinguishable from an alert that is broken, and "we have had no incidents" does not resolve the ambiguity. If a detective control is the mitigation for a serious threat, arrange for it to be tested deliberately and record that test — it is the only way silence becomes evidence.

When there is no mitigation

Some threats will have no control behind them, and the register has to say so honestly. There are two legitimate ways to write that, and one illegitimate one.

The first is acceptance: the risk is understood and not being treated, recorded with the four things an acceptance needs — what, why in terms of cost and exposure, who accepted it at a level that owns the consequence, and when it will be revisited. This is a normal, defensible outcome, and auditors are markedly more comfortable with a well-documented acceptance than with a vague mitigation, because the former is a decision and the latter is a gap wearing a costume.

The second is a compensating control: you cannot address the root cause, so something else reduces the exposure — tighter monitoring around a component that cannot be patched, network restriction in front of a system that cannot enforce its own authentication. The rule when writing one is to label it as compensating rather than presenting it as a fix, and to state what remains uncovered. Auditors accept these routinely; what they do not accept is discovering that a control described as a solution was really a workaround.

The illegitimate version is the entry that describes a mitigation which does not exist, or which exists somewhere no one can point to. It is worth being blunt about this one: an inaccurate register is worse than an incomplete one, because it removes the team's own visibility of the gap in exchange for nothing, and because a single unsupportable claim casts doubt over every other entry the auditor has not yet tested.

A worked entry

Take a threat straight off a data flow diagram: a compromised CI job uses its deployment credentials to reach the production database directly. The first draft of the mitigation reads "pipeline credentials are locked down."

Rewritten with the six parts in place:

Control. Deployment jobs authenticate with short-lived credentials issued per run by the identity provider; the credentials carry deploy-only permissions and have no network route to the production database, which accepts connections from the application subnet only. Standing long-lived deployment keys were removed and their creation is blocked by policy.

Type. Preventive, with a detective layer: any authentication attempt against the production database from outside the application subnet raises an alert to the on-call channel.

Owner. Platform Engineering.

Evidence. The identity provider's trust policy and the security group rules, both in version control with change history; the credential-issuance log for any sampled run; the alert definition plus the record of its quarterly test firing.

Residual risk. A compromised job can still deploy malicious application code, which would then reach the database through the legitimate path. That threat is treated separately by build provenance and review requirements, recorded against its own entry.

Every part of that is checkable by someone who has never seen your system, and the residual-risk line does something the original could not: it points at the next threat and shows that the register is joined up rather than a list of isolated assertions. If you want the fuller treatment of the pipeline itself, the CI/CD guide works the same ground from the diagram outwards.

Where mitigations get rejected

  • Future tense. "Will be implemented in Q3" is a roadmap entry. Until it ships, the honest register entry is an acceptance with a date.
  • Awareness as a control. Training, guidelines, and documentation shape behaviour; they do not gate it. Pair them with something that does.
  • No enforcement point. If the entry does not say where the control lives, there is nothing for the auditor to open.
  • An individual as the owner. People change teams. Assign the role.
  • Evidence with no date or scope. An undated screenshot proves something was true once, which is not the claim being tested.
  • The wrong altitude. "We host on a major cloud provider" is context, not a control — their certification covers their responsibilities, not your configuration of them.
  • A control filed against the wrong threat. Encryption at rest is real and does nothing about a stolen session token. Read the pairing, not just the entry.
  • Overclaiming with no residual risk. Every control has an edge. Stating yours is cheaper than having it found.

None of this is really about audits. A mitigation written this way is one the next engineer can maintain without archaeology, because it says what is true, where it lives, and who owns it — and if it also happens to survive fieldwork without a week of scrambling, that is the side effect rather than the point. The register that passes an audit cleanly is generally just the register that was accurate, and the discipline that produces one is the same discipline that keeps the threat model connected to the system it describes.

If the register is heading for a specific framework, the mapping matters as much as the wording: see threat models as SOC 2 evidence and making a risk register speak ISO 27001, or start from the pre-structured risk register template.

Write mitigations against the threat that produced them

ThreatTree keeps each mitigation attached to the threat and the diagram element it came from, with owners, status, and residual risk on the entry — so the register you export for an auditor is the one your team already works from, not a document rebuilt the week before fieldwork.

Get started free

Not ready to sign up? Get new threat-modeling guides by email instead.