Description
APT trusts the keyrings in /etc/apt/trusted.gpg.d/, /etc/apt/keyrings/,
/usr/share/keyrings/ (and the legacy /etc/apt/trusted.gpg), and downloads from the
repositories listed in /etc/apt/sources.list and /etc/apt/sources.list.d/. These
directories should be root:root mode 0755 and their files root:root mode 0644 or
stricter.
On Debian 13, the files in /usr/share/keyrings/ named *.gpg are symbolic links to *.pgp
files. The check follows links and checks their target.
Rationale
A user able to add a key or a source entry can make APT install a package of their choice, with
maintainer scripts running as root, at the next update. Only root may change them. Reading them
is harmless: keys are public and APT's unprivileged _apt user needs to read them.
Impact
None known. Debian ships these files with these permissions.
Setting
| Location | /etc/apt/trusted.gpg.d, /etc/apt/keyrings, /usr/share/keyrings, /etc/apt/sources.list, /etc/apt/sources.list.d |
| Default | root:root, 0755 for directories and 0644 for files |
| Recommended | root:root, 0755 or stricter for directories, 0644 or stricter for files |
Audit
stat -c '%U:%G %a %n' /etc/apt/trusted.gpg.d /etc/apt/keyrings /usr/share/keyrings /etc/apt/sources.list.dshowsroot:rootand755or stricter.stat -L -c '%U:%G %a %n' /etc/apt/trusted.gpg /etc/apt/trusted.gpg.d/* /etc/apt/keyrings/* /usr/share/keyrings/* /etc/apt/sources.list /etc/apt/sources.list.d/*showsroot:rootand644or stricter for every existing file.
Automated: every check must pass. Scanners report each check by its id.
trusted-gpg-d
The /etc/apt/trusted.gpg.d directory.
path: /etc/apt/trusted.gpg.d
owner: root
group: root
mode: '0755'
etc-keyrings
The /etc/apt/keyrings directory.
path: /etc/apt/keyrings
owner: root
group: root
mode: '0755'
usr-share-keyrings
The /usr/share/keyrings directory.
path: /usr/share/keyrings
owner: root
group: root
mode: '0755'
key-files
Every keyring file APT can use, following symbolic links.
script: |
d="/etc/apt/trusted.gpg /etc/apt/trusted.gpg.d /etc/apt/keyrings /usr/share/keyrings"
# shellcheck disable=SC2086
bad=$(find -L $d -maxdepth 1 -type f \( ! -user root -o ! -group root -o -perm /7133 \) \
-exec stat -L -c '%n %U:%G %a' {} + 2>/dev/null)
if [ -n "$bad" ]; then
printf '%s\n' "$bad"
exit 1
fi
# shellcheck disable=SC2086
echo "$(find -L $d -maxdepth 1 -type f 2>/dev/null | wc -l) key files root:root 644 or stricter"
sources-list
The /etc/apt/sources.list file.
path: /etc/apt/sources.list
owner: root
group: root
mode: '0644'
sources-list-d
The /etc/apt/sources.list.d directory.
path: /etc/apt/sources.list.d
owner: root
group: root
mode: '0755'
sources-list-d-files
Files in /etc/apt/sources.list.d.
path: /etc/apt/sources.list.d/*
owner: root
group: root
mode: '0644'
Remediation
chown root:root /etc/apt/trusted.gpg.d /etc/apt/keyrings /usr/share/keyrings /etc/apt/sources.list.dandchmod go-won them.- For each key file and source file:
chown root:root <file>andchmod 644 <file>(or stricter).
| Restart | none |
| Disruption | none |
Rollback
Restore the previous owner and mode with chown and chmod. Nothing else depends on them.
trusted-gpg-d
Generated from check trusted-gpg-d: the engine writes the fix for every output, it sets the expected value and the check runs again after.
etc-keyrings
Generated from check etc-keyrings: the engine writes the fix for every output, it sets the expected value and the check runs again after.
usr-share-keyrings
Generated from check usr-share-keyrings: the engine writes the fix for every output, it sets the expected value and the check runs again after.
key-files
find -L /etc/apt/trusted.gpg /etc/apt/trusted.gpg.d /etc/apt/keyrings /usr/share/keyrings \
-maxdepth 1 -type f \( ! -user root -o ! -group root -o -perm /7133 \) 2>/dev/null |
while IFS= read -r f; do
chown root:root "$f" && chmod u-xs,go-wxs,o-t "$f" || exit 1
done
sources-list
Generated from check sources-list: the engine writes the fix for every output, it sets the expected value and the check runs again after.
sources-list-d
Generated from check sources-list-d: the engine writes the fix for every output, it sets the expected value and the check runs again after.
sources-list-d-files
Generated from check sources-list-d-files: the engine writes the fix for every output, it sets the expected value and the check runs again after.
Handwritten code reads parameters from CB_<NAME> environment variables. 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
- apt-secure(8), Debian manual pages Debian, vendor-doc, accessed 2026-10-18
- sources.list(5), Debian manual pages Debian, vendor-doc, accessed 2026-10-18
- Debian Wiki - DebianRepository/UseThirdParty Debian, vendor-doc, accessed 2026-10-18
Mappings
| Framework | ID | Relation |
|---|---|---|
| NIST SP 800-53 Rev. 55.1.1 | CM-5 | related |
| NIST SP 800-53 Rev. 55.1.1 | AC-3 | related |
How this control relates to the other framework's: equivalent, stricter, looser, partial or related.
Threats mitigated
Related controls
- related
CB-DEB-PKG-005Restrict access to APT repository credentials
People and lifecycle
| Authors |
|
| Verified | 2026-10-18 by Sn0wAlice on 12, Proxmox VM, Debian 12 genericcloud image, kernel 6.1.0-54-cloud-amd64. Passes on stock (Debian 13 keyring symlinks followed); writable keyring, foreign owner and group-writable sources.list.d detected and fixed; kept after reboot. |
| Verified | 2026-10-18 by Sn0wAlice on 13, Proxmox VM, Debian 13 genericcloud image, kernel 6.12.113+deb13-cloud-amd64. Passes on stock (Debian 13 keyring symlinks followed); writable keyring, foreign owner and group-writable sources.list.d detected and fixed; kept after reboot. |
| Introduced in | v0.1.0 |
| Created, updated | 2026-10-18, 2026-10-18 |
| Translations | fr |