Audit USB Devices and Block the Bad Ones (Scriptable)

Was this helpful?

USB is the office hallway of hardware: everybody uses it, nobody owns it, and the worst things happen there at 2 a.m.
If you run production systems, you’ve seen some version of this: a “helpful” thumb drive appears, a “keyboard” shows up
that isn’t a keyboard, or a UPS with a USB management cable quietly changes behavior after a firmware update.

This guide is for Linux operators who want to inventory USB devices and block the bad ones in a way that’s
repeatable, testable, and safe to roll across a fleet. We’ll use standard tools (lsusb, udevadm, journald),
plus policy layers (usbguard, kernel module controls) and we’ll do it with commands you can paste into a shell.

Threat model: why USB is a production risk

USB is not “a port.” It’s a bus with power delivery, hotplug, multiple device classes, and a long history of
“trust the device, because what else can you do?” assumptions. That’s fine on a dev laptop. It’s reckless on a
server that holds credentials, customer data, or anything you’d be embarrassed to explain to your audit committee.

The most common operational failure modes don’t require Hollywood-grade malware:

  • Data exfiltration: USB mass storage mounts, someone copies a few directories, everyone’s day is ruined.
  • Keystroke injection: a device claims it’s a keyboard (HID) and types commands faster than a human can blink.
  • Network pivot: a “USB Ethernet” gadget shows up and creates a new network interface with DHCP.
  • Service instability: a driver binds to a new USB serial device and changes /dev paths or udev names.
  • Supply chain surprises: same-looking device, different USB IDs, different firmware, different behavior.

Your job is not to “block USB.” Your job is to decide what USB is allowed to do on this class of hosts, then
enforce it with tooling that doesn’t rely on wishful thinking.

One quote to keep you honest: “Hope is not a strategy.” — James Cameron.

Facts and context that change decisions

A few short, concrete points that matter when you’re designing policy instead of arguing in Slack:

  1. USB Mass Storage dates back decades and became ubiquitous because it was dead simple: present a block device, let the OS mount it.
  2. HID (keyboards/mice) is “trusted by default” in most environments because usability beat security in the early PC era.
  3. Composite USB devices are normal: one physical device can expose multiple functions (HID + storage + serial). This is great for docks, great for attackers too.
  4. Vendor/Product IDs are not authentication: they’re identifiers, and firmware can lie. They’re useful for policy, not proof of goodness.
  5. USB serial adapters created an entire ecosystem of operational dependency (console access, UPS, PDU control). Blocking everything breaks real work.
  6. “BadUSB” made the industry admit the firmware problem: device firmware can reprogram and present different classes, even if it looks like a thumb drive.
  7. Linux treats “a new device appeared” as an event storm: udev rules, systemd generators, networkd, desktop automounters—lots of actors react.
  8. Servers quietly have USB dependencies: hardware watchdogs, license dongles, KVMs, and BMC virtual media all show up as USB-ish things.
  9. Modern USB-C docks are function factories: storage, Ethernet, audio, display, input devices—your policy needs to be explicit about what’s acceptable.

If those facts make you uncomfortable, good. That’s the correct baseline.

Fast diagnosis playbook

When something USB-related is “weird” (mysterious mounts, new interfaces, unstable device names), don’t start with
theoretical security policy. Start with a quick triage sequence that narrows the blast radius.

First: what event just happened?

  • Check kernel/journal for hotplug events and driver binds.
  • Identify the device class (storage/HID/network/serial).
  • Confirm whether the system auto-mounted or auto-configured anything.

Second: what device is it, exactly?

  • Get vendor/product IDs, serial (if present), and the physical port path.
  • Check if it’s a composite device exposing multiple interfaces.
  • Map from USB device to block device node (if any) and to filesystem mounts.

Third: what control plane do you have?

  • If you run usbguard, check policy logs and device state.
  • If not, decide whether to block via kernel module (mass storage), udev rules, or physical port lockdown.
  • Apply a temporary block that’s reversible, then write the permanent rule with testing.

