Debian GNU/Linux · Desktop environment

Allow only known USB devices with USBGuard

When it fails: Any USB device plugged into the machine is accepted. A malicious keyboard emulator, network adapter or storage device is enabled as soon as it is plugged in.

CB-DEB-DESK-012mediumactiveautomatedautomated fix, lockout riskprofile desktop-hardened

As released in v0.1.1 beta · pre-release. Current state.

Description

USBGuard is a daemon that authorizes each USB device against a rule list (/etc/usbguard/rules.conf). On first install, the Debian package writes a rule for every device present, then starts the daemon. With ImplicitPolicyTarget=block (the default), devices that match no rule are blocked.

The fix installs the package and enables the service; it is disabled by default because a missing rule can block the only keyboard. The check verifies the daemon configuration and service, not the content of the rule list: review it with usbguard list-rules. The control is not applicable when the kernel has no USB support (/sys/bus/usb absent, as with Debian's cloud kernels), since the daemon cannot start there.

Rationale

USB attacks rely on the system trusting whatever is plugged in: a "rubber ducky" types commands as a keyboard, a rogue network adapter reroutes traffic, a storage device carries malware. An allow list built from the devices the user actually has stops these attacks on an unattended or lent machine.

Impact

New USB devices (a different keyboard, a docking station, a phone, a USB stick) are blocked until an administrator allows them with usbguard allow-device and adds a rule with usbguard append-rule or by regenerating the policy. Devices unplugged at installation time are not in the policy: plug in every regular device before applying the fix.

Applies when

Detected: when: The kernel has USB support A scanner reports the control not applicable when one is false.

Setting

Location/etc/usbguard/rules.conf, /etc/usbguard/usbguard-daemon.conf
DefaultNot installed
Recommendedusbguard installed and active, ImplicitPolicyTarget=block, rules from the present devices

Audit

  1. dpkg -s usbguard shows the package installed.
  2. systemctl is-enabled usbguard prints enabled and systemctl is-active usbguard prints active.
  3. /etc/usbguard/usbguard-daemon.conf sets ImplicitPolicyTarget=block and /etc/usbguard/rules.conf exists.
  4. usbguard list-rules lists the expected devices.

Automated: every check must pass. Scanners report each check by its id.

package

USBGuard is installed.

name: usbguard
state: installed

service

The USBGuard daemon starts at boot.

unit: usbguard.service
state: enabled

policy

The daemon runs and blocks devices that match no rule.

script: |
  c=/etc/usbguard/usbguard-daemon.conf
  [ -f "$c" ] || { echo "$c missing"; exit 1; }
  t=$(sed -n 's/^[[:space:]]*ImplicitPolicyTarget[[:space:]]*=[[:space:]]*//p' "$c" | tail -n 1)
  r=$(sed -n 's/^[[:space:]]*RuleFile[[:space:]]*=[[:space:]]*//p' "$c" | tail -n 1)
  a=$(systemctl is-active usbguard 2>/dev/null)
  n=$(grep -c '^[[:space:]]*[a-z]' "${r:-/nonexistent}" 2>/dev/null)
  echo "ImplicitPolicyTarget=${t:-unset} RuleFile=${r:-unset} rules=${n:-none} service=${a:-unknown}"
  [ "$t" = block ] && [ -n "$r" ] && [ -f "$r" ] && [ "$a" = active ]

Remediation

  1. Plug in every USB device used regularly.
  2. apt install usbguard. On first install, the package writes /etc/usbguard/rules.conf from the devices present and starts the daemon.
  3. Check the rules with usbguard list-rules, then systemctl enable --now usbguard.
  4. Check that ImplicitPolicyTarget=block is set in /etc/usbguard/usbguard-daemon.conf.
Restartnone
Disruptionhigh
Lockout riskyes: can cut off administrative access. Off by default in generated scripts and playbooks, opt in through a tailoring file.

Rollback

systemctl disable --now usbguard (blocked devices are authorized again when replugged), or apt purge usbguard.

package

Generated from check package: the engine writes the fix for every output, it sets the expected value and the check runs again after.

service

Generated from check service: the engine writes the fix for every output, it sets the expected value and the check runs again after.

Each release turns these fixes into remediate.sh and an Ansible role per profile: dry run by default, a fix runs only when its check fails.

References

Mappings

FrameworkIDRelation
NIST SP 800-53 Rev. 55.1.1IA-3related
NIST SP 800-53 Rev. 55.1.1CM-8(3)related

How this control relates to the other framework's: equivalent, stricter, looser, partial or related.

Threats mitigated

  • related CB-DEB-DESK-001 Disable automatic mounting of removable media in GNOME

People and lifecycle

Authors
Verified2026-10-18 by Sn0wAlice on 12, Proxmox VM with minimal GNOME, Debian 12, generic kernel 6.1.0-54-amd64. Not applicable on the cloud kernel (no USB support). With the generic kernel and a UHCI controller: package installed, policy generated from present devices by the package, daemon active, root hub still authorized; state kept after reboot.
Verified2026-10-18 by Sn0wAlice on 13, Proxmox VM with minimal GNOME, Debian 13, generic kernel 6.12.113+deb13-amd64. Not applicable on the cloud kernel (no USB support). With the generic kernel and a UHCI controller: package installed, policy generated from present devices by the package, daemon active, root hub still authorized; state kept after reboot.
Introduced inv0.1.0
Created, updated2026-10-18, 2026-10-18
Translationsfr