Hardware Security

BadUSB Controls for Engineering Teams

BadUSB controls that survive contact with engineering teams — USB device control, HID allowlisting, USBGuard and WDAC, plus detection that does not block real work.

A USB dock with several ports, one port glowing red and blocked while the others glow cyan
Threat reference

BadUSB controls for engineering teams have a hard constraint: engineers plug in more hardware than anyone — keyboards, docks, debuggers, dev boards, SDRs — so a blanket USB block breaks real work and gets disabled within a week. The controls that survive are allowlist-based: permit known-good devices by hardware ID, block new unknown HID devices, and alert on the rest. This guide ships the device-control architecture (USBGuard on Linux, device-installation policy on Windows) plus the detection that catches a malicious device without stopping legitimate engineering.

A BadUSB device — a USB Rubber Ducky, a malicious cable, or a Flipper Zero in BadUSB mode — is a hardware addition: MITRE ATT&CK T1200 — Hardware Additions, with injected commands mapping to T1059.001.

What is a BadUSB attack, and why is it hard for engineering teams?

BadUSB abuses the implicit trust the operating system grants to a USB device’s declared class. A device can claim to be a keyboard and inject keystrokes, a network adapter and reroute traffic, or storage — and the OS believes it. The USB Rubber Ducky detection patterns post covers the behavioral detection; this post is about the controls that prevent it at scale.

The engineering-team challenge is that the obvious control — block USB — is a non-starter. Developers need keyboards, KVMs, docks, JTAG/SWD debuggers, dev boards, and SDRs. A policy that blocks them all gets exception-requested into uselessness. The answer is precision: allow the known, block the novel.

What are the BadUSB control options?

ControlPlatformWhat it doesTrade-off
Device allowlist (by hardware ID)Win / LinuxPermit known devices, block the restNeeds an inventory to maintain
Block new HID by defaultWin / LinuxStops injected-keyboard attacksMust allow legit new keyboards
USBGuardLinuxPolicy-based device authorizationTuning for dev workflows
WDAC / app allowlistingWindowsBlocks the payload’s executionSetup effort
Port physical controlHardwareDisable/epoxy unused portsCrude; rare for laptops

The pattern that works for engineers: allowlist what they use, block new HID keyboards by default, and let application allowlisting backstop the payload — so even a permitted-looking device cannot run an arbitrary command.

How to enforce BadUSB controls

On Linux, USBGuard authorizes devices by attribute. Start from your current, trusted devices and block anything new by default:

# /etc/usbguard/rules.conf — allow current devices, block new ones
allow id 046d:c52b serial "..."      # known wireless receiver
allow with-interface equals { 03:*:* } \
  if !allowed-matches(with-interface equals { 03:00:01 })   # HID, not new keyboards
block                                 # default-deny everything else

On Windows, use device-installation restrictions (Group Policy / Intune) to allow known device IDs and block new HID classes, and pair it with WDAC so an injected command cannot run an unsigned payload. The detection layer then alerts on anything that slips the policy.

Sigma New USB Device Installed With a HID Keyboard Interface
title: New USB Device Installed With a HID Keyboard Interface
id: 4f1d9b73-darkpwn-illustrative
status: experimental
logsource:
  product: windows
  service: security
detection:
  selection:
    EventID: 6416
    ClassName: 'Keyboard'
  filter_known:
    DeviceId|contains: 'KNOWN_INSTANCE_PREFIX'
  condition: selection and not filter_known
falsepositives:
  - Genuinely new keyboards/KVMs (add to the allowlist, then this clears)
level: medium
Sigma USB Device Presenting Multiple Conflicting Device Classes
title: USB Device Presenting Multiple Conflicting Device Classes
id: 8c2e1a64-darkpwn-illustrative
status: experimental
logsource:
  product: linux
  service: usbguard
detection:
  selection:
    event: 'device.present'
    interfaces|contains|all: ['03:', '08:']   # HID + Mass Storage on one device
  condition: selection
falsepositives:
  - Legitimate composite devices (some keyboards with storage); allowlist them
level: medium

Not just keyboards: the classes that matter

BadUSB discussion defaults to keyboards, and the keyboard is one of several classes a device can claim. Your allowlist and your alerting need to know the others.