The bottleneck is usually not “USB.” It’s your observability of USB. Fix that first, then enforce policy.

Audit fundamentals: what’s plugged in and what it really is

Auditing USB on Linux is about building a chain of evidence:
kernel event → USB ID → interface class → driver → device node → system behavior.
If you can’t draw that chain for a device, you don’t control it.

Also: don’t rely on the “name” of the device as shown by desktop tools. In production, you care about stable identifiers
(port path, serial, vendor/product IDs) and which kernel driver bound to it.

Joke #1: USB devices are like interns—some are brilliant, but you still shouldn’t let them run payroll unsupervised.

Practical tasks (commands, outputs, decisions)

These are real tasks you can run on a Linux host. Each includes:
a command, sample output, what the output means, and the decision you make from it.
Assume you’re root or have sudo where required.

Task 1: List all USB devices (coarse inventory)

cr0x@server:~$ lsusb
Bus 002 Device 003: ID 0781:5581 SanDisk Corp. Ultra
Bus 001 Device 002: ID 046d:c534 Logitech, Inc. Unifying Receiver
Bus 001 Device 003: ID 0bda:8153 Realtek Semiconductor Corp. RTL8153 Gigabit Ethernet Adapter
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

What it means: Vendor:Product IDs show the device identity as reported by firmware. Root hubs are normal.

Decision: Anything that isn’t a root hub should be justified. SanDisk storage on a server? That’s a policy conversation.

Task 2: Get verbose details for a suspicious device

cr0x@server:~$ lsusb -d 0781:5581 -v | sed -n '1,80p'
Bus 002 Device 003: ID 0781:5581 SanDisk Corp. Ultra
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               3.00
  bDeviceClass            0
  bDeviceSubClass         0
  bDeviceProtocol         0
  idVendor           0x0781 SanDisk Corp.
  idProduct          0x5581 Ultra
  iManufacturer           1 SanDisk
  iProduct                2 Ultra
  iSerial                 3 4C530001230101234567
  bNumConfigurations      1

What it means: You’ve got a serial number (great for allowlisting) and it’s not claiming a single device class at the device level (common).

Decision: Capture the serial and port path. If you allow storage at all, allowlist specific serials only.

Task 3: Watch live USB hotplug events (who touched the box?)

cr0x@server:~$ sudo udevadm monitor --udev --kernel
monitor will print the received events for:
KERNEL - the kernel uevent
UDEV - the udev event

KERNEL[24812.531129] add      /devices/pci0000:00/0000:00:14.0/usb1/1-2 (usb)
UDEV  [24812.612204] add      /devices/pci0000:00/0000:00:14.0/usb1/1-2 (usb)
KERNEL[24812.713001] add      /devices/pci0000:00/0000:00:14.0/usb1/1-2/1-2:1.0 (usb)
UDEV  [24812.714983] add      /devices/pci0000:00/0000:00:14.0/usb1/1-2/1-2:1.0 (usb)

What it means: You get the physical port path (like 1-2) and interface events (1-2:1.0).

Decision: Use the port path to build a “this rack port is allowed” policy when serials aren’t reliable.

Task 4: Identify the driver that bound to a USB interface

cr0x@server:~$ readlink -f /sys/bus/usb/devices/1-2:1.0/driver
/sys/bus/usb/drivers/usb-storage

What it means: The usb-storage driver is in play, so this device can present block storage.

Decision: If the host should never accept removable storage, plan to block usb-storage globally or via usbguard/udev.

Task 5: Map USB storage to a block device node

cr0x@server:~$ lsblk -o NAME,TYPE,TRAN,SIZE,MODEL,SERIAL,MOUNTPOINT
NAME   TYPE TRAN  SIZE MODEL            SERIAL               MOUNTPOINT
sda    disk sata  1.8T INTEL SSDSC2BX   BTTV1234001
└─sda1 part       1.8T                                  /
sdb    disk usb  14.9G Ultra            4C530001230101234567
└─sdb1 part usb  14.9G                                  /media/usb

