Description
apt-get -s dist-upgrade simulates an upgrade from the local package lists and shows, for each
package, the version and origin of the update. Updates coming from a security pocket
(<codename>-security, or <codename>-infra-security and <codename>-apps-security from
Ubuntu Pro ESM) fix vulnerabilities. The result is only as fresh as the package lists, refreshed by apt-get update
or apt-daily.timer.
The check fails on pending security updates and on package lists older than
{{ max_lists_age }} days (newest Release file or
/var/lib/apt/periodic/update-success-stamp), since stale lists hide pending updates. Other
pending updates (-updates, backports) are only listed in the evidence. The check does not
run apt-get update: refresh the lists first for an up-to-date answer.
Phased updates: Ubuntu releases some -updates (SRU) to a growing share of systems, and apt
(22.04 and later) holds them back on the others. Security pockets are never phased, so a
deferred update is never a pending security fix; deferred packages are counted in the evidence
only. ESM updates are only visible on systems attached to Ubuntu Pro: on a 20.04 system that is
not attached, the check passes while pro security-status lists ESM fixes it cannot install.
CB-UBU-PKG-009 catches that case.
Rationale
An available security update means the vulnerability is public and a fix exists, which is when exploitation is most likely. Checking for pending security updates catches systems where automatic updates are disabled, broken, or blocked by a held package or a dependency change.
Impact
None for the check, which changes nothing. Installing updates restarts the services concerned.
Parameters
| Parameter | Core | Server | Server hardened | Desktop | Desktop hardened | Bounds |
|---|---|---|---|---|---|---|
max_lists_ageinteger, days. Maximum age of the newest package list before the check fails. | 7 | 7 | 7 | 7 | 7 | 1 to 90 |
The value used is your override (tailoring file), else the profile's, else the one of the profile it extends, else the default. Bounds limit what an override may set.
Audit
- Run
apt-get update. - Run
apt-get -s dist-upgrade | grep '^Inst' | grep -i security. It must print nothing.
Automated: every check must pass. Scanners report each check by its id.
pending
Updates pending in the local package lists, and the age of these lists.
script: |
s=$(LC_ALL=C apt-get -s -o Debug::NoLocking=1 dist-upgrade 2>/dev/null) || { echo "apt-get simulation failed"; exit 3; }
all=$(printf '%s\n' "$s" | grep -c '^Inst ')
sec=$(printf '%s\n' "$s" | grep '^Inst ' | grep -E '\(.*-security' | awk '{ print $2 }')
nsec=$(printf '%s' "$sec" | grep -c .)
# apt dates the Release files with the archive's Last-Modified: also use the stamp that
# Ubuntu touches after each successful apt-get update.
newest=$(find /var/lib/apt/lists /var/lib/apt/periodic -maxdepth 1 \( -name '*Release' -o -name update-success-stamp \) -printf '%T@\n' 2>/dev/null | sort -n | tail -1)
age=999
[ -n "$newest" ] && age=$(( ($(date +%s) - ${newest%.*}) / 86400 ))
ph=$(printf '%s\n' "$s" | sed -n '/deferred due to phasing/,/^[^ ]/p' | grep '^ ' | wc -w)
echo "$all pending, $nsec security ($(printf '%s' "$sec" | head -20 | tr '\n' ' ')), $ph deferred by phasing, lists $age days old"
[ "$nsec" -eq 0 ] && [ "$age" -le "$CB_MAX_LISTS_AGE" ]
Remediation
Run apt-get update then apt-get dist-upgrade (or unattended-upgrade for security
updates only, which also installs ESM updates on attached systems), during a maintenance
window if services must not restart. Reboot when the kernel, libc or systemd were updated (/var/run/reboot-required exists, see CB-UBU-PKG-013). If a
package is held (apt-mark showhold), find out why before releasing it.
References
- apt-get(8), Ubuntu manual pages Canonical, vendor-doc, accessed 2026-10-19
- Ubuntu Server documentation - About apt upgrade and phased updates Canonical, vendor-doc, accessed 2026-10-19
- ANSSI-BP-028 v2.0 - Recommandations de configuration d'un système GNU/Linux (R61) ANSSI, guide, accessed 2026-10-19
Mappings
| Framework | ID | Relation | Note |
|---|---|---|---|
| ANSSI-BP-028 - Recommandations de configuration d'un système GNU/Linux2.0 | R61 | partial | R61 asks for a regular update process; this control checks its result for security updates. |
| NIST SP 800-53 Rev. 55.1.1 | SI-2 | related |
How this control relates to the other framework's: equivalent, stricter, looser, partial or related.
Threats mitigated
Related controls
- related
CB-UBU-PKG-007Install security updates automatically - related
CB-UBU-PKG-013Reboot after updates that require it, or use Livepatch
People and lifecycle
| Authors |
|
| Verified | 2026-10-19 by Sn0wAlice on 20.04, Proxmox VM, Ubuntu 20.04 cloud image, kernel 5.4.0-216-generic. Passes on up-to-date VM; fails after downgrading libexpat1 below its security version and with lists older than max_lists_age; passes after upgrade and after apt-get update (update-success-stamp). |
| Verified | 2026-10-19 by Sn0wAlice on 22.04, Proxmox VM, Ubuntu 22.04 cloud image, kernel 5.15.0-198-generic. Passes on up-to-date VM; fails after downgrading libexpat1 below its security version and with lists older than max_lists_age; passes after upgrade and after apt-get update (update-success-stamp). |
| Verified | 2026-10-19 by Sn0wAlice on 24.04, Proxmox VM, Ubuntu 24.04 cloud image, kernel 6.8.0-147-generic. Passes on up-to-date VM; fails after downgrading libexpat1 below its security version and with lists older than max_lists_age; passes after upgrade and after apt-get update (update-success-stamp). |
| Verified | 2026-10-19 by Sn0wAlice on 26.04, Proxmox VM, Ubuntu 26.04 cloud image, kernel 7.0.0-38-generic. Passes on up-to-date VM; fails after downgrading libexpat1 below its security version and with lists older than max_lists_age; passes after upgrade and after apt-get update (update-success-stamp). |
| Introduced in | v0.1.0 |
| Created, updated | 2026-10-19, 2026-10-19 |
| Translations | fr |