skip to content
← cd ..

Allowlisting before EDR: block the predictable, detect the rest

Every endpoint control sits somewhere on a timeline that runs from before a process executes to after it already has. EDR lives on the right side of that line. By design it is a detection-and-response tool: it watches what runs, decides whether the behavior looks malicious, and acts. That is genuinely valuable — but it carries a structural assumption. Something has to run first.

Application allowlisting lives on the left side of the line. It decides what is permitted to execute at all, before there is any behavior to judge. Think of it as the bouncer at the door versus the detective reviewing the CCTV after the fact. Both have a job. But if you can stop someone at the door, you would rather not be reconstructing what they did once they are already inside.

My argument is simple: in a layered stack, the allowlisting layer should be doing most of the work, and the EDR should be catching what is genuinely new — not the other way around.

The attacker top 10 hasn’t moved in a decade

Read enough threat reports and a deflating pattern emerges: the techniques that hurt enterprises today are the same ones that hurt them in 2019. Command and scripting interpreters (T1059 — PowerShell, cmd), signed-binary proxy execution (T1218rundll32, mshta, regsvr32), valid accounts (T1078), credential dumping (T1003), WMI (T1047), scheduled tasks (T1053), bring-your-own-vulnerable-driver, and remote-management-tool abuse. Year after year, report after report, the same list.

That stability is not depressing — it is the gift. A surface that predictable is a surface you can pre-empt. You are not being asked to anticipate the unknowable. You are being asked to close doors that have been kicked in, documented, and re-used for ten years straight.

EDR acts after execution — by design

The catch is that EDR is the wrong tool to close those doors, because it operates after the door is already open. It has to: detection is inference over behavior, and behavior does not exist until code runs.

Two trends make that gap costly. First, a growing share of intrusions are “malware-free.” Attackers are not dropping payloads for your scanner to catch; they are driving the trusted tools already on the box. There is nothing to “scan,” only legitimate binaries being used illegitimately, which turns detection into noisy behavioral guesswork with a large false-positive surface.

Second, breakout time keeps shrinking. The window from initial access to lateral movement is now routinely measured in minutes — sometimes less. When the adversary moves at machine speed and your response still has a human in the loop, detect-and-respond stops being a strategy and becomes a coin flip: you are trying to triage and contain faster than an automated chain can spread.

You can’t detect your way out of a disabled detector

Here is the part that should bother anyone treating EDR as the last line of defense: increasingly, the first move is to turn the EDR off.

Bring-your-own-vulnerable-driver works because Windows will load a properly signed kernel driver even if that driver is known to be exploitable. Attackers ship a legitimately signed but vulnerable driver, load it, and use it to blind or kill the endpoint agent — the “EDR killer” pattern. If your innermost layer can be switched off before it ever gets to act, then your entire model rests on a control the adversary removes on move one.

This is exactly where execution control earns its place. Driver and application allowlisting that refuses to load an unknown or known-vulnerable driver stops the killer before it runs — which means the EDR is still alive to do its job on everything else. Prevention here is not competing with detection. It is protecting the thing that does the detecting.

Predictable is preventable — and the targets are already catalogued

The strongest practical case for allowlisting is that the abusable surface is not a mystery. It is enumerated, machine-readable, and maintained for free by defenders:

  • LOLBAS — the catalog of living-off-the-land binaries and scripts (since 2018).
  • LOLDrivers — known-vulnerable and malicious drivers (since 2023).
  • LOLRMM — remote-management tools abused for access and persistence.
  • bootloaders.io and the various malicious-certificate trackers.

These are MITRE-mapped and ready to consume. A default-deny posture plus blocking the known-abused binaries, drivers, and unsanctioned RMM turns a published list of how you will be attacked into a closed door. You do not have to win a detection race against a technique you simply did not allow to run.

Allowlisting isn’t a silver bullet

If I am honest about the case, I have to be honest about the cost — and there is real cost.

Default-deny has operational weight. Software inventory, change management, update churn, and the dreaded “allowlist fatigue” are not free. Done carelessly, default-deny is just a self-inflicted outage with extra steps. It demands tooling and discipline, not a weekend project.

“Allowed” does not mean “safe.” Several of the top techniques abuse binaries you cannot simply block — powershell.exe, wmic, rundll32, mshta are part of the operating system. Naming-the-executable allowlisting does nothing against these on its own. The allowlisting layer only works if it is paired with execution constraints on the tools you must keep: ringfencing that stops Office from spawning a script host, WDAC and AppLocker policy, PowerShell Constrained Language Mode, and breaking the parent-child process chains that LOLBin abuse depends on.

None of this is an argument against the approach. It is the reason it is a layer and not a replacement. It shrinks the problem; it does not erase it.

The order that actually makes sense

Put the layers in the order their economics demand:

  1. Block the predictable. Default-deny, plus LOLBAS / vulnerable-driver / unsanctioned-RMM control. Deterministic, cheap, no analyst in the loop.
  2. Constrain what you can’t block. WDAC, AppLocker, Constrained Language Mode, script and host restrictions on the trusted tools you have to keep.
  3. Detect the creative residue. Now point your EDR’s probabilistic muscle at the genuinely novel — the small fraction that survived layers 1 and 2.
  4. Respond fast to what is left, which should be a much shorter list.

EDR is not the enemy in this story. It is just badly spent as a first line. Reserve deterministic prevention for the deterministic, decade-old threats, and reserve scarce detection and response budget for the irreducible unknown.

Bottom line

A layered stack that puts application control upstream of EDR stops the predictable before it executes, shrinks the alert pile, keeps the EDR from being disabled out from under you, and frees detection-and-response to do the one thing it is actually good at: catching what is new. For the top 10, prevention is not the ideal-but-impossible option the industry sometimes treats it as. It is mostly just unshipped.

// share tweet linkedin email