What it means: TRAN=usb confirms transport. Now you know which block device to unmount and wipe, if necessary.

Decision: If this mount is unexpected, unmount immediately, then block recurrence. Inventory what was copied if you’re doing incident response.

Task 6: See recent kernel messages for USB and storage behavior

cr0x@server:~$ sudo journalctl -k -n 80 | egrep -i 'usb|scsi|uas|storage|hid'
Feb 05 10:41:12 server kernel: usb 1-2: new SuperSpeed USB device number 5 using xhci_hcd
Feb 05 10:41:12 server kernel: usb 1-2: New USB device found, idVendor=0781, idProduct=5581
Feb 05 10:41:12 server kernel: usb-storage 1-2:1.0: USB Mass Storage device detected
Feb 05 10:41:12 server kernel: scsi host6: usb-storage 1-2:1.0
Feb 05 10:41:13 server kernel: scsi 6:0:0:0: Direct-Access     SanDisk  Ultra            1.00 PQ: 0 ANSI: 6
Feb 05 10:41:13 server kernel: sd 6:0:0:0: [sdb] 31260672 512-byte logical blocks: (16.0 GB/14.9 GiB)

What it means: This confirms the enumeration sequence and the fact that storage was recognized as SCSI disk.

Decision: If you’re building an audit trail, stash these events with timestamps. If you’re preventing recurrence, block by class/driver.

Task 7: Inspect USB device attributes via udev (for stable matching)

cr0x@server:~$ udevadm info -q property -n /dev/sdb | egrep 'ID_VENDOR_ID|ID_MODEL_ID|ID_SERIAL_SHORT|ID_BUS|ID_USB_DRIVER'
ID_BUS=usb
ID_VENDOR_ID=0781
ID_MODEL_ID=5581
ID_SERIAL_SHORT=4C530001230101234567
ID_USB_DRIVER=usb-storage

What it means: These properties are what you can match in udev rules. Serial is the strongest here.

Decision: Decide whether to enforce by serial (preferred), vendor/product (acceptable for known-good fixed devices), or port path (last resort).

Task 8: Check for USB network interfaces that shouldn’t exist

cr0x@server:~$ ip -br link | egrep 'enx|usb|wl|ww'
enx00e04c680001    UP             02:11:22:33:44:55

What it means: Interfaces named enx* are often USB NICs (MAC-derived naming).

Decision: If the host is not supposed to gain network connectivity via USB, block the device class or explicitly deny that VID:PID with policy.

Task 9: Identify a USB NIC’s origin and USB IDs

cr0x@server:~$ udevadm info -q all -n /sys/class/net/enx00e04c680001 | egrep 'ID_VENDOR_ID|ID_MODEL_ID|DEVPATH|ID_NET_DRIVER' | head
E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-3/1-3:1.0/net/enx00e04c680001
E: ID_VENDOR_ID=0bda
E: ID_MODEL_ID=8153
E: ID_NET_DRIVER=r8152

What it means: This is a Realtek USB NIC driven by r8152, located at port path 1-3.

Decision: For servers, default to deny USB NICs unless you have a documented use case (kiosk/edge boxes excepted).

Task 10: Detect USB Human Interface Devices (HID) presence

