Description
Each APT source entry names one or more URIs. The https method encrypts and authenticates
the connection to the mirror; http and ftp do not. Entries using mirror+file: point to a
local list of mirrors, whose URIs are checked too.
Every Ubuntu release, cloud images included, ships http://archive.ubuntu.com and
http://security.ubuntu.com (or http://<country>.archive.ubuntu.com after a desktop
installation): the control fails by default. archive.ubuntu.com, security.ubuntu.com and
ports.ubuntu.com serve HTTPS; the automated fix switches them. Country mirrors
(<country>.archive.ubuntu.com) are run by third parties and may not offer HTTPS with a valid
certificate: they are left to a human. The Ubuntu Pro repositories (esm.ubuntu.com) already
use HTTPS.
Rationale
APT verifies the signature of the Ubuntu archive whatever the transport, so HTTP does not let an attacker change packages. It still exposes the list of installed packages and their versions, which tells an attacker which vulnerabilities are left, and lets a network attacker serve stale but validly signed metadata until it expires, or block updates silently. HTTPS removes these exposures and is required for repositories that are not signed by their provider.
Impact
The system needs the ca-certificates package and outbound HTTPS. Caching proxies such as
apt-cacher-ng cannot cache HTTPS traffic they do not terminate: list their HTTP URIs in the
http_allowed_uris parameter rather than weaken the other controls.
Setting
| Location | /etc/apt/sources.list, /etc/apt/sources.list.d/*.list, /etc/apt/sources.list.d/*.sources |
| Default | http (archive.ubuntu.com, security.ubuntu.com) |
| Recommended | https (or a local method such as file:, cdrom:, copy:) for every URI, except those starting with: {{ http_allowed_uris }} |
Parameters
| Parameter | Core | Server | Server hardened | Desktop | Desktop hardened | Bounds |
|---|---|---|---|---|---|---|
http_allowed_urislist. URI prefixes allowed over plain HTTP, for example a local apt-cacher-ng proxy (http://apt-cache.example.org:3142/). Empty means none. | | | | | |
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 grep -rhiE '^[^#]*(http|ftp)://' /etc/apt/sources.list /etc/apt/sources.list.d/, and read
the files named after mirror+file: if any. Every URI must use https or a local method, or
start with one of the allowed prefixes.
Automated: every check must pass. Scanners report each check by its id.
uris
Transport of every URI of the enabled APT source entries, including mirror lists.
script: |
files=
for f in /etc/apt/sources.list /etc/apt/sources.list.d/*.list /etc/apt/sources.list.d/*.sources; do
[ -f "$f" ] && files="$files $f"
done
[ -n "$files" ] || { echo "no APT source file"; exit 2; }
# One line per entry: file:line, types, URIs, suites, ;option=value list (lowercase).
# shellcheck disable=SC2086
entries=$(awk '
function flush() { if (st && en != "no") print src "\t" ty "\t" ur "\t" su "\t" op; st = 0; ty = ur = su = op = en = "" }
FNR == 1 { flush(); d = FILENAME ~ /\.sources$/ }
!d {
sub(/#.*/, ""); if ($1 !~ /^deb(-src)?$/) next
l = $0; o = ""; i = index(l, "["); j = index(l, "]")
if (i && j > i) { o = substr(l, i + 1, j - i - 1); l = substr(l, 1, i - 1) " " substr(l, j + 1) }
split(l, w, " "); gsub(/[ \t]+/, ";", o)
print FILENAME ":" FNR "\t" w[1] "\t" w[2] "\t" w[3] "\t;" tolower(o); next
}
/^#/ { next }
/^[ \t]*$/ { flush(); next }
/^[ \t]/ { next }
{
if (!st) { st = 1; src = FILENAME ":" FNR }
k = $0; sub(/:.*/, "", k); k = tolower(k); v = $0; sub(/^[^:]*:[ \t]*/, "", v)
if (k == "types") ty = v; else if (k == "uris") ur = v; else if (k == "suites") su = v
else if (k == "enabled") en = tolower(v)
else op = op ";" k "=" tolower(v == "" ? "inline" : v)
}
END { flush() }' $files)
bad=$(printf '%s\n' "$entries" | while IFS="$(printf '\t')" read -r src _ uris _ _; do
for u in $uris; do
case $u in
mirror+file:*)
p=$(printf '%s' "$u" | sed 's#^mirror+file:/*#/#')
[ -f "$p" ] || { echo "$src: $u (missing mirror list)"; continue; }
list=$(grep -v '^[[:space:]]*#' "$p" 2>/dev/null | awk '{ print $1 }') ;;
*) list=$u ;;
esac
for m in $list; do
case $m in https://* | tor+https://* | mirror+https://* | file:* | cdrom:* | copy:*) continue ;; esac
for a in ${CB_HTTP_ALLOWED_URIS:-}; do
case $m in "$a"*) continue 2 ;; esac
done
echo "$src: $m"
done
done
done)
n=$(printf '%s\n' "$entries" | grep -c .)
if [ -n "$bad" ]; then
printf '%s\n' "$bad"
exit 1
fi
echo "$n entries, all over https or a local method"
Remediation
- Install
ca-certificates. - In each source entry, and in the mirror lists named after
mirror+file:, replacehttp://withhttps://when the mirror serves HTTPS (archive.ubuntu.com,security.ubuntu.comandports.ubuntu.comdo). Pick another mirror otherwise. - Run
apt-get updateand check that it prints no error.
| Restart | none |
| Disruption | low |
Rollback
Restore the source files from the backup directory printed by remediate.sh, or replace
https:// with http:// again.
https-ubuntu
#!/bin/sh
# CB-UBU-PKG-002 / https-ubuntu - switch the Ubuntu archive entries from HTTP to HTTPS.
# Only archive.ubuntu.com, security.ubuntu.com and ports.ubuntu.com are changed: Canonical serves
# them over HTTPS. Country mirrors and other hosts need a human. Hosts listed in
# CB_HTTP_ALLOWED_URIS are left alone. Idempotent, no-op when compliant.
# SPDX-License-Identifier: Apache-2.0
set -eu
files=
for f in /etc/apt/sources.list /etc/apt/sources.list.d/*.list /etc/apt/sources.list.d/*.sources; do
[ -f "$f" ] && files="$files $f"
done
[ -n "$files" ] || exit 0
# Mirror lists referenced as mirror+file: hold the real URIs.
# shellcheck disable=SC2086
for p in $(grep -hoE 'mirror\+file:/*[^[:space:]]+' $files | sed -E 's#^mirror\+file:/*#/#' | sort -u); do
[ -f "$p" ] && files="$files $p"
done
for host in archive security ports; do
for a in ${CB_HTTP_ALLOWED_URIS:-}; do
case $a in *"://$host.ubuntu.com"*) continue 2 ;; esac
done
for f in $files; do
grep -Eq "(^|[[:space:]+])http://$host\.ubuntu\.com/" "$f" || continue
if [ ! -s /etc/ssl/certs/ca-certificates.crt ]; then
echo "ca-certificates is not installed, APT could not check the HTTPS servers" >&2
exit 1
fi
cb_backup "$f"
sed -E -i "s#(^|[[:space:]+])http://$host\.ubuntu\.com/#\1https://$host.ubuntu.com/#g" "$f"
done
done
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
- sources.list(5), Ubuntu manual pages Canonical, vendor-doc, accessed 2026-10-19
- apt-transport-https(1), Ubuntu manual pages Canonical, vendor-doc, accessed 2026-10-19
- Ubuntu Server documentation - Package management Canonical, vendor-doc, accessed 2026-10-19
Mappings
| Framework | ID | Relation |
|---|---|---|
| NIST SP 800-53 Rev. 55.1.1 | SC-8 | related |
How this control relates to the other framework's: equivalent, stricter, looser, partial or related.
Threats mitigated
Related controls
- related
CB-UBU-PKG-001Bind every APT repository to its signing key
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. Fails on stock (http archive and security); fix switches archive/security.ubuntu.com to https (and a test .list), apt-get update works without warning; idempotent, kept after reboot. |
| Verified | 2026-10-19 by Sn0wAlice on 22.04, Proxmox VM, Ubuntu 22.04 cloud image, kernel 5.15.0-198-generic. Fails on stock (http archive and security); fix switches archive/security.ubuntu.com to https (and a test .list), apt-get update works without warning; idempotent, kept after reboot. |
| Verified | 2026-10-19 by Sn0wAlice on 24.04, Proxmox VM, Ubuntu 24.04 cloud image, kernel 6.8.0-147-generic. Fails on stock (http archive and security); fix switches archive/security.ubuntu.com to https (and a test .list), apt-get update works without warning; idempotent, kept after reboot. |
| Verified | 2026-10-19 by Sn0wAlice on 26.04, Proxmox VM, Ubuntu 26.04 cloud image, kernel 7.0.0-38-generic. Fails on stock (http archive and security); fix switches archive/security.ubuntu.com to https (and a test .list), apt-get update works without warning; idempotent, kept after reboot. |
| Introduced in | v0.1.0 |
| Created, updated | 2026-10-19, 2026-10-19 |
| Translations | fr |