Skip to content
Français
Account: not signed in, sync available My learning
Select theme
Français

Apply security updates on Linux

By updated

Improve this page

Security updates fix known vulnerabilities (CVEs) in the kernel, the libraries and the installed services. On an exposed server, applying them quickly is the first line of defence. Each distribution provides a way to target only these patches, without pulling in functional version upgrades.

This guide shows the commands that work, and takes apart two widespread recipes that patch nothing at all while giving the reader the impression of having secured the machine. That is worse than no patch: it is an imaginary patch. All outputs were captured on 30 September 2026 on Debian 13, Ubuntu 24.04 and AlmaLinux 10.2.

What you will learn

  • Tell security updates apart from regular updates
  • List the available security patches on Debian/Ubuntu and on RHEL
  • Apply only the security patches, with verified commands
  • Configure automatic updates without them doing more than intended
  • Check that a patch is really installed, and whether a reboot is required
  • Recognise the two commands that patch nothing despite appearances

In what context?

Security updates are critical in any infrastructure:

  • A critical CVE is published for OpenSSL or the kernel, and you must patch within hours.
  • Your web server is exposed to the Internet, and every outdated package widens the attack surface.
  • Compliance imposes a maximum patching delay (30 days for the CIS or ANSSI frameworks).
  • You manage a fleet of servers and must automate without risking a regression.
  • Before an audit, you must prove that the system is up to date on critical CVEs.

Regular updates and security updates

TypeContentsRegression riskUrgency
SecurityCVE fixes, targeted patchesLow (minimal changes)High
BugfixFixes for functional bugsMediumMedium
FeatureNew features, version upgradesHighLow

In production, the strategy fits in one sentence: apply security automatically, and schedule the rest in a maintenance window.

A fourth case falls completely outside this table: the major version upgrade of the distribution, for instance from Debian 12 to Debian 13. It is not an update, it is a migration, with its preparations and its traps (network interface names may change, /etc/sysctl.conf stops being read, a badly stopped MariaDB database becomes unrecoverable). It cannot be automated: see Debian 13 "Trixie" (in French).

On Debian and Ubuntu

List the available security patches

Start by refreshing the package catalogue. This command changes nothing on the system:

Terminal window
sudo apt update

To see what is security-related, filter on the origin of the package, because that is what carries the information:

Terminal window
apt list --upgradable 2>/dev/null | grep -i security
libssl3t64/noble-security 3.0.13-0ubuntu3.6 amd64 [upgradable from: 3.0.13-0ubuntu3.4]
openssl/noble-security 3.0.13-0ubuntu3.6 amd64 [upgradable from: 3.0.13-0ubuntu3.4]

The -security suffix in the suite name (noble-security on Ubuntu, stable-security on Debian 13, which shows bsdutils/stable,stable-security) is what tells a security patch apart from a regular update.

The command that patches nothing

Here is the recipe found everywhere, and on this very site until this review:

Terminal window
# ❌ DO NOT DO THIS: this command installs nothing
sudo apt-get upgrade -y -o Dir::Etc::SourceList=/etc/apt/sources.list \
-o Dir::Etc::SourceParts=/dev/null

The idea looks clever: restrict APT to sources.list alone by neutralising the rest. It does not work, and the lab proves it. In simulation, measured on 30 September 2026:

Ubuntu 24.04 Debian 13
apt-get -s upgrade 36 packages 24 packages
apt-get -s upgrade -o Dir::Etc::SourceList=... 0 packages 0 packages

Dozens of updates available, zero applied. The reason is that the repositories have moved to the deb822 format: the real sources live in /etc/apt/sources.list.d/ubuntu.sources (or debian.sources), and /etc/apt/sources.list only contains comments on Ubuntu 24.04, when it has not simply disappeared, as in the Debian 13 image. The command therefore points to an empty file, and SourceParts=/dev/null excludes the file that matters. APT no longer sees any repository, so it has nothing to install.

The worst part is not that it fails, it is that it fails silently: it returns 0, shows no error, and you leave the server believing it is patched.

The method that works

The only tool that really knows what a security update is on Debian and Ubuntu is unattended-upgrades. It reads the origin of the packages, not their name.

Terminal window
sudo apt install unattended-upgrades
sudo unattended-upgrades --dry-run -v
Allowed origins are: o=Ubuntu,a=noble, o=Ubuntu,a=noble-security,
o=UbuntuESMApps,a=noble-apps-security, o=UbuntuESM,a=noble-infra-security
Packages that will be upgraded: gzip libncursesw6 libtinfo6 ncurses-base
ncurses-bin perl-base tar