cr0x@server:~$ grep -H . /sys/bus/usb/devices/*/bInterfaceClass 2>/dev/null | head
/sys/bus/usb/devices/1-2:1.0/bInterfaceClass:08
/sys/bus/usb/devices/1-4:1.0/bInterfaceClass:03

What it means: Interface class 08 is mass storage, 03 is HID. This is a quick way to spot device types without parsing lsusb.

Decision: If a server suddenly has HID, treat it as suspicious unless it’s a known KVM or console dongle.

Task 11: Temporarily disable USB mass storage (quick containment)

cr0x@server:~$ sudo modprobe -r usb_storage
cr0x@server:~$ lsmod | grep -E '^usb_storage\b' || echo "usb_storage unloaded"
usb_storage unloaded

What it means: Removing the module stops new USB storage devices from binding. Existing mounted devices may remain until unmounted.

Decision: Use as an emergency brake during incident response. For permanence, use a modprobe denylist and/or usbguard policy.

Task 12: Permanently prevent usb-storage from loading (server baseline)

cr0x@server:~$ printf "blacklist usb_storage\ninstall usb_storage /bin/false\n" | sudo tee /etc/modprobe.d/usb-storage.conf
blacklist usb_storage
install usb_storage /bin/false
cr0x@server:~$ sudo update-initramfs -u
update-initramfs: Generating /boot/initrd.img-6.1.0-18-amd64

What it means: Blacklisting reduces accidental loads; install ... /bin/false is the firm “no.” Updating initramfs ensures early boot honors it.

Decision: Do this on hosts where USB storage is never required. Don’t do it blindly on hosts that rely on BMC virtual media for recovery.

Task 13: Audit automount behavior (the silent accomplice)

cr0x@server:~$ systemctl is-enabled udisks2.service 2>/dev/null || true
enabled
cr0x@server:~$ systemctl status udisks2.service --no-pager | sed -n '1,8p'
● udisks2.service - Disk Manager
     Loaded: loaded (/lib/systemd/system/udisks2.service; enabled; preset: enabled)
     Active: active (running)

What it means: On servers, udisks2 is usually unnecessary and can facilitate automount workflows (especially in desktop-ish environments).

Decision: For server images, disable what you don’t need. If you need udisks2 (rare), compensate with stricter USB policy.

Task 14: Install and enable usbguard (policy engine)

cr0x@server:~$ sudo apt-get update
cr0x@server:~$ sudo apt-get install -y usbguard
cr0x@server:~$ sudo systemctl enable --now usbguard.service
Created symlink /etc/systemd/system/multi-user.target.wants/usbguard.service → /lib/systemd/system/usbguard.service.

What it means: usbguard can enforce allow/deny policy per device, including class and interface details.

Decision: Use usbguard when you need fine-grained control (e.g., allow a UPS USB HID but deny storage). If you just need “no USB storage,” kernel module controls may be simpler.

Task 15: Generate a baseline allowlist policy with usbguard

cr0x@server:~$ sudo usbguard generate-policy
allow id 1d6b:0002 serial "" name "xHCI Host Controller" hash "..."
allow id 046d:c534 serial "" name "Unifying Receiver" with-interface 03:01:02 hash "..."
allow id 0bda:8153 serial "" name "RTL8153 Gigabit Ethernet Adapter" with-interface ff:ff:ff hash "..."

What it means: usbguard sees what’s currently connected and emits rules. It may include hubs/controllers; that’s normal.

Decision: Review before deploying. If the baseline was generated during an incident, you just enshrined the attacker’s device as “allowed.” Generate from a known-clean state.

Task 16: Enforce default-deny and allow only known devices (usbguard config)

cr0x@server:~$ sudo sed -i 's/^ImplicitPolicyTarget=.*/ImplicitPolicyTarget=block/' /etc/usbguard/usbguard-daemon.conf
cr0x@server:~$ sudo install -m 0600 /dev/null /etc/usbguard/rules.conf
cr0x@server:~$ sudo bash -lc 'usbguard generate-policy > /etc/usbguard/rules.conf'
cr0x@server:~$ sudo systemctl restart usbguard.service

What it means: Default policy blocks devices unless rules allow them. Rules file becomes the allowlist.

Decision: Default-deny is the only setting that scales. Then explicitly allow what you need—ideally by serial, interface, and port where practical.

Task 17: Observe usbguard decisions in real time