ClassCodeWhy an attacker wants it
HID03Keystroke injection — the familiar case
Mass Storage08Payload delivery, and the found-drive social vector
CDC / Communications02, 0APresents as a network adapter — see below
Hub09Hides additional devices behind one physical connector
Smart Card0BCredential-adjacent, rarely legitimate on a laptop
Vendor-specificFFAnything at all; the class tells you nothing

The network-adapter case is the one most often missed, and it is worse than the keyboard. A device that declares itself a USB Ethernet adapter typically becomes an active network interface the moment it is attached — commonly a preferred one, because operating systems tend to favour a freshly connected wired link. The device then answers DHCP, naming itself as gateway and DNS server, and traffic from the host starts flowing through hardware the attacker controls. Credential material follows, because a great deal of software authenticates to network resources without being asked.

Two properties make this materially worse than keystroke injection:

  • It requires no unlocked session. Keystroke injection needs a logged-in desktop. A rogue network adapter works against a locked machine, because the network stack is running regardless.
  • It is silent. No windows open, nothing types, and the user sees nothing. There is no process-creation event to correlate against, so the entire detection approach from the keystroke-injection guide does not apply.

Alert on new network interfaces appearing over USB, and treat a device presenting a CDC class on an engineering laptop with the same seriousness as a new keyboard. On the control side, blocking class 02/0A except for the specific docks and adapters your organisation issues is usually easy, because that list is genuinely short.

The USB-C problem: Thunderbolt and DMA

A USB-C port is frequently also a Thunderbolt port, and Thunderbolt carries PCIe. That means a malicious device can request direct memory access to the host — reading and writing system memory without going through the operating system at all.

This is a different category from everything else in this guide. Device-class allowlisting does not address it, because the attack does not need to impersonate a device class. Application allowlisting does not address it, because no application runs. The mitigations are firmware and platform features:

  • Kernel DMA Protection, which uses the IOMMU to confine what a hot-plugged PCIe device can reach. It requires UEFI firmware support and virtualisation-based memory protections, so it is present on modern hardware and frequently absent on the older machines still in service.
  • Thunderbolt security levels, set in firmware, ranging from no authorisation through user-approval-per-device to restricting the port to DisplayPort or USB only. Restricting a port to USB-only removes the PCIe path entirely, and for most non-engineering users nothing is lost.
  • Disabling Thunderbolt in firmware where it is genuinely unused, with a firmware password so the setting cannot simply be changed back.
  • Requiring the machine to be locked is not sufficient here — DMA attacks against a locked machine are the specific scenario these mitigations exist for.

Verify which of your fleet actually has Kernel DMA Protection enabled rather than assuming it. This is one of the few controls where hardware age genuinely determines your exposure, and the answer is usually a straightforward inventory query.

Windows device installation policy has a precedence trap

The Windows device-installation restrictions are the right control and their evaluation order surprises people.

By default, prevent policies take precedence over allow policies, across all matching criteria. So a configuration that blocks a broad device setup class and separately allows a specific device ID within that class results in the device being blocked — the allow entry is not consulted, and nothing reports an error. The administrator concludes the allowlist is broken.

Windows added an option to apply a layered order of evaluation, which makes the more specific match win — allowing the intuitive pattern of “block this class, permit these specific devices inside it.” Enable it deliberately, and know that your policy behaves differently depending on whether it is on.

Three related practicalities:

  • Device IDs are hierarchical. You can match at several levels of specificity, from a broad hardware ID down to a device instance ID that identifies one physical unit. Allowlist at the narrowest level that is maintainable — instance IDs are precise and change when hardware is replaced, which is an inventory burden that may or may not be worth it.
  • Removable-device policies are separate from device-installation policies, and both may be needed.
  • Test on the actual hardware. Docks in particular enumerate as several devices at once, and a policy that permits the dock and blocks one of its internal components produces a dock that half-works — which generates the exception requests that eventually hollow out the policy.

USBGuard: the operational details that bite

USBGuard is the correct Linux control and it has failure modes worth knowing before you deploy it fleet-wide.

You can lock yourself out. A default-deny policy that does not permit the machine’s own keyboard leaves you at a login prompt that will not accept input. Always generate the initial policy from the currently attached devices, always confirm the keyboard and any KVM are in it, and always test on one machine you can physically recover before pushing to a fleet.