Remove --dry-run to apply for real. But first read the Allowed origins line: it hides a trap.

Configure automatic updates

Automating security on Debian and Ubuntu takes four steps, and the automation is only reliable if all four are done: install the package, restrict the origins, enable periodic execution, then check that the list of origins matches the intent. Skipping the second step gives an automation that also applies functional updates.

  1. Install the package. apt-listchanges is useful to receive the details of what changed.

    Terminal window
    sudo apt install unattended-upgrades apt-listchanges
  2. Restrict to security patches. It is the step most tutorials skip, and it is the most important one.

    Terminal window
    sudo nano /etc/apt/apt.conf.d/50unattended-upgrades
    // Ubuntu 24.04 (on Debian 13, likewise comment out the first line of Origins-Pattern)
    Unattended-Upgrade::Allowed-Origins {
    // "${distro_id}:${distro_codename}"; // commented out: no functional updates
    "${distro_id}:${distro_codename}-security";
    };
    Unattended-Upgrade::Automatic-Reboot "false";
    Unattended-Upgrade::Mail "admin@example.com";
    Unattended-Upgrade::Remove-Unused-Dependencies "true";
    OptionRecommendation in production
    Allowed-Origins (Ubuntu) or Origins-Pattern (Debian)security only, the main repository line commented out
    Automatic-Rebootfalse: a reboot is scheduled, not suffered
    Mailan address someone really reads, otherwise the automation is blind
    Remove-Unused-Dependenciestrue to avoid piling up orphaned packages
  3. Enable the service. Without this command, the configuration exists but nothing runs it.

    Terminal window
    sudo dpkg-reconfigure -plow unattended-upgrades
  4. Check that the result matches the intent. It is the only proof that counts: the Allowed origins line must only contain security origins (noble-security on Ubuntu, label=Debian-Security on Debian).

    Terminal window
    sudo unattended-upgrades --dry-run -v | grep "Allowed origins"
    systemctl status apt-daily-upgrade.timer

Check what was applied

Terminal window
grep "^Upgrade:" /var/log/apt/history.log | tail -5
sudo tail -20 /var/log/unattended-upgrades/unattended-upgrades.log

The first file logs all the APT operations, the second only those of the automation. Comparing the two reveals updates applied by hand, outside the procedure. Do filter on ^Upgrade:: each transaction lists its packages there in the form Upgrade: tzdata:amd64 (2026b-0+deb13u1, 2026c-0+deb13u1), old then new version, whereas a grep " upgrade " only returns the Commandline: line of an apt upgrade typed by hand.

On RHEL, Rocky and AlmaLinux

List the security patches

DNF, for its part, understands the notion of a security patch natively, because Red Hat publishes advisories (errata) that link a package to a CVE:

Terminal window
sudo dnf updateinfo list security
ALSA-2026:59380 Moderate/Sec. attr-2.6.0-1.el10_2.x86_64
ALSA-2026:67886 Moderate/Sec. coreutils-single-9.5-8.el10_2.1.x86_64
ALSA-2026:33124 Moderate/Sec. coreutils-single-9.5-8.el10_2.x86_64

Each line carries an advisory identifier (RHSA at Red Hat, ALSA at AlmaLinux, RLSA at Rocky) and a severity. It is this metadata that makes targeting possible, and reliable.

Apply only the security patches

The --security option restricts the transaction to the packages covered by an advisory, and severity narrows it further when only the most urgent must go out now:

Terminal window
sudo dnf update --security

To handle only the most urgent ones, filter by severity:

Terminal window
sudo dnf update --security --sec-severity=Critical
SeverityWhen to apply
Criticalimmediately, without waiting for the maintenance window
Importantwithin 48 hours
Moderatescheduled maintenance window
Lownext maintenance

Automate with dnf-automatic

On the RHEL side, the automation is called dnf-automatic and follows the same logic as on Debian: a package, a configuration file to restrict, a systemd timer to enable. Its shipped configuration is not limited to security either, and it does not even install anything as long as apply_updates stays at no.

  1. Install the automation.

    Terminal window
    sudo dnf install dnf-automatic
  2. Restrict it to security, in /etc/dnf/automatic.conf:

    [commands]
    upgrade_type = security
    apply_updates = yes
    [emitters]
    emit_via = email,stdio
    [email]
    email_from = root@localhost
    email_to = admin@example.com

    The key is upgrade_type = security: its default value is default, which applies everything. The file shipped on AlmaLinux 10.2 also carries apply_updates = no: without switching it to yes, the automation downloads without installing.

  3. Enable the timer, otherwise the configuration stays a dead letter.

    Terminal window
    sudo systemctl enable --now dnf-automatic.timer
    systemctl status dnf-automatic.timer