cr0x@server:~$ sudo usbguard watch
device-present id 0781:5581 serial "4C530001230101234567" name "Ultra" hash "..." via-port "1-2" with-interface 08:06:50
device-policy id 0781:5581 serial "4C530001230101234567" target block

What it means: The device appeared and was blocked. Interface 08:06:50 is mass storage (SCSI transparent, Bulk-Only or similar).

Decision: If the block is expected, you’re done. If you broke a legitimate workflow, craft a narrow allow rule, not a broad exception.

Task 18: Create a usbguard allow rule for a specific serial and interface

cr0x@server:~$ sudo bash -lc 'printf "%s\n" \
"allow id 051d:0002 serial \"\" name \"American Power Conversion\" with-interface 03:00:00" \
>> /etc/usbguard/rules.conf'
cr0x@server:~$ sudo systemctl reload usbguard.service || sudo systemctl restart usbguard.service

What it means: This example allows a UPS-like HID interface (not storage). The interface triple matters: it prevents “same device also exposes storage” surprises.

Decision: Always include with-interface unless you’re allowing a hub/controller. Narrow beats clever.

Task 19: Block a specific VID:PID via udev (surgical, but limited)

cr0x@server:~$ cat | sudo tee /etc/udev/rules.d/90-usb-block-sandisk.rules
ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="0781", ATTR{idProduct}=="5581", ATTR{authorized}="0"
cr0x@server:~$ sudo udevadm control --reload-rules
cr0x@server:~$ sudo udevadm trigger --subsystem-match=usb

What it means: Setting authorized=0 tells the kernel to de-authorize the device. This can work well, but behavior varies across device types and timing.

Decision: Use udev as a tactical tool. For fleet-grade policy with auditing, prefer usbguard.

Task 20: Confirm a block device is gone and mounts are clean

cr0x@server:~$ mount | grep -E '/media/usb|/run/media' || echo "no removable mounts"
no removable mounts
cr0x@server:~$ lsblk -o NAME,TRAN,SIZE,MOUNTPOINT | egrep 'usb|^sdb' || echo "no usb block devices"
no usb block devices

What it means: No remaining mounts and no remaining USB transport disks.

Decision: Declare containment only after both are true. Blocking without unmounting is how you get half-fixed incidents.

Blocking strategies: blunt, precise, and fleet-friendly

Strategy A: Disable USB mass storage at the kernel module layer

This is the big hammer. It’s wonderfully effective for “servers never accept thumb drives.”
It’s also indiscriminate: it blocks all USB storage, including legitimate recovery workflows that use virtual media.

When to use it:

  • General-purpose servers in a controlled datacenter where hands-on recovery uses other mechanisms.
  • Compliance-driven environments where removable storage is categorically prohibited.

When not to use it:

  • Remote/edge deployments where field recovery depends on USB media.
  • Systems that rely on USB-attached storage as a designed component (some appliances do).

Strategy B: usbguard default-deny + allowlist

This is the grown-up approach: explicit policy, logging, and a manageable path to exceptions.
usbguard can allow a specific UPS HID device while denying storage and denying unknown interfaces on the same device.

If you’re operating a fleet, usbguard also gives you a policy artifact you can review like code.
That’s not a nice-to-have. That’s how you survive audits without lying.

Strategy C: udev-based blocking (fast and local)

udev rules can deauthorize devices or prevent certain behaviors. They’re useful for targeted denies and for systems
where you can’t introduce a new daemon. The trade-off is complexity and edge cases: timing matters, attributes vary,
and you’ll debug it at the worst moment.

Strategy D: Attack the automount surface

Even if a USB storage device is detected, it doesn’t have to mount. For non-desktop servers, removing automounting
agents is good hygiene. It won’t stop keystroke injection or USB NICs, but it reduces the “oops it mounted” class of incident.

Strategy E: Physical and firmware controls (the part everyone forgets)

If you can disable external USB ports in BIOS/UEFI, do it on systems that never need them.
If you can lock ports with physical blockers, do it on boxes in semi-public spaces.
Software policy is necessary; it’s not always sufficient.