Internal devices are USB too. Laptop webcams, fingerprint readers, Bluetooth radios, and internal card readers frequently sit on the USB bus. A default-deny policy that only considered external peripherals will disable hardware users assume is part of the machine, and the reports will arrive as “the camera broke” rather than as a policy problem.

Ordering matters and the daemon must start early. Rules are evaluated in order, so a broad block placed above a specific allow wins. And the daemon needs to be running before a user can reach a login prompt, or the policy is not applied to devices present at boot.

Screen-lock integration is worth configuring. USBGuard can be configured to refuse newly attached devices while the screen is locked, which directly addresses the walk-past scenario while leaving normal working behaviour untouched. It is the highest-value setting in the whole configuration and it is not on by default.

Designing an exception path people actually use

Every control in this guide depends on an exception process, and a bad one guarantees the policy gets hollowed out. Design it deliberately:

  • Publish a target turnaround and meet it. An engineer who needs a debugger working today will find a way around a policy with a five-day approval queue, and the way around is usually a personal laptop, which is a considerably worse outcome than the device you declined to approve.
  • Make the common cases self-service. A pre-approved catalogue of standard peripherals that anyone can add without a ticket removes most of the volume, and it lets the review process focus on genuinely unusual hardware.
  • Approve device classes for roles, not devices for people. Hardware engineers need debuggers and dev boards; that is a role attribute, not a per-request judgement. Deciding once per role scales; deciding once per person does not.
  • Record why each exception exists and review them. Exceptions granted for a project that ended two years ago are the bulk of most allowlists, and they accumulate silently.
  • Make declining rare and explain it. A process that mostly says yes quickly earns compliance on the rare occasions it says no. A process that is slow and arbitrary teaches people to stop asking, and after that you have no visibility into what is being plugged in at all.

The measure of this control is not how much it blocks. It is whether it is still enforced in a year — and that depends almost entirely on how the exception path feels to the people subject to it.

How to roll out BadUSB controls without breaking engineering

  1. Inventory the USB devices engineers actually use (keyboards, docks, debuggers, dev boards) and build the allowlist from reality.
  2. Deploy in audit/monitor mode first — log what would be blocked, refine the allowlist, then enforce.
  3. Block new HID keyboards by default on high-value endpoints; allow known instance IDs.
  4. Layer application allowlisting (WDAC/AppLocker) so a slipped device’s payload still fails.
  5. Give a fast exception path so a legitimate new debugger does not drive workarounds onto unmanaged hardware, which is the failure mode a strict policy actually produces.

Common BadUSB control mistakes

  • Blanket USB blocking. Breaks engineering and gets disabled.
  • Allowlisting by class, not device. “Allow all keyboards” permits the Ducky.
  • No audit phase. Enforcing blind generates exception chaos and burns the goodwill you need for the rollout.
  • Control without detection. Allowlists drift; you still need alerts on the novel.
  • Thinking only about keyboards. A USB network adapter reroutes traffic from a locked machine, silently, with no process to correlate against.
  • Ignoring Thunderbolt. A USB-C port frequently carries PCIe, and DMA bypasses every device-class and application control in this guide. Kernel DMA Protection and firmware security levels are the mitigations.
  • Assuming Windows allow policies beat prevent policies. By default they do not; the layered order of evaluation has to be turned on deliberately.
  • Deploying USBGuard without allowing your own keyboard. A default-deny policy at a login prompt that accepts no input is a physical recovery job.
  • Forgetting that internal devices are USB. Webcams, fingerprint readers, and Bluetooth radios sit on the same bus, and users report their disappearance as broken hardware.
  • Not refusing new devices while the screen is locked. USBGuard supports this and it directly addresses the walk-past scenario, at essentially no cost to normal working.
  • An exception path slower than the work. Engineers route around it, usually onto unmanaged hardware, which is a worse outcome than the device you declined.
  • Never reviewing exceptions. Most allowlists are mostly grants for projects that ended.

Tier the policy by endpoint, not by organisation

One policy across the whole estate is why this control usually fails. Engineering laptops and reception kiosks have nothing in common, and a policy strict enough for one is unworkable on the other while a policy loose enough for the other is pointless on the first.

Three tiers cover almost every organisation:

Fixed-function endpoints — kiosks, reception machines, shared terminals, point-of-sale, digital signage, and servers. These legitimately never receive new hardware. Default-deny with a frozen allowlist, no new HID devices at all, physical port blockers where the machine is publicly accessible, and Thunderbolt disabled in firmware. Support cost is close to zero because nothing ever changes, and these are the most exposed machines you own — publicly reachable, frequently unattended, and rarely audited.

Standard corporate endpoints — most laptops and desktops. Allowlist by device class rather than by individual device, so mice, keyboards, headsets, and issued docks work without a ticket. Block network-adapter classes except for issued docks, refuse new devices while the screen is locked, and alert on anything outside the allowlist. This is where the population is, so the policy has to be quiet.

Engineering endpoints — the hard case this guide is named for. A broader allowlist covering debuggers, dev boards, SDRs, and programmers, granted by role rather than per request. Keep the detection layer at full strength here even though enforcement is looser, because these are the machines with the most credentials and the most source-code access. And keep Kernel DMA Protection on: engineers use Thunderbolt docks constantly, which is exactly the exposure.

The tiering does two things. It makes the strict settings deployable, because they land only where nothing breaks. And it makes the loose settings defensible, because the exception is scoped to a population with a stated reason rather than being the de facto standard everywhere.

Decide where a machine sits at provisioning time, from its role, and re-evaluate when the role changes. A tier assigned per-request drifts to the loosest setting within a year, which is the same failure as having no tiers at all.

BadUSB controls checklist

  1. Inventory engineers’ real USB devices; build a hardware-ID allowlist.
  2. Deploy device control (USBGuard / Windows device-install policy) in audit mode first.
  3. Block new HID keyboards by default on high-value endpoints; allow known IDs.
  4. Layer WDAC/AppLocker so payloads cannot execute.
  5. Forward USB device events to the SIEM; alert on new HID and conflicting classes.
  6. Correlate device-add with rapid script-host launches.
  7. Provide a fast, low-friction exception path for legitimate new hardware.
  8. Review the allowlist on a schedule for drift.
  9. Block USB network-adapter classes except for issued docks, and alert on new USB network interfaces — the attack that works against a locked machine.
  10. Enable Kernel DMA Protection and set Thunderbolt security levels; verify which of your fleet actually supports it.
  11. Refuse newly attached devices while the screen is locked.
  12. Tier the policy by endpoint role at provisioning time, and publish an exception path with a turnaround you meet.

The takeaway

BadUSB controls for engineering teams work when they are allowlist-based: permit the hardware engineers actually use, block new unknown HID devices, layer application allowlisting for the payload, and alert on the novel. Precision is what keeps the control deployed. Continue with USB Rubber Ducky detection patterns and Flipper Zero NFC risk, or browse the full Hardware Security pillar.

Training & tools referenced

Disclosure: Some links below are affiliate links. If you buy through them, darkpwn may earn a commission at no extra cost to you. We only recommend training and tools we actually use in our own lab, and affiliate links never influence editorial coverage.

  • TryHackMeAuthorized labs to practice USB and endpoint security controlsSecurity Training
    Start training

Frequently asked questions

What is a BadUSB attack?

BadUSB is a class of attack where a USB device's firmware makes it impersonate a trusted device class — most commonly a keyboard (HID) that injects keystrokes, but also network adapters or storage. Because the OS trusts the device class, antivirus and USB mass-storage policy do not stop it. A USB Rubber Ducky and a malicious cable are examples.

How do engineering teams control BadUSB without blocking work?

Use device control that allowlists known-good devices by hardware ID rather than blanket-blocking USB, which breaks legitimate engineering work. USBGuard on Linux and Windows device-installation policy (or WDAC) let you permit existing keyboards, docks, and debuggers while blocking new, unknown HID devices and alerting on them.

Can you block BadUSB with antivirus?

No. A BadUSB device injects keystrokes or presents a trusted device class; it runs no malicious file of its own, so signature antivirus has nothing to scan. The controls are device allowlisting plus application allowlisting to stop whatever the keystrokes try to run.

What is USBGuard?

USBGuard is a Linux framework that enforces a device-authorization policy: you define allowed USB devices by attributes (vendor, product, serial, interface class) and it blocks devices that do not match. It is the Linux counterpart to Windows device-installation restrictions for BadUSB control.