Check what was applied

Terminal window
sudo dnf history list
sudo dnf history info last

dnf history is richer than its APT equivalent: each transaction can be undone with dnf history undo <id>, which offers a real rollback after an unfortunate update.

Check the patch level of a system

Is a specific package up to date?

Faced with a security advisory that names a package, the first question is simple: is the installed version the latest one published by the repositories? Each family answers it with one command, which compares the installed version with the candidate.

Terminal window
apt-cache policy openssl
openssl:
Installed: 3.0.13-0ubuntu3.6
Candidate: 3.0.13-0ubuntu3.6

If Installed equals Candidate, the package is up to date.

Do you need to reboot?

A patch to the kernel, glibc or systemd only takes effect after a reboot. The method differs by family.

Terminal window
[ -f /run/reboot-required ] && cat /run/reboot-required.pkgs

The file only exists if a package requested a reboot, and the second one names the culprits. Do use /run/: /var/run is only a symbolic link inherited from the past.

Update policy in production

EnvironmentSecurityFunctionalReboot
Dev / Testautomatic, immediateautomaticautomatic
Stagingautomatic, immediateweeklyscheduled
Productionautomatic, security onlymaintenance window, after validation in stagingmaintenance window

The rule that holds in production: security is automated, functional updates are scheduled, reboots are decided. The three are distinct decisions, and confusing them is the most frequent source of incidents related to updates.

Three safeguards complete the setup. Receive the reports by email, and read them: an automation whose output nobody reads is a blind automation. Test functional updates in staging before production. And do not postpone reboots indefinitely: an unapplied kernel patch protects against nothing.

Troubleshooting

Most problems come from a command that fails silently, or from an automation configured but never triggered. The table starts from the visible symptom.

SymptomProbable causeSolution
apt update fails on a keyRepository key expired or missingPut the key in /etc/apt/keyrings/ and declare it with Signed-By:. apt-key is gone from Debian 13, and only deprecated on Debian 12 and Ubuntu 24.04.
The "security only" command installs nothingsources.list is empty (deb822 format)Go through unattended-upgrades, the only tool that reads the origin of packages
dnf update --security does nothing on FedoraFedora publishes no security advisoriesUse plain dnf update
needs-restarting: command not foundStandalone command missing by default on RHELUse dnf needs-restarting, or dnf install yum-utils
unattended-upgrades also applies functional updatesThe main suite line is active by defaultComment it out in 50unattended-upgrades
The automation never runsTimer not enabledsystemctl enable --now apt-daily-upgrade.timer (or dnf-automatic.timer)
Update blocked by a conflictHeld package or broken dependencyapt --fix-broken install, or dnf distro-sync
Interrupted transactionOutage during the operationdpkg --configure -a, or dnf check then dnf distro-sync

Key points

  • Security updates fix CVEs: they come first, with a low regression risk.
  • Two widespread recipes patch nothing, silently and returning 0: the APT command with Dir::Etc::SourceList (sources.list is empty with deb822), and dnf --security on Fedora (which publishes no security advisory).
  • On Debian and Ubuntu, the only tool that really identifies security updates is unattended-upgrades: it reads the origin of packages, not their name.
  • Its default configuration is not limited to security, on Ubuntu as on Debian: the main suite line also allows functional updates. Comment it out in production.
  • On RHEL and its derivatives, dnf update --security works because Red Hat publishes advisories linking package and CVE. --sec-severity=Critical targets urgency.
  • On RHEL, dnf needs-restarting -r works out of the box, but the standalone needs-restarting command requires yum-utils. /run/reboot-required does not exist: it is a Debian reflex.
  • After a kernel patch, uname -r still shows the old one until you reboot. An up-to-date server running a vulnerable kernel is a failed audit.
  • In production: security is automated, functional updates are scheduled, reboots are decided.

Knowledge check

Check that the essentials of this guide are acquired. The questions only cover what has just been explained here.

Knowledge check

Check what you have learned with this interactive quiz

6 questions
6 min
70% to pass

How it works

  • The timer starts when you click Start
  • Multiple choice, true/false and short answer questions
  • You can move between questions
  • Detailed results are shown at the end

Starts the quiz and the timer

Is this project useful to you?

The guides, courses, quizzes and labs stay free. If you use them regularly, you can contribute to their upkeep and development.

Become a supporting member (new tab) One-time support (new tab) Learn more

Follow the project on LinkedIn