Joke #2: The only truly secure USB port is the one filled with epoxy—but Facilities gets weird about it.

Three corporate mini-stories from the trenches

1) Incident caused by a wrong assumption: “It’s just a keyboard”

A mid-sized company ran a set of Linux jump hosts that engineers used for production access. The hosts were locked down:
no compilers, tight sudo, MFA for SSH. The team felt good about it, which is usually the first symptom.

During a maintenance window, a contractor needed console access because one jump host had network issues. Someone plugged in
a “spare keyboard” from a drawer. The assumption was simple: keyboards are inert input devices; they can’t do much besides type.

The keyboard was not inert. It enumerated as an HID device and injected a short command sequence into the console.
Nothing cinematic—just a curl-to-shell style one-liner that fetched a script from an internal host and ran it.
The script added a user with SSH keys and left. It was fast, quiet, and it didn’t need privilege escalation because the console
session was already privileged for troubleshooting.

The postmortem was painful because the “security controls” were all network-centric. USB wasn’t in the threat model.
The team ended up implementing a default-deny USB policy on those hosts: allow only the KVM’s known USB VID:PID and block everything else.
They also learned to stop keeping mystery peripherals in drawers. Inventory isn’t glamorous, but surprise hardware is how you get owned.

The most embarrassing part: there were no malware signatures to find, no fancy exploit chain. Just an assumption that “HID is safe.”
It wasn’t.

2) Optimization that backfired: “Let’s allow all hubs and docks”

Another organization standardized on USB-C docks for their on-call laptops. The intent was good: fewer adapters, easier workstation swaps,
less time spent hunting for the right dongle. They wrote a usbguard policy that broadly allowed known dock vendors and their hubs.

The policy looked tidy: allow these vendor IDs, allow these hubs, allow this Ethernet function. It even passed a pilot. Then it hit reality.
Docks are not stable, single-function devices. Firmware updates changed reported IDs. Replacement units came from different manufacturing runs.
The policy started blocking legitimate docks and allowing some surprising interfaces.

The backfire was subtle: an allowed dock exposed a mass storage interface used for “driver installation” on Windows.
On Linux, it showed up as a small read-only disk. Nothing mounted automatically on the hardened laptop image, but developers being developers
mounted it “to see what it is.” The disk contained scripts and binaries. Someone ran one. It wasn’t malware, just a vendor troubleshooting tool,
but it changed system network settings and broke VPN routing.

The incident wasn’t a breach. It was worse in a different way: it knocked out on-call connectivity in the middle of a production incident.
The team revised the policy to allow dock Ethernet and display functions but explicitly deny storage interfaces, even on “allowed” devices.
The lesson: optimization that broadens trust is an optimization that eventually bills you for its own convenience.

3) Boring but correct practice that saved the day: “Baseline USB inventory as code”

A financial services firm ran a mixed fleet: servers in datacenters, edge devices in branches, and a handful of kiosks.
They had a simple, boring rule: every host class had a documented USB policy, versioned in configuration management.
Not a wiki page. Actual policy files.

On an edge device, an operator reported that “a USB stick doesn’t work anymore.” That phrasing is always suspicious:
either you intentionally blocked it (and it’s working as designed), or you unintentionally blocked a legitimate device (and you broke something).

They checked usbguard logs and saw a new device appear: same vendor and product as the “approved” USB modem, but a different serial and an extra interface.
The baseline policy allowed the modem’s known interface class and required a serial match. So the new device was blocked by default.
The operator’s complaint was the alarm bell, not the problem.

It turned out the modem had been replaced by a third-party contractor with a cheaper unit that reported similar IDs but exposed a storage interface.
The storage interface contained an autorun tool for Windows. The firm didn’t care about Windows autorun; they cared about the existence of
an unexpected storage interface on a network path device. They rejected the hardware, updated vendor requirements, and moved on.

