13.4 APT Pinning and Package Authenticity
Key Takeaways
- APT pinning lives in /etc/apt/preferences and /etc/apt/preferences.d/, using stanzas of Package, Pin, and Pin-Priority to control which repository versions apt will install
- Priority thresholds: above 1000 permits downgrades, 990 is the default for the target release, 500 is a normal non-target source, 100 applies to installed versions, and 1 effectively means never install automatically
- Pinning kali-bleeding-edge to a low priority like 1 lets you pull individual packages from it with apt -t kali-bleeding-edge install without risking the whole system
- APT verifies each repository's Release file against GPG signatures before trusting any package from it; a NO_PUBKEY error means the signing key is missing from apt's keyring
- apt-key is deprecated; modern practice stores ASCII-armored keys as .asc files in /etc/apt/trusted.gpg.d/ or uses per-source signed-by= keyrings — the kali-archive-keyring package ships Kali's current signing key
Why Pinning Exists
A Kali system normally tracks a single repository — kali-rolling — and apt always installs the highest available version of each package. APT pinning is the mechanism for overriding that behavior: it lets you add extra repositories (such as kali-dev or kali-bleeding-edge, or even a Debian repo) while telling apt exactly how much to trust each one. Kali's kali-bleeding-edge archive already ships NotAutomatic: yes (together with ButAutomaticUpgrades: yes) in its Release file, so APT gives its versions a default priority of 100 instead of 500: apt upgrade will not pull a new package from it on its own, although it will keep upgrading packages you already installed from it. Pinning is what you need for sources that carry no such marker — a Debian suite, kali-dev, or a third-party repository — because those default to priority 500 and would compete with kali-rolling on version number alone.
Pinning configuration lives in /etc/apt/preferences and in files under /etc/apt/preferences.d/. Each stanza has three lines:
Package: *
Pin: release a=kali-bleeding-edge
Pin-Priority: 1
- Package: a package name, a glob like
nmap*, or*for everything. - Pin: the selection criterion — most commonly
releasewith fields such asa=(archive/suite, e.g.kali-rolling),o=(origin, e.g.o=Kali),n=(codename), orl=(label),c=(component) andv=(release version);version 1.2.3pins an exact version;origin "http.kali.org"pins by mirror hostname. - Pin-Priority: an integer that decides what apt may do with matching versions.
Check the effective result at any time with apt policy (overall priorities per source) and apt policy nmap (the candidate version for one package).
The Priority Ranges You Must Memorize
The exam expects you to know what each numeric band permits:
| Priority | Effect |
|---|---|
| P ≥ 1000 | Version is installed even if it means downgrading the currently installed package |
| 990 ≤ P < 1000 | Installed even if it is not from the target release, unless the installed version is newer |
| 500 ≤ P < 990 | Installed unless a version from the target release exists or the installed version is newer |
| 100 ≤ P < 500 | Installed only if no other source offers the package and the installed version is not newer |
| 0 < P < 100 | Never installed automatically; only installed if no version is installed at all and explicitly selected |
| P < 0 | Never installed under any circumstances |
Anchor the three numbers you will actually quote: 990 is the default priority of the target release (the suite apt prefers by default, settable with APT::Default-Release or overridable per command with apt -t kali-rolling), 500 is the default for every ordinary non-target source, and 100 is the priority of the currently installed version itself. The ≥1000 band is the famous one: it is the only priority that makes apt willing to downgrade, which is why hand-written version pins conventionally use 1001.
Pinning kali-bleeding-edge Safely
kali-bleeding-edge is Kali's untested, straight-from-upstream snapshot repository. A common defensive pattern — though not one the Kali documentation itself prescribes, since Kali documents apt install <package>/kali-bleeding-edge instead — is to add the repository but pin it so low that nothing comes from it unless you ask explicitly:
# /etc/apt/sources.list.d/bleeding-edge.list
deb http://http.kali.org/kali kali-bleeding-edge main contrib non-free non-free-firmware
# /etc/apt/preferences.d/bleeding-edge
Package: *
Pin: release a=kali-bleeding-edge
Pin-Priority: 1
With priority 1, apt upgrade ignores the bleeding-edge versions entirely. When you deliberately want one package from it, you override on the command line:
$ sudo apt -t kali-bleeding-edge install nmap
The -t flag raises that release to the target-release priority for this run only. This combination — low pin in preferences, explicit -t on demand — is the standard answer to "how do you test one bleeding-edge tool without destabilizing the system?" The same technique pins kali-dev low or holds a specific package version with Package: nmap / Pin: version 7.94* / Pin-Priority: 1001.
Multi-Arch Support
One more APT capability the book gives its own sub-section: multi-arch, which lets a single system install packages built for more than one architecture. The classic Kali case is running a 32-bit binary — an old exploit, a vendor tool, a Wine target — on an amd64 install.
Enable the foreign architecture once, refresh, then install with an explicit qualifier:
sudo dpkg --add-architecture i386
sudo apt update
sudo apt install libncurses6:i386
dpkg --print-foreign-architectures
dpkg --remove-architecture i386 reverses it, but only once no packages of that architecture remain installed. Package names take an :arch suffix wherever ambiguity is possible — apt install wine32:i386, dpkg -s libwine:amd64 — and dpkg -l shows the architecture in its own column.
What makes this work is a control field on every package. Multi-Arch: same means the package may be co-installed for several architectures at once because its files are architecture-qualified (typical of libraries under /usr/lib/<triplet>/). Multi-Arch: foreign means one installed copy can satisfy dependencies from any architecture (typical of architecture-independent tools). Multi-Arch: allowed lets a dependent choose, by writing pkg:any in its own dependency. A package carrying no Multi-Arch field at all cannot be co-installed for more than one architecture at a time, and cannot satisfy a dependency coming from a different architecture — which is why some 32-bit installs fail with dependency errors that no amount of pinning will fix.
How APT Authenticates Packages
Pinning controls which versions apt may install; package authenticity controls whether apt trusts them at all. APT's trust model works at the repository level, not the individual-package level:
- Every Kali repository publishes a Release file listing all package indexes (
Packages.xz, etc.) with their checksums. The signed copy isInRelease(inline signature) orReleaseplus a detachedRelease.gpg. - When you run
apt update, apt downloads the Release file and verifies its GPG signature against keys in apt's trusted keyrings. - Only then does apt trust the checksums inside that Release file — and every
.debit later downloads must match one of those checksums.
So the signature on the repository transitively guarantees every package in it. This is why Kali's mirrors can be ordinary HTTP mirrors run by volunteers: tampered packages would fail checksum verification.
apt-key Deprecation and Modern Key Management
Historically you added a repository key with apt-key add, but apt-key is deprecated: it stuffs every key into a single global trust file, meaning any key could sign for any repository. The modern approaches you should name on the exam:
- Drop an ASCII-armored key as a
.ascfile in/etc/apt/trusted.gpg.d/(binary keyrings use.gpg). Keys here are still globally trusted, but each is an individually managed file. - Better, give the source its own keyring: store the key in
/usr/share/keyrings/or/etc/apt/keyrings/and reference it withsigned-by=in the sources entry:
deb [signed-by=/usr/share/keyrings/kali-archive-keyring.gpg] http://http.kali.org/kali kali-rolling main contrib non-free non-free-firmware
With signed-by, that key can authenticate only that repository — the whole point of deprecating apt-key.
NO_PUBKEY Errors and kali-archive-keyring
The signature check fails loudly when the verifying key is absent:
W: GPG error: http://http.kali.org/kali kali-rolling InRelease:
The following signatures couldn't be verified because the public key is not available:
NO_PUBKEY ED65462EC8D5E4C5
A NO_PUBKEY error means apt fetched the Release file but has no matching public key in its keyring to check the signature, so it refuses to trust that repository's packages. On Kali the fix is normally trivial, because Kali distributes its own signing key as a package:
$ sudo apt update && sudo apt install kali-archive-keyring
The kali-archive-keyring package installs the current Kali repository signing key. In April 2025 Kali lost its old key ED444FF07D8D0BF6 and rotated to a new one, key ID ED65462EC8D5E4C5 (fingerprint 827C8569F2518CC677FECA1AED65462EC8D5E4C5) — a real-world event that produced this class of error on unpatched systems (current apt reports it as "Missing key 827C8569F2518CC677FECA1AED65462EC8D5E4C5, which is needed to verify signature" rather than the legacy NO_PUBKEY wording). Note the catch: because apt refuses the repository, you cannot install the keyring package from it, so Kali's documented fix is to fetch the keyring directly over HTTPS with sudo wget https://archive.kali.org/archive-keyring.gpg -O /usr/share/keyrings/kali-archive-keyring.gpg. One last trap: resist advice to bypass failures with --allow-insecure or Acquire::AllowInsecureRepositories — that disables the authenticity guarantee entirely, and the exam treats it as the wrong answer.
You add kali-bleeding-edge to your sources and create a preferences stanza Package: * / Pin: release a=kali-bleeding-edge / Pin-Priority: 1. What is the practical effect on routine apt upgrade runs?
After Kali rotated its repository signing key, apt update fails with Missing key 827C8569F2518CC677FECA1AED65462EC8D5E4C5, which is needed to verify signature. What does this error mean, and what is the correct fix?