Most endpoints still run anything that is not explicitly forbidden, so a well-kept list of forbidden executables is often the first execution control a team can actually enforce. MITRE D3FEND names this countermeasure Executable Denylisting (D3-EDL), synonym Executable Blacklisting, and defines it as "Blocking the execution of files on a host in accordance with defined application policy rules." It sits under the Isolate tactic as a child of Execution Isolation (D3-EI), beside Executable Allowlisting, Application-based, Hardware-based and Kernel-based Process Isolation. This card covers what D3-EDL blocks, the ATT&CK techniques D3FEND relates to it, how the main operating system enforcement points implement it, how to verify the block holds and where denylists are bypassed. It is written for endpoint engineers and detection teams; the allowlist side is covered in D3-EAL Executable Allowlisting and the general discipline in the Application Allowlisting Guide.
Key takeaways
- Denylisting blocks what you name, nothing else. D3FEND's own considerations say denylists "may not provide protection from new, unknown, or zero day attacks", so D3-EDL is a complement to allowlisting, not a substitute.
- The best denylist targets trusted tools. Signed system binaries that can run arbitrary code (script hosts, build tools, debuggers) are the highest value entries, because attackers prefer them over custom malware.
- Rule type decides how easy the bypass is. D3FEND notes that filename, path and hash rules "could still be evaded by an attacker"; publisher and signing identity rules are harder to sidestep but block more.
- A deny-only policy must allow everything else explicitly. On Windows, App Control for Business blocks all code that no rule authorises, so a deny policy without the "Allow All" rules can stop the whole machine.
- Every block must be logged and tested. Audit mode events, enforcement events and a scheduled test execution of a harmless denied binary prove the list is loaded and enforced.
D3-EDL at a glance
| Attribute | Value |
|---|---|
| D3FEND ID | D3-EDL (d3f:ExecutableDenylisting) |
| Tactic | Isolate |
| Parent technique | Execution Isolation (D3-EI): techniques that "prevent application processes from accessing non-essential system resources" |
| Digital artefacts | Executable File (D3FEND relation: blocks) and Create Process (relation: filters) |
| Rule criteria D3FEND lists | File name, file path, file hash, publisher from the digital signature, file permissions, a malware scan result, and a user and file combination |
| Enforcement point | Usually a kernel component that intercepts the system calls that start a process |
| Main limitation | Blocks only what is listed; unknown or modified binaries run |
| Effort | Low to start with a published block list; ongoing to keep it current |
How it works
D3FEND describes a policy-enforcing program, often running in kernel mode, that intercepts process creation and compares the file being started against rules. If a rule matches, the process does not start. D3FEND lists the reasons organisations deny a binary:
- Known bad: known trojan programs, or files matching the hash of known malware.
- Known vulnerable: an old version of a program with known vulnerabilities.
- Location: files in a directory that low-privileged users can write to, where a malware dropper could place them.
- Permissions: files with permissions that are too open, for example set to run as another user.
- Licensing: unlicensed software that creates legal exposure.
- Scan or behaviour verdict: files flagged by a scan or by runtime behaviour, with Windows SmartScreen given as an example of a scan source.
The difference from D3-EAL is the default. An allowlist blocks everything not approved; a denylist runs everything not forbidden. That makes denylisting cheap to deploy without breaking business software, and also makes it weak against anything new. In practice teams use denylisting in three ways: as a stopgap before an allowlist exists, as a layer on top of an allowlist to remove dangerous binaries that the allowlist would otherwise trust because of their signer, and as an emergency response control to block a specific file across the estate during an incident.
ATT&CK techniques D3FEND relates to D3-EDL
Relationship type: inferred only. D3FEND derives these rows from the shared artefacts Executable File and Create Process and labels them "inferred, experimental" (D3FEND 1.6.0, checked November 2026). They show where a denylist can interrupt the technique, not proof that it stops it. Each ID was checked against ATT&CK v20.
| ATT&CK tactic (v20) | Techniques D3FEND relates to D3-EDL |
|---|---|
| Execution | T1204.002 Malicious File; also listed by name: T1059 Command and Scripting Interpreter, T1047 Windows Management Instrumentation, T1053 Scheduled Task/Job |
| Persistence and Privilege Escalation | T1546.002 Screensaver, T1546.005 Trap, T1546.006 LC_LOAD_DYLIB Addition, T1546.008 Accessibility Features, T1546.009 AppCert DLLs, T1546.010 AppInit DLLs, T1546.013 PowerShell Profile, T1546.015 Component Object Model Hijacking; T1547.001 Registry Run Keys / Startup Folder, T1547.009 Shortcut Modification; T1037.001 to T1037.004 logon and RC scripts and Login Hook; T1505.001 SQL Stored Procedures, T1505.003 Web Shell; T1137.001 Office Template Macros; T1548.002 Bypass User Account Control |
| Stealth | T1218.001 Compiled HTML File, T1218.002 Control Panel, T1218.003 CMSTP, T1218.005 Mshta, T1218.011 Rundll32; T1574.007, T1574.008, T1574.009 path interception; T1036.001 Invalid Code Signature, T1036.003 Rename Legitimate Utilities; T1027.001 Binary Padding, T1027.002 Software Packing, T1027.004 Compile After Delivery; T1055.003 Thread Execution Hijacking, T1055.004 Asynchronous Procedure Call, T1055.013 Process Doppelgänging; T1134.004 Parent PID Spoofing; also listed by name: T1140 Deobfuscate/Decode Files or Information, T1220 XSL Script Processing |
| Defense Impairment | T1690 Prevent Command History Logging |
| Discovery (listed by name) | T1007 System Service Discovery, T1010 Application Window Discovery, T1016 System Network Configuration Discovery, T1018 Remote System Discovery, T1033 System Owner/User Discovery, T1057 Process Discovery, T1082 System Information Discovery, T1124 System Time Discovery |
| Impact | T1565.003 Runtime Data Manipulation |
D3FEND still lists Impair Command History Logging under an ID that ATT&CK v20 has revoked; its v20 successor is T1690 Prevent Command History Logging, shown above. Rows "listed by name" appear on the D3FEND page without an ID; the IDs given are the matching ATT&CK v20 techniques.
Where denylisting genuinely bites (NHI Mgmt Group view): system binary proxy execution and discovery utilities. Blocking mshta.exe, cmstp.exe, or rarely needed tools such as wmic.exe removes a ready-made execution path that an allowlist trusting the Microsoft signer would leave open. Against T1027.002 packing or T1036.003 renamed utilities, hash and filename rules fail, and only publisher or signing identity rules hold. See the T1218 System Binary Proxy Execution Defensive Guide and the T1036 Masquerading Defensive Guide.
Rule types and how they fail
| Rule type | Blocks | Bypassed by | Use for |
|---|---|---|---|
| File name | Any file with that name | Renaming the file (T1036.003) | Quick emergency blocks only, paired with a stronger rule |
| File path | Files at a location | Copying the binary to another writable path | Denying execution from user-writable folders such as download and temp directories |
| File hash | One exact file | Any change to the file, including padding (T1027.001) or repacking | Known malware samples, vulnerable versions of a specific tool |
| Publisher or signer, optionally with product name and version | All matching signed files, or versions below a threshold | Unsigned copies, if unsigned code is otherwise allowed | Vulnerable old versions of signed tools; whole products you never want to run |
| Scan or reputation verdict | Files a scanner or reputation service flags | New samples with no verdict yet | Commodity malware; see D3-FHRA File Hash Reputation Analysis |
Microsoft's App Control documentation makes the hash weakness explicit: because a file's hash changes with any change to the file, an attacker "can trivially update the file", and it notes that tens of thousands of hash rules can affect runtime performance. Its recommendation is to prefer signer rules (PCACertificate, Publisher, FilePublisher) wherever possible and use hash rules only if necessary.
Where it is implemented
Platforms are listed alphabetically; the order is not a ranking. Endpoint protection and EDR products also offer file block indicators, usually by SHA-256 hash, and follow the same rule-type trade-offs.
Linux: fapolicyd
The Red Hat Enterprise Linux 9 documentation describes fapolicyd rules in /etc/fapolicyd/rules.d/, merged by fagenrules into /etc/fapolicyd/compiled.rules, with the file name's numeric prefix setting rule order. Rules can match path, hash, MIME type or trust. The default rule file 90-deny-execute.rules holds the catch-all deny_audit perm=execute all : all, so a denylist entry must sit in a file that sorts before any rule that would allow the binary. permissive = 1 in /etc/fapolicyd/fapolicyd.conf logs decisions without enforcing them, fapolicyd --debug-deny shows denials, and ausearch -m fanotify finds them in the audit log. More detail is in the fapolicyd and Linux Application Allowlisting Guide.
macOS: Santa
Santa, an open source binary authorisation tool for macOS maintained by North Pole Security, evaluates every execution against rules of type CDHASH, BINARY (SHA-256 of the whole file), SIGNINGID, CERTIFICATE (leaf certificate) and TEAMID. Its documentation describes a BLOCKLIST policy that applies even in Monitor mode and cannot be overridden, which makes Santa usable as a pure denylist on machines not yet ready for Lockdown mode. TEAMID has the broadest reach and the documentation advises using it carefully.
Windows: App Control for Business
App Control for Business (formerly WDAC) runs its policy enforcement in the kernel, the example D3FEND itself gives. Microsoft's deny policy guidance says a policy made only of deny rules must include "Allow All" rules in both the kernel and user mode sections, otherwise all code without an authorising rule is implicitly denied. Deny rules in one policy block a file even when another policy allows it. Microsoft also publishes a recommended block list of signed binaries that can bypass App Control, including mshta.exe, msbuild.exe, wmic.exe, cscript.exe, wscript.exe, InstallUtil.exe, debuggers such as cdb.exe and windbg.exe, and WSL components, with advice to block them unless a scenario explicitly requires them. The App Control for Business (WDAC) guide covers policy design in depth.
Implementation steps
- Decide the role of the denylist. Stopgap before allowlisting, overlay on an allowlist, or incident response tool. The role sets which rule types and which owners you need.
- Start from a published list. On Windows, take Microsoft's recommended block rules; on other platforms, list the interpreters, compilers and remote administration tools users do not need. Add vulnerable versions of tools you do use, as publisher plus version rules.
- Add location rules. Deny execution from user-writable locations (download folders, temp directories, browser caches) where your platform supports path conditions.
- Deploy in audit mode. App Control audit blocks appear as event 3076; fapolicyd runs with permissive = 1. Santa's BLOCKLIST applies even in Monitor mode, so on macOS stage new block rules to a pilot group instead. Collect two to four weeks of events and review who would have been blocked.
- Handle the exceptions. Where a team genuinely needs a denied tool (developers and msbuild.exe, for example), scope the exception to that group or device set, not the whole estate.
- Enforce in rings. Pilot devices first, then wider groups. Keep the previous policy version ready to redeploy; on Windows, App Control policy refresh and activation events (3095 to 3105) confirm the switch.
- Feed incident response. Give responders a documented, tested way to push a hash or signer block estate-wide within an agreed time.
- Review on a schedule. D3FEND stresses continuous management. Review the list after vendor block list updates, after incidents and at least quarterly.
How to verify it works
- Policy presence: confirm on a sample of devices that the expected policy version is loaded (App Control event 3099 policy loaded; fapolicyd-cli --list for rule order; the client mode and rules synced to each Santa client).
- Test execution: keep one harmless, deliberately denied test binary or hash and execute it from an approved test account on a schedule. Confirm the block and the event: 3077 on Windows for enforced blocks, a fanotify audit record on Linux, a denied execution event in Santa's telemetry on macOS.
- Bypass tests: in authorised testing, copy a denied tool to another path, rename it, and modify one byte. The results tell you which of your rules are name, path or hash rules in practice.
- Event flow: confirm block events reach the SIEM and that a block of a high-value entry (a proxy execution binary, a known malware hash) raises an alert, not just a log line.
| Metric | Example target (NHI Mgmt Group suggestion, not a standard) | Why it matters |
|---|---|---|
| Devices with the current denylist policy loaded | Above 98% | Unenforced devices are the gap attackers find |
| Scheduled test execution blocked and logged | 100% of test runs | Proves enforcement and logging end to end |
| Share of rules that are signer or publisher based | Rising quarter on quarter | Fewer trivially bypassed hash and name rules |
| Time to push an emergency block estate-wide | Measured in each exercise | Shows the incident response use works |
| Blocks of proxy execution binaries per month | Tracked and triaged | Each one is either an exception to scope or an intrusion attempt |
Limits, bypasses and failure patterns
- Treating a denylist as application control: new malware, recompiled tools and anything not listed run freely. D3FEND is explicit that denylists may not stop new or zero day attacks.
- Deny-only policy without allow-all rules: on Windows this blocks everything not authorised, a self-inflicted outage. Always test the merged policy in audit mode first.
- Hash lists that never stop growing: large hash lists cost performance and rot as tools update; prefer publisher and version rules.
- Blocking the binary but not the host: blocking an executable does not stop the same code running inside an allowed interpreter or loaded as a DLL. Script control (App Control's 8028 and 8029 script events) and DLL rules need their own coverage.
- Stale lists: Microsoft advises adding deny rules for older vulnerable versions once a bypass is patched. A list nobody owns falls behind the moment it is deployed.
- Exceptions granted to everyone: a single developer request that unblocks msbuild.exe for the whole estate removes the control.
Framework mapping
| Framework | Reference | Relevance |
|---|---|---|
| NIST SP 800-53 Rev 5 | CM-7(4) Unauthorized Software, Deny-by-exception | The control enhancement that describes denylisting directly |
| NIST SP 800-53 Rev 5 | CM-7(5) Authorized Software, Allow-by-exception | The allowlist counterpart that denylisting complements |
| NIST SP 800-53 Rev 5 | CM-7 Least Functionality, CM-11 User-installed Software, SI-3 Malicious Code Protection | Restricting unneeded programs and blocking malicious code |
| NIST CSF 2.0 | PR.PS-05 | Installation and execution of unauthorised software are prevented |
| MITRE ATT&CK mitigation | M1038 Execution Prevention | See M1038 Execution Prevention |
| MITRE D3FEND | D3-EI, D3-EDL, D3-EAL | Parent, technique and sibling |
Related countermeasures
- Executable Allowlisting (D3-EAL): the default-deny counterpart; denylisting is most useful layered on top of it.
- Kernel-based Process Isolation (D3-KBPI): limits what an allowed process can reach. See D3-KBPI Kernel-based Process Isolation.
- Process Spawn Analysis (D3-PSA): detects suspicious process creation that a denylist does not block. See D3-PSA Process Spawn Analysis.
- File Hashing (D3-FH): the hash that hash rules depend on. See D3-FH File Hashing.
Practitioner checklist
- Write down whether the denylist is a stopgap, an allowlist overlay or an incident tool, and who owns it.
- Start from the platform's published block list for signed proxy execution binaries.
- Prefer publisher and version rules; use hash rules for specific samples only.
- Deny execution from user-writable paths where the platform supports it.
- On Windows, include "Allow All" rules in any deny-only App Control policy and test in audit mode (event 3076).
- Scope exceptions to the groups that need them, never estate-wide.
- Run a scheduled test execution of a denied binary and confirm the block event reaches the SIEM.
- Rehearse an emergency hash or signer block and time it.
- Review the list quarterly and after every relevant incident.
Standards and references
- MITRE D3FEND: Executable Denylisting (D3-EDL)
- NIST: SP 800-53 Rev. 5 Security and Privacy Controls (CM-7)
- Microsoft Learn: Guidance on creating App Control deny policies
- Microsoft Learn: Applications that can bypass App Control and how to block them
- Microsoft Learn: Understanding App Control event IDs
- Red Hat: Blocking and allowing applications by using fapolicyd
- North Pole Security: Santa binary authorization
Related NHI Mgmt Group resources: D3-EAL Executable Allowlisting · Application Allowlisting Guide · App Control for Business (WDAC) · M1038 Execution Prevention · MITRE D3FEND Guide