The saving grace wasn’t a magical security product. It was the boring practice of: baseline inventory, explicit allowlist, and logs that made the decision obvious.
When you can answer “what changed?” in minutes, you sleep more.

Common mistakes (symptoms → root cause → fix)

Mistake 1: “We blocked USB storage, but drives still show up sometimes.”

Symptoms: Some USB sticks mount; others don’t. Behavior varies by kernel update or device.

Root cause: You blocked usb_storage but the device is using uas (USB Attached SCSI) or another path, or your initramfs still loads modules early.

Fix: Check loaded modules for both usb_storage and uas; update initramfs; consider usbguard class-based blocking for storage interfaces.

Mistake 2: “We allowlisted by vendor ID, now attackers can spoof us.”

Symptoms: Policy says “allow vendor X,” and you feel safe. You shouldn’t.

Root cause: VID:PID is not authentication. Firmware can present IDs. Also, legitimate devices can change IDs across revisions.

Fix: Prefer serial + interface constraints. If serial is missing, tie policy to physical port paths on fixed hardware, and enforce default-deny.

Mistake 3: “usbguard blocked our UPS and the box powered off during maintenance.”

Symptoms: Power events aren’t reported; shutdown hooks don’t trigger; monitoring loses contact with UPS.

Root cause: The UPS was a USB HID device and your default-deny policy didn’t allow it, or it was allowed without the required interface detail.

Fix: Add an allow rule for the UPS with specific interface class. Test by unplug/replug during a maintenance window and confirm monitoring sees it.

Mistake 4: “We blocked everything and now remote recovery is impossible.”

Symptoms: You can’t use BMC virtual media; rescue ISO doesn’t attach; remote hands can’t boot recovery media.

Root cause: You globally denied USB storage, but your out-of-band management presents virtual media as USB storage to the OS.

Fix: Create a host class exception: allow USB storage only for BMC virtual media devices (specific VID:PID/port) or only in break-glass mode with change control.

Mistake 5: “We wrote a udev rule, but it doesn’t trigger.”

Symptoms: You plug the device in and nothing happens; rule seems ignored.

Root cause: Matching is wrong (SUBSYSTEM vs SUBSYSTEMS), attributes don’t exist at that device node, or rule ordering conflicts.

Fix: Use udevadm info -a -p against the device path to find correct attributes; verify rule file name ordering; monitor with udevadm monitor.

Mistake 6: “We blocked new devices, but old sessions keep working.”

Symptoms: You apply policy but an already-connected device still functions.

Root cause: Enforcement applies on connect; existing mounts/drivers remain bound.

Fix: Unmount filesystems, bring interfaces down, and physically unplug/replug if needed. Validate with lsblk and ip link.

Checklists / step-by-step plan

Checklist A: Build a USB inventory you can defend

  1. Run lsusb on a known-clean host state and capture output in your config repo or CMDB export.
    Devices in “normal” state should not be a mystery.
  2. For each non-root-hub device, record: VID:PID, serial (if any), interface classes, and port path (from udevadm monitor or sysfs).
  3. For USB storage or NICs, map to OS nodes (lsblk, ip link) and document whether it’s allowed for that host class.
  4. Decide your host classes: datacenter servers, jump hosts, developer workstations, kiosks, edge appliances. Same policy for all is lazy and wrong.

Checklist B: Choose your enforcement layer (don’t over-engineer)

  1. If the rule is “no USB storage ever”: deny via modprobe config (and update initramfs). Simple, strong.
  2. If you need exceptions (UPS, serial console, specific dock Ethernet): deploy usbguard and use default-deny allowlisting.
  3. If you need a tactical block today: use udev authorization rules for specific VID:PID while you build proper policy.
  4. If automount exists: remove/disable it on servers. Don’t give USB storage a free runway.

