#!/usr/bin/env python3 """Render SM-023 from the summary. python3 -I make_page.py summary.json OUT.html""" import json, sys, os, html S = json.load(open(sys.argv[1])); OUT = sys.argv[2] HERE = os.path.dirname(os.path.abspath(__file__)); P = os.path.join(os.path.dirname(HERE), "ghsa", "page_parts") esc = html.escape d = lambda x: f"{x:g} days" if x is not None else "—" HD, CV, Y = S["hand_rated"], S["cvss_rated"], S["y2026"] CP, CK, CA = S["cvss_rated_from_publication"], S["cvss_rated_from_known"], S["cvss_rated_alt_release_ships"] MONTHS = {"2026-06": "June", "2026-07": "July", "2026-08": "August", "2026-09": "September", "2026-10": "October"} notfixed = len(S["no_fix_open_pro_days_since_raise"]); missed = CV["measured"] + notfixed SP, SL, KM = S["fixed_kernel_still_open_pro"], S["fixed_kernel_still_open_legacy"], S["known_minus_published"] NAMES = {"stonking": "26.10", "resolute": "26.04 LTS", "noble": "24.04 LTS", "jammy": "22.04 LTS", "focal": "20.04 LTS", "bionic": "18.04 LTS", "xenial": "16.04 LTS", "trusty": "14.04 LTS"} rn = lambda c: f"{NAMES.get(c, c)} ({c})" _dep = os.path.expanduser("~/second-measurements/zenodo/sm-023/deposit.json") DOI = json.load(open(_dep))["metadata"]["prereserve_doi"]["doi"] if os.path.exists(_dep) else "pending" EX = "sm-023/exhibits/" title = (f"Canonical says “critical vulnerabilities are released within 24 hours” in Ubuntu. Since June its security team has raised {CV['n']} kernel vulnerabilities " f"to critical from a CVSS score; of the {CV['measured']} fixed after being raised, none was fixed within a week, and the median wait was {CV['median_d']:g} days") desc = (f"Ubuntu’s security team sets each vulnerability’s priority, and Canonical says critical ones are released within 24 hours, across every supported release. " f"We read all {S['total_critical']} vulnerabilities Ubuntu rated critical on {S['read_at'][:10]}, the commit in the team’s public tracker that made each one critical, and the day its first fix reached users. " f"{CV['n']}, all Linux kernel, were recorded as medium and raised to critical from a CVSS score between June and October 2026. {CV['fixed_before_start']} were already fixed when raised, and one affects no Ubuntu release. None of the other {missed} was fixed within a day: {CV['measured']} were fixed a median {CV['median_d']:g} days later, none within a week, and {notfixed} were still waiting.") hand_rows = "".join( f"
{desc}
ubuntu-cve-tracker, the commit that first set each one’s Priority: line to critical; and the first fix that reached users, the earlier of its first security notice (USN) and the day the fixed package was published to the archive.6linux package as needed or pending on a release in standard or Ubuntu Pro support (read {S['read_at'][:10]}).Disclosure: Markovian Protocol holds no financial position in Canonical, was paid by no one for this work, and showed it to no one before publication. How we work.
| How the priority was set | Critical | Fixed | Fixed before rated critical | Timed | Within a day | Within a week | Median wait |
|---|---|---|---|---|---|---|---|
| By the team’s judgement | {HD['n']} | {HD['fixed']} | {HD['fixed_before_start']} | {HD['measured']} | {HD['within_1d']} | {HD['within_7d']} | {d(HD['median_d'])} |
| Raised from medium on a CVSS score | {CV['n']} | {CV['fixed']} | {CV['fixed_before_start']} | {CV['measured']} | {CV['within_1d']} | {CV['within_7d']} | {d(CV['median_d'])} |
Wait = first fix reaching users minus the first commit that set the vulnerability’s Priority: line to critical in ubuntu-cve-tracker. First fix = the earlier of the first USN and the first publication, in the Security, Updates or Release pocket and on or after that release’s own release date, of the fixed version the tracker lists for any release: the main linux package for kernel vulnerabilities, the vulnerability’s own package otherwise (Launchpad publishing history; versions kept in Ubuntu Pro’s private archive cannot be dated and are left out). “Fixed before rated critical” = a negative wait, left out of the timed columns. Livepatch notices (LSNs) exist for {S['lsn_cves']} of these vulnerabilities; none came before the first fix, so counting them changes nothing. Read at {S['read_at'][11:16]} UTC on {S['read_at'][:10]}.
The team-rated ones, all {HD['n']}:
| CVE | Published | Package | Priority reason | Rated critical to fix |
|---|
For the {CV['n']} raised on a CVSS score, other starts give longer waits, because they include the time each spent at medium, for which the FAQ’s figure is 60 days:
| Clock starts when | Timed | Within a day | Median |
|---|---|---|---|
| the vulnerability was published | {CP['measured']} | {CP['within_1d']} | {d(CP['median_d'])} |
| the team first recorded it (at medium) | {CK['measured']} | {CK['within_1d']} | {d(CK['median_d'])} |
| the team raised it to critical (used above) | {CV['measured']} | {CV['within_1d']} | {d(CV['median_d'])} |
Counting a new release that came out after a vulnerability was raised, already carrying the fix, as a fix on its release date changes nothing: {CA['timed']} timed, {CA['within_1d']} within a day, median {d(CA['median_d'])}. {S['cvss_never_affected'][0]} is left out of every count of waits, since no Ubuntu release carried it.
The FAQ applies the 24 hours “across every Ubuntu release actively supported”. On {S['read_at'][:10]}, {len(S['standard_releases'])} releases are in standard support and {len(S['pro_releases']) - len(S['standard_releases'])} more in Ubuntu Pro (ESM): {', '.join(rn(r) for r in S['pro_releases'])}. Of the {S['fixed_kernel']} critical kernel vulnerabilities with a fix somewhere, {SP['n']} still show the main linux package as needed or pending on at least one of them:
| Release | Critical kernel fixes still needed or pending |
|---|
Only the main linux source package is counted, not the dozens of kernel variants. “Pending” means a fix is prepared but not yet released. {', '.join(rn(r) for r in S['legacy_releases'])} are now covered only by the paid Legacy add-on, not Ubuntu Pro, and are left out above; on them {SL['n']} of the fixed critical kernel vulnerabilities are still open.5
Another {notfixed} critical kernel vulnerabilities had no fix released for the LTS releases that still need them on {S['read_at'][:10]}, {min(S['no_fix_open_pro_days_since_raise']):g} to {max(S['no_fix_open_pro_days_since_raise']):g} days after they were raised to critical. One of them, CVE-2023-53867, is already fixed in the kernels 24.04 and 26.04 LTS shipped with; it is still needed on 18.04, 20.04 and 22.04 LTS.
Canonical’s post of 23 September 2026 outlined “a transition from its current 4-week regular and 2-week security kernel Stable Release Update (SRU) cycles to a unified, rapid 2-week SRU cycle, published weekly”, with no date given for the change, and said that while a patch is prepared “Canonical aims to provide safe workarounds where applicable”.4 It went on: “Where no safe workaround exists, Canonical will say so clearly and point users toward general hardening steps instead.” Since that post, two vulnerabilities now rated critical were published; both were recorded as medium and raised to critical on 18 October 2026, two days before our read. On {S['read_at'][:10]}, CVE-2026-93221 had a fix pending for 26.04 LTS and still needed for 20.04, 22.04 and 24.04 LTS; CVE-2026-98365 had fixes pending for 24.04 and 26.04 LTS and still needed for 18.04, 20.04 and 22.04 LTS. 26.10 already ships a kernel containing both fixes. Neither had a USN, the mitigation field on each CVE page was empty, and searching Canonical’s blog, Ubuntu’s security notices and Ubuntu’s Discourse forum for each CVE found neither a workaround nor a statement that none exists (workaround_search_2026-10-20.json). On {S['read_at'][:10]}, Ubuntu’s web pages for both, and for CVE-2026-89530, still showed “Ubuntu priority Medium” (last updated 8 October, 25 September and 6 October) while Ubuntu’s CVE API and tracker said critical (saved pages: 98365, 93221, 89530).
Canonical can close it three ways: ship CVSS-rated critical kernel fixes within 24 hours; stop rating kernel vulnerabilities critical from a CVSS score alone, so that “critical” means what the team judges critical; or change the FAQ to say what kernel users should expect. We recheck monthly and print the table here.
What we told whom, and when.
| {S['read_at'][:10]} | Measured. Nobody has seen the page. |
Priority: line to critical in the public tracker; the CVSS v4 score is the one that commit added (“ubuntu: CVSS:4.0 … [9.x CRITICAL]”). The team may decide on a priority before pushing the commit, which would make the waits longer. On each commit’s author date instead of its push date, {S['cvss_rated_author_date']['timed']} can be timed, {S['cvss_rated_author_date']['within_7d']} within a week, median {d(S['cvss_rated_author_date']['median_d'])}.-proposed, which users get only if they opt in. 26.10 had some of these fixes during its development, before it was released on 15 October 2026.git clone --filter=blob:none --no-checkout https://git.launchpad.net/ubuntu-cve-tracker uct python3 known_dates.py exhibits/rows_2026-10-20.json uct known.json python3 crit_dates.py exhibits/ubuntu_critical_cves_raw_2026-10-20.json uct crit.json python3 fix_dates.py exhibits/ubuntu_critical_cves_raw_2026-10-20.json exhibits/ubuntu_releases_2026-10-20.json fixes.json python3 analyze.py exhibits/ubuntu_critical_cves_raw_2026-10-20.json known.json crit.json exhibits/ubuntu_releases_2026-10-20.json uct fixes.json summary.json # a fresh read of the live API instead of the saved one: python3 census.py raw_new.json rows_new.json
Needs Python 3 and git; Ubuntu’s CVE API and Launchpad’s are anonymous. The tracker clone takes a few minutes; known_dates.py about two, crit_dates.py about 35, since it fetches each file’s history. Scripts and exhibits: sm-023/.
ubuntu.com/security/cves.json?priority=critical (saved: ubuntu_critical_cves_raw_2026-10-20.json); ubuntu.com/security/releases.json; Launchpad publishing history (api.launchpad.net, saved as fixes_2026-10-20.json); ubuntu-cve-tracker git history (priority changes saved as crit_2026-10-20.json).