There are two independent defects in the Debian packaging of
usbguard. Either one alone is enough for any local user in the
plugdev group to get full unauthenticated control of the daemon,
defeating the point of installing the package. Both are present in
trixie (1.1.3+ds-3) and unchanged on debian/sid HEAD (1.1.4+ds-2):
debian/org.usbguard1.rules and
debian/patches/0001-Set-IPCAllowedGroups-to-root-plugdev.patch
are both still in tree.
1) D-Bus / polkit rule
----------------------
debian/org.usbguard1.rules unconditionally returns
polkit.Result.YES for any active local member of plugdev or sudo on:
org.usbguard1.setParameter
org.usbguard.Policy1.appendRule
org.usbguard.Devices1.applyDevicePolicy
Upstream's org.usbguard1.policy requires auth_admin for these. The
Debian rule overrides that. No password, no agent prompt, no audit
gate. Same shape as CVE-2019-25058 (USBGuard before 1.1.0,
unprivileged user could let any USB device through over D-Bus,
NVD scored 7.8 high).
2) IPC ACL silently shadowed by IPCAllowedGroups
------------------------------------------------
debian/patches/0001-Set-IPCAllowedGroups-to-root-plugdev.patch sets
IPCAllowedGroups=root plugdev in the shipped usbguard-daemon.conf.
postinst then writes /etc/usbguard/IPCAccessControl.d/:plugdev with
Devices=list,modify,listen
Policy=list
Exceptions=listen
usbguard-daemon.conf(5) labels IPCAllowedUsers/Groups as Legacy and
IPCAccessControlFiles as Recommended. They are not meant to be
combined. In Daemon::loadConfiguration (src/Daemon/Daemon.cpp), the
legacy keys are processed first (around line 271) and call
addAllowedGroupname() with the default access control of
Section::ALL, Privilege::ALL. The ACL files are processed second
(around line 329) and call the same method with the parsed
restricted access control. The backing store is std::map
_allowed_groupnames and the insertion is std::map::emplace
(src/Library/IPCServerPrivate.cpp:1102), which is a no-op when the
key already exists. The restricted entry for plugdev is dropped at
startup. matchACLByName() then merges the ALL/ALL entry on every
authenticated IPC connection.
The postinst-generated :plugdev ACL file is dead code. The
README.Debian claim that the IPC ACL "takes precedence over
IPCAllowedGroups" is the opposite of what the daemon does.
PoC
---
Reproducer attached as usbguard-poc.sh, verified locally
(usbguard 1.1.3+ds-3). Set up a poc user in plugdev only (no sudo,
no polkit admin), block one device as root, then as poc:
$ usbguard append-rule 'allow id 1234:5678'
Rule ID: 9 # accepted, no auth
$ usbguard set-parameter ImplicitPolicyTarget allow
$ usbguard get-parameter ImplicitPolicyTarget
allow # changed by plugdev member
$ busctl --system call org.usbguard1 \
/org/usbguard1/Devices org.usbguard.Devices1 \
applyDevicePolicy uuu <id> 0 0
# exit 0, no prompt; device unblocked
The first two are defect 2 (IPC). The busctl call is defect 1
(polkit). Either is enough.
Fix
---
A merge request implementing the fix is open at
https://salsa.debian.org/birger/usbguard/-/merge_requests/6
Summary of changes:
a) Drop debian/patches/0001-Set-IPCAllowedGroups-to-root-plugdev.patch
from debian/patches/series. With the legacy directive gone, the
IPCAccessControlFile mechanism actually takes effect.
b) Remove debian/org.usbguard1.rules and its install line. Upstream's
auth_admin defaults then apply. Sites that want plugdev to skip
auth on D-Bus can ship their own rule under
/etc/polkit-1/rules.d/.
c) Stop hard-coding plugdev in postinst. Add a debconf question
usbguard/ipc-allowed-groups (string, default empty) listing the
groups that should get read-only IPC access. postinst generates a
/etc/usbguard/IPCAccessControl.d/:GROUP file for each preseeded
group with Devices=listen, Policy=list, Exceptions=listen. New
installs are root-only by default. Existing ACL files are not
touched on upgrade or reconfigure, so admin-managed sites keep
their settings.
Note on conffile coverage: /etc/usbguard/IPCAccessControl.d/* and
/etc/usbguard/rules.conf are generated in postinst and not declared
as conffiles. Postinst does guard regeneration on `[ ! -f rules.conf ]`,
so routine apt upgrade does not touch them. Reinstall and
dpkg-reconfigure paths can regenerate. With the patch above, that
generation is admin-controlled (debconf), but the files still live
outside dpkg's tracking. Out of scope for this bug; flagging.
Bug-Debian: #837175 introduced the IPCAllowedGroups widening; the
polkit rule postdates it. Both bypass the IPCAccessControlFile
hardening that the same postinst writes.
Hi, > Add `plugdev` to the IPCAllowedGroups setting. It's commonly the group > that is allowed to deal with pluggable devices, and it's not a big > compromise to allow them to decide what gets plugged in or not. So the users in the `plugdev` group don't "GET full unauthenticated control of the daemon", they "HAVE full unauthenticated control of the daemon" and that's on purpose. I'm happy to discuss changes in the default configuration of usbguard, though. But I'm not sure about the severity of the bug. cheers, Birger
Hi Birger,
928032 is about IPCAllowedGroups. List/listen access on the IPC channel, restricted by an IPCAccessControlFile. That is
not what I reported.
What I reported is debian/org.usbguard1.rules. Different file, different channel (D-Bus), different authorization
decision. Not in 928032. Not in upstream. Debian-specific. The subject of this bug is "plugdev gets full unauthenticated
control via D-Bus and IPC". You replied without mentioning D-Bus.
That polkit rule returns polkit.Result.YES for setParameter, appendRule, and applyDevicePolicy for any active local user
in plugdev or sudo. No password. Upstream sets auth_admin on those three actions in src/DBus/org.usbguard1.policy. The
Debian rule downgrades upstream's authorization model and ships it as the default.
The postinst-generated IPCAccessControlFile restricts plugdev to policy=list, devices=modify,list,listen, which
README.Debian correctly explains. The polkit rule routes around the ACL entirely via D-Bus. The same package contradicts
itself: the IPC channel says plugdev is list-only, the D-Bus channel says plugdev has full modify rights.
PoC from a plugdev user, no prompt:
busctl --system call org.usbguard1 /org/usbguard1/Devices \
org.usbguard.Devices1 applyDevicePolicy uuu <id> 0 0
Upstream's position is explicit. doc/usbguard-daemon.conf.5.adoc lines 123 to 125:
"Do not leave the ACL unconfigured as that will expose the IPC interface to all local users and will allow them to
manipulate the authorization state of USB devices and modify the USBGuard policy."
debian-installer (user-setup) adds the first non-root user, the only account d-i forces an admin to create, to plugdev
automatically. Along with audio, video, cdrom, dialout, and the rest. No prompt, no explanation. After apt install
usbguard, that user has unauthenticated applyDevicePolicy rights against the daemon the admin just installed to enforce
policy. The admin is never told this at any point. So a vanilla Debian install plus one apt command gives the first
account full daemon control with no password.
That is not "doesn't fit my use case". It is a privilege grant the admin never agreed to, defaulting to a user the
installer forced them to create.
Separate defect. /etc/usbguard/rules.conf and /etc/usbguard/IPCAccessControl.d/* are generated by postinst and are not
declared as conffiles. Admin edits to harden the IPC ACL silently regress on any postinst rerun: reinstall, divert,
remove and install. If a future maintainer changes the usbguard add-user arguments, that change propagates via routine
apt upgrade with no dpkg --conffile prompt. The package treats its own load-bearing security configuration as ephemeral.
Patch: https://salsa.debian.org/birger/usbguard/-/merge_requests/6. It drops the polkit rule and the IPCAllowedGroups
patch, and adds a debconf question with default empty so granting the privilege becomes a deliberate, preseedable action
by the admin instead of a hidden default.
Pétur
Hi, I replied trying to explain why unauthenticated control for users in the plugdev group is on purpose.
Right. Are you rejecting my PR?
We believe that the bug you reported is fixed in the latest version of
usbguard, which is due to be installed in the Debian FTP archive.
A summary of the changes between this version and the previous one is
attached.
Thank you for reporting the bug, which will now be closed. If you
have further comments please address them to 1134751@bugs.debian.org,
and the maintainer will reopen the bug report if appropriate.
Debian distribution maintenance software
pp.
Birger Schacht <birger@debian.org> (supplier of updated usbguard package)
(This message was generated automatically at their request; if you
believe that there is a problem with it please contact the archive
administrators by mailing ftpmaster@ftp-master.debian.org)
Format: 1.8
Date: Fri, 22 May 2026 18:39:26 +0200
Source: usbguard
Architecture: source
Version: 1.1.4+ds-4
Distribution: unstable
Urgency: medium
Maintainer: Birger Schacht <birger@debian.org>
Changed-By: Birger Schacht <birger@debian.org>
Closes: 1134751
Changes:
usbguard (1.1.4+ds-4) unstable; urgency=medium
.
* Drop 0001-Set-IPCAllowedGroups-to-root-plugdev.patch
The `IPCAllowedGroups` config option is marked as legacy for ages,
so we drop the override and rely only on the access control file
configuration approach (Closes: #1134751)
Adapted the usbguard.README.Debian to only mention the
`IPCAccessControlFile`.
* Add usr/lib/tmpfiles.d/usbguard.conf to debian/usbguard.install
Checksums-Sha1:
da6f3caa7ac20b73898a610b5996b1ea4b0a66c1 2630 usbguard_1.1.4+ds-4.dsc
a8c89e8ea46791eba52765ffcc0aacc9431fb9f5 10460 usbguard_1.1.4+ds-4.debian.tar.xz
6da7c6074621c4d27c3a737f7bd0b0e9fdadec95 517268 usbguard_1.1.4+ds-4.git.tar.xz
dbfea1f79db96cb9e40487abf5762117fbfe122c 17438 usbguard_1.1.4+ds-4_source.buildinfo
Checksums-Sha256:
577fb748d899004043482b2a61473f9a9539787e47c3988a92c52613d791b8ad 2630 usbguard_1.1.4+ds-4.dsc
3d7987b7b2c6b418566b3d100d6b4bcf6256aae2857593b5940badfb506d82f1 10460 usbguard_1.1.4+ds-4.debian.tar.xz
b8366bda88af7413c31db98ff76c664356d514b731d3668eb2e71c36f22a2863 517268 usbguard_1.1.4+ds-4.git.tar.xz
77caf081e9333a980ae097200167ba8b4d9307a6af11aa721651caf7ea5f19a4 17438 usbguard_1.1.4+ds-4_source.buildinfo
Files:
a5da5a2e29d760a09e27307b9041f847 2630 utils optional usbguard_1.1.4+ds-4.dsc
e82937a0f0b04fc38fbbe4b303c2d8ce 10460 utils optional usbguard_1.1.4+ds-4.debian.tar.xz
1a78341ee392a1eb811038bf2eafe226 517268 utils None usbguard_1.1.4+ds-4.git.tar.xz
8ec7447685741bbadacb531fed2bb99d 17438 utils optional usbguard_1.1.4+ds-4_source.buildinfo
Git-Tag-Info: tag=471f1631cc45128ec5da8bfa01287ad267926119 fp=3af0bcb67c26ac48ceb4e5bc2a0c5d60f204bdb0
Git-Tag-Tagger: Birger Schacht <birger@debian.org>
-----BEGIN PGP SIGNATURE-----
iQIzBAEBCgAdFiEEN02M5NuW6cvUwJcqYG0ITkaDwHkFAmoQikQACgkQYG0ITkaD
wHmJnBAAyP/wK9BYjArarF9LdRUKJ3CY/mT12PjfFKQLyt9YsENhiunEoS0MIiKi
2eQfKG/kiRcueHvIT3PmctKczp7vJ9fqWsoE477IKkBSBdppoo+w9BjtsA9olDRr
HhqLVCzAGfl8Y8reuOa7Ap1zCPFIzFwYwJJgdVeFGzkdPfH5+PlENfSIdqPjUqRx
wT5aOppuKWKSHRa5796KDRmAoQlGStpTtqjeAB9h6jHxDr/32CInWD6LOmo7wehG
eZH7I3rpfKu+MKxS9SDwPYbG9zZJ459rs8+C2Utfdm2HitCi8zKMvuksalvpId8/
+noNM5y7zmD3qZUOpTeY4Potpht1Rab95LsbrnUT0wCOf8AH9tnMpzPdLtxzGw8W
UtvLpCSnhIGBTZQ8y+OPFWU40SJL7WZJ70WxiThk7490j/pTnuLLMBScJzzR/S3N
0iYvOipz6v6I0l1EaKizOMKEwbVknPlIq3Zn0YKYBfC3Fje5POibMnRKaks3O2Kb
7pDRsdo+ylVmt9JjOkBrZYPyBM/ECcX5M7k0eWrSvBV982pyEeTIf/EDM45p42Wd
P4ysg4O+CBrUzGjI7g/0lqJCdXXPq+5u656UCAqd1AdajIK/PaEXL/6hjPc8TkcV
5pKcnsr65OqQeBhfkSXStNmL74Gjtm5++HdBDdgEPqA5NO+2rMo=
=O+/y
-----END PGP SIGNATURE-----