Checklist C: Rollout plan that won’t brick your fleet

  1. Start in observe mode: deploy usbguard but log decisions; don’t block yet if you’re unsure. Then switch to block when you have policy.
  2. Pilot on a small set of hosts per class, including the weird ones (the ones with UPS, serial dongles, KVMs).
  3. Validate operational workflows: remote recovery, console access, UPS monitoring, out-of-band management.
  4. Add a break-glass procedure: a temporary policy override with strict change control and a clear rollback.
  5. Make USB policy a CI-reviewed artifact. If it’s not reviewable, it will drift until it fails.

Checklist D: Incident response when a rogue USB device is found

  1. Capture logs: journalctl -k events around insertion time, plus usbguard watch output if available.
  2. Identify what it enumerated as: storage/HID/network/serial.
  3. Contain: unmount storage, remove interfaces, unload modules if needed, and physically remove device.
  4. Assess: check shell history and sudo logs for injected commands if HID is suspected; check network changes if USB NIC appeared.
  5. Prevent recurrence: write explicit deny rules; then write the allowlist for required devices.

FAQ

1) Should I just disable all USB ports in BIOS/UEFI?

On servers that never need local input and have reliable out-of-band management, yes. It’s clean.
But many environments still need USB for KVMs, UPS monitoring, or break-glass recovery. Don’t pretend you don’t.

2) Is blocking usb_storage enough to stop USB drives?

Often, but not always. Some devices bind via UAS, and early boot module loading can bypass late policy.
Verify with lsmod, kernel logs, and by plugging in a test device after reboot.

3) Why not just block mounting and leave devices alone?

Because storage isn’t the only risk. HID can inject commands, and USB NICs can create new network paths.
“No automount” is good hygiene; it’s not a USB security policy.

4) Is usbguard safe to deploy broadly?

Yes, if you treat it like firewall policy: start with observation, generate policy from a known-clean state,
and roll out per host class. The dangerous version is enabling default-deny on a box you don’t fully understand.

5) What’s the most reliable identifier to allowlist?

Serial numbers are best when they exist and are stable. Next best is port path on fixed hardware.
VID:PID is helpful but not sufficient on its own.

6) How do I handle USB devices that legitimately change IDs after firmware updates?

Plan for it: treat firmware updates like any other change that can affect policy.
Use interface constraints and, where possible, allow by serial rather than only VID:PID.
Keep a staging environment to observe new IDs before production rollout.

7) What about “USB condom” data blockers?

They can reduce risk for charging-only scenarios, mostly on mobile devices. On servers, they’re not a strategy.
Your controls should be enforceable by policy and auditable, not dependent on someone using the right adapter under pressure.

8) Can I block only new USB devices but keep existing ones working?

Yes, conceptually: default-deny for new devices while allowlisting existing known-good devices.
Practically, you must still test reboots and re-enumeration because “existing” often becomes “new” after a reboot.

9) How do I audit USB usage across a fleet?

Collect lsusb, lsblk (USB transport), and usbguard logs centrally. Treat the output as inventory data.
The key is consistency: same commands, same parsing, scheduled runs, and alerts on drift.

Conclusion: next steps you can ship

USB is a reliability problem wearing a security hat. The fix is not a single command; it’s a policy you can explain, implement, and audit.
Start by learning what’s actually connected, then decide what each host class should permit, and enforce it with the simplest layer that meets the requirement.

  1. Today: Run the audit tasks on one representative host per class. Capture the baseline.
  2. This week: Disable automount services on servers and add emergency containment steps to your incident runbook.
  3. This month: Deploy usbguard where you need exceptions; otherwise block USB storage at the module layer. Roll out with pilots and change control.
  4. Ongoing: Treat USB policy like firewall policy—reviewed, versioned, and tested after hardware/firmware changes.

The goal is boring USB. Boring is stable, secure, and pleasantly uneventful. Production loves uneventful.

← Previous
Export Installed Drivers to a Folder (So Reinstalls Are Painless)
Next →
Windows Backup Lies: The 3 Settings That Decide Whether You Can Restore

Leave a comment