Plugging In a USB Drive — Sounds Simple, but It’s Actually Risky
Here’s something that happened to me once: a colleague left a USB drive on the desk, and someone picked it up and plugged it into their machine just to “check who it belonged to.” The result? A keylogger got silently installed on the computer. It sounds like something out of a movie, but this is an extremely real-world scenario — it’s a type of attack known as BadUSB.
What makes BadUSB so dangerous is that the device looks exactly like an ordinary USB drive, but its microcontroller has been reprogrammed to impersonate a keyboard, network adapter, or other HID device. Once plugged in, it automatically types commands, downloads malware, or opens a backdoor — all within seconds before you even realize what’s happening.
I’ve been using Fedora as my main development machine for about two years and I’m pretty happy with how fast packages get updated. One thing I noticed is that Fedora ships USBGuard in its official repositories — a tool that lets you precisely control which USB devices are allowed to operate on your system. It’s a layer of protection that many people overlook simply because they’ve never heard of it.
What Is USBGuard and How Does It Work?
USBGuard is a security daemon that runs at the kernel level, intercepting the USB enumeration process (when the system recognizes a newly connected device). Instead of letting the kernel automatically allow every device to connect, USBGuard checks it against a set of policy rules — similar to a firewall, but for USB devices.
There are 3 main policy states:
- allow — the device is permitted to function normally
- block — the device is disabled and cannot be used, but is still visible to the system
- reject — the device is completely rejected at the kernel level and is invisible to userspace
The key point: USBGuard doesn’t block by filename or virus signature. It blocks based on hardware characteristics — vendor ID, product ID, serial number, and interface class. So even if a device looks perfectly normal but declares itself as a keyboard (HID) when you’re only plugging in a USB storage device, it gets blocked immediately.
Installing USBGuard on Fedora
Fedora includes USBGuard in its default repository — one command and you’re done:
sudo dnf install usbguard usbguard-tools -y
After installation, enable and start the service:
sudo systemctl enable --now usbguard
Check that the service is running:
sudo systemctl status usbguard
Important note: If you enable USBGuard without any policy in place, the default behavior is to block all USB devices — including your keyboard and mouse. Make sure to generate a policy before enabling the service, especially if you’re connecting over SSH or using a USB keyboard.
Generating an Initial Policy from Currently Connected Devices
The simplest approach is to let USBGuard scan all currently connected devices and generate allow rules for them. Run this command before starting the service for the first time:
sudo usbguard generate-policy > /etc/usbguard/rules.conf
This command scans `/sys/bus/usb/devices/`, identifies all currently connected devices, and generates a policy file. Check the contents to verify:
cat /etc/usbguard/rules.conf
The output will look something like this:
allow id 1d6b:0002 serial "" name "xHCI Host Controller" hash "..." parent-hash "..." with-interface 09:00:00
allow id 046d:c52b serial "" name "USB Receiver" hash "..." parent-hash "..." with-interface { 03:01:01 03:00:00 }
allow id 058f:6387 serial "1234567890" name "Mass Storage" hash "..." parent-hash "..." with-interface 08:06:50
Each line is a rule for one device. The id field is the vendor:product ID, and with-interface is the interface class (03 = HID/keyboard, 08 = mass storage, 09 = hub).
Managing USB Devices in Real Time
Once the service is running, any new USB device you plug in will be blocked by the default policy. To list devices currently being blocked:
sudo usbguard list-devices
Output looks like:
1: allow id 1d6b:0002 serial "" name "xHCI Host Controller" ...
5: block id 0781:5591 serial "4C5300........" name "SanDisk Ultra" ...
The number at the start of each line is the device ID. To allow a device temporarily (until the next reboot):
sudo usbguard allow-device 5
To allow it permanently (adds the rule to rules.conf):
sudo usbguard allow-device --permanent 5
To block a currently allowed device:
sudo usbguard block-device 5
Writing Manual Policy Rules for Complex Cases
Sometimes you want more precise rules — for example, only allowing USB storage from a specific vendor. Open the rules file:
sudo nano /etc/usbguard/rules.conf
Example: allow only SanDisk USB storage devices (vendor ID 0781), and reject any device impersonating a keyboard (with-interface 03:01:01) except for the actual keyboard currently in use:
# Allow the Logitech keyboard currently in use
allow id 046d:c52b name "USB Receiver" with-interface { 03:01:01 03:00:00 }
# Allow any SanDisk USB with any product ID, mass storage interface only
allow id 0781:* with-interface 08:06:50
# Reject any device that declares itself as an HID keyboard but is not a known keyboard
reject with-interface 03:01:01
# Block everything else (not reject, so it still gets logged)
block
After editing, reload the policy:
sudo systemctl reload usbguard
Monitoring USB Events via the Audit Log
USBGuard integrates with the Linux audit subsystem. Every USB connection event is logged:
sudo journalctl -u usbguard -f
Or view the full audit log:
sudo ausearch -m USER_DEVICE | tail -20
This is the part I find most useful — when someone plugs a USB device into my machine while I’m away, the log immediately records the vendor ID, product ID, and timestamp. It makes post-incident investigation straightforward.
Configuring IPC Permissions to Use Without sudo
By default, only root can run the usbguard CLI. To give a regular user permission to list and allow devices without sudo every time, edit the IPC ACL file:
sudo nano /etc/usbguard/usbguard-daemon.conf
Find the IPCAllowedUsers line and add your username:
IPCAllowedUsers=root hieu
Or add by group:
IPCAllowedGroups=wheel
Restart the service to apply the changes:
sudo systemctl restart usbguard
Conclusion
USBGuard addresses the exact gap that conventional antivirus misses: malicious hardware devices that operate below the file system layer, where signature-based detection can’t reach. With just a few setup steps, you get a clear USB control layer — only whitelisted devices are allowed to run, and everything else is blocked at the source.
My current workflow: generate a policy on fresh install, add a reject with-interface 03:01:01 rule to block BadUSB keyboard impersonators, and enable audit logging. Whenever I plug in a new USB device, one usbguard allow-device --permanent command takes care of it. It becomes second nature quickly, and in return you get genuine peace of mind when working at a coffee shop or a shared office.
