Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 12 additions & 12 deletions content/posts/python-31022-31117/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,29 +30,29 @@ Python 3.12.15 is also a source-only security release, with security support con

## Security content in all five releases

* [gh-158446](https://github.com/python/cpython/issues/158446): Fix crashes or incorrect output when formatting float or complex values with precision close to INT_MAX.
* [CVE-2026-19553](https://www.cve.org/CVERecord?id=CVE-2026-19553) — [gh-156793](https://github.com/python/cpython/issues/156793): `ssl.SSLContext.wrap_bio()` now validates its `server_side`, `server_hostname`, and `session` arguments. `asyncio` also validates TLS `server_hostname` arguments. On Python 3.10, 3.11, and 3.12, missing hostnames with `check_hostname` enabled emit `DeprecationWarning` for compatibility; they raise `ValueError` on Python 3.13 and later.
* [CVE-2026-82049](https://www.cve.org/CVERecord?id=CVE-2026-82049) — [gh-157190](https://github.com/python/cpython/issues/157190): Fix a tarfile extraction-filter vulnerability involving hard links to symbolic links that could expose files outside the destination and change their permissions or modification times.
* [gh-157953](https://github.com/python/cpython/issues/157953): Update bundled libexpat to version 2.8.5.
* [CVE-2026-15310](https://www.cve.org/CVERecord?id=CVE-2026-15310) — [gh-156002](https://github.com/python/cpython/issues/156002): Bound `zipfile` decompression per read for bzip2 and LZMA members, and for Zstandard members on Python 3.14, preventing unbounded allocations from small compressed members. Third-party decompressors supplied by monkey-patching `_get_decompressor()` that lack `needs_input` and two-argument `decompress()` remain vulnerable.
* [CVE-2026-19672](https://www.cve.org/CVERecord?id=CVE-2026-19672) — [gh-155999](https://github.com/python/cpython/issues/155999): Prevent tarfile extraction filters from creating directories outside the destination for paths that leave it and then return.
* [CVE-2026-19445](https://www.cve.org/CVERecord?id=CVE-2026-19445) — [gh-156293](https://github.com/python/cpython/issues/156293): Fix an ssl crash when an SNI callback switches contexts and the original callback context is no longer referenced.
* [CVE-2026-17084](https://www.cve.org/CVERecord?id=CVE-2026-17084) — [gh-155292](https://github.com/python/cpython/issues/155292): Restrict stringprep and the IDNA codec to Unicode codepoint attributes defined by RFC 3454.
* [CVE-2026-15806](https://www.cve.org/CVERecord?id=CVE-2026-15806) — [gh-155694](https://github.com/python/cpython/issues/155694): Scope urllib.request HTTPPasswordMgr credentials by URL scheme to prevent HTTPS credentials from being used for matching HTTP URLs.
* gh-158446: Fix crashes or incorrect output when formatting float or complex values with precision close to INT_MAX.
* CVE-2026-19553 — gh-156793: `ssl.SSLContext.wrap_bio()` now validates its `server_side`, `server_hostname`, and `session` arguments. `asyncio` also validates TLS `server_hostname` arguments. On Python 3.10, 3.11, and 3.12, missing hostnames with `check_hostname` enabled emit `DeprecationWarning` for compatibility; they raise `ValueError` on Python 3.13 and later.
* CVE-2026-82049 — gh-157190: Fix a tarfile extraction-filter vulnerability involving hard links to symbolic links that could expose files outside the destination and change their permissions or modification times.
* gh-157953: Update bundled libexpat to version 2.8.5.
* CVE-2026-15310 — gh-156002: Bound `zipfile` decompression per read for bzip2 and LZMA members, and for Zstandard members on Python 3.14, preventing unbounded allocations from small compressed members. Third-party decompressors supplied by monkey-patching `_get_decompressor()` that lack `needs_input` and two-argument `decompress()` remain vulnerable.
* CVE-2026-19672 — gh-155999: Prevent tarfile extraction filters from creating directories outside the destination for paths that leave it and then return.
* CVE-2026-19445 — gh-156293: Fix an ssl crash when an SNI callback switches contexts and the original callback context is no longer referenced.
* CVE-2026-17084 — gh-155292: Restrict stringprep and the IDNA codec to Unicode codepoint attributes defined by RFC 3454.
* CVE-2026-15806 — gh-155694: Scope urllib.request HTTPPasswordMgr credentials by URL scheme to prevent HTTPS credentials from being used for matching HTTP URLs.

## Additional security content by version

### Python 3.10.22, 3.11.17, 3.12.15 and 3.13.16

* [CVE-2026-87910](https://www.cve.org/CVERecord?id=CVE-2026-87910) — [gh-157265](https://github.com/python/cpython/issues/157265): Apply tarfile extraction filters when a link falls back to extracting an archive member, skipping members rejected by the filter.
* CVE-2026-87910 — gh-157265: Apply tarfile extraction filters when a link falls back to extracting an archive member, skipping members rejected by the filter.

### Python 3.13.16 and 3.14.8

* [gh-158010](https://github.com/python/cpython/issues/158010): Update bundled OpenSSL to [3.5.9](https://openssl-library.org/news/secadv/20260929.txt). In Python 3.13.16 this applies to Windows, macOS and Android, moving from OpenSSL 3.0.21 to the 3.5 LTS series. In Python 3.14.8 it applies to Windows, macOS, Android and iOS. The source-only Python 3.10–3.12 releases do not bundle OpenSSL.
* gh-158010: Update bundled OpenSSL to [3.5.9](https://openssl-library.org/news/secadv/20260929.txt). In Python 3.13.16 this applies to Windows, macOS and Android, moving from OpenSSL 3.0.21 to the 3.5 LTS series. In Python 3.14.8 it applies to Windows, macOS, Android and iOS. The source-only Python 3.10–3.12 releases do not bundle OpenSSL.

### Python 3.10.22

* [gh-149018](https://github.com/python/cpython/issues/149018): Improve protection against XML hash-flooding attacks in `xml.parsers.expat` and `xml.etree.ElementTree` when compiled with libexpat 2.8.0 or later.
* gh-149018: Improve protection against XML hash-flooding attacks in `xml.parsers.expat` and `xml.etree.ElementTree` when compiled with libexpat 2.8.0 or later.

This XML hash-flooding protection was already included in Python 3.11.16.

Expand Down
2 changes: 2 additions & 0 deletions src/layouts/BlogPostLayout.astro
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ const groupMeta: Record<string, { label: string; order: number }> = {
"gh-repo": { label: "Repositories", order: 2 },
"gh-user": { label: "People", order: 3 },
"pypi": { label: "Packages", order: 4 },
"cve": { label: "Security", order: 5 },
};

const sortedGroups = [...refGroups.entries()]
Expand Down Expand Up @@ -195,6 +196,7 @@ const sortedGroups = [...refGroups.entries()]
type === "gh-repo" && "bg-zinc-100 text-zinc-700 hover:bg-zinc-200 dark:bg-zinc-800 dark:text-zinc-300 dark:hover:bg-zinc-700",
type === "gh-user" && "bg-zinc-100 text-zinc-700 hover:bg-zinc-200 dark:bg-zinc-800 dark:text-zinc-300 dark:hover:bg-zinc-700",
type === "pypi" && "bg-emerald-50 text-emerald-700 hover:bg-emerald-100 dark:bg-emerald-900/20 dark:text-emerald-300 dark:hover:bg-emerald-900/40",
type === "cve" && "bg-rose-50 text-rose-700 hover:bg-rose-100 dark:bg-rose-900/20 dark:text-rose-300 dark:hover:bg-rose-900/40",
]}
target="_blank"
rel="noopener noreferrer"
Expand Down
55 changes: 54 additions & 1 deletion src/plugins/remark-python-refs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,12 @@
* - GitHub users/orgs (github.com/NAME — exactly 1 segment, not reserved)
* - CVE references (nvd.nist.gov/vuln/detail/CVE-YYYY-NNNNN)
* - Python releases (python.org/downloads/release/python-XXXX/)
*
* Bare "gh-NNNN" and "CVE-YYYY-NNNN" text (not already inside a link
* or heading) is autolinked and rendered as a badge.
*/
import type { Root, Link, Paragraph, PhrasingContent } from "mdast";
import { visit } from "unist-util-visit";
import { SKIP, visit } from "unist-util-visit";
import {
pythonIcon,
docsIcon,
Expand All @@ -35,6 +38,14 @@ const DOCS = /^https?:\/\/docs\.python\.org\//i;
const PYPI = /^https?:\/\/pypi\.org\/project\/([^/]+)\/?/i;
const GH_ISSUE = /^https?:\/\/github\.com\/([\w.-]+)\/([\w.-]+)\/(issues|pull)\/(\d+)\/?/i;
const CVE = /^https?:\/\/nvd\.nist\.gov\/vuln\/detail\/(CVE-[\d-]+)\/?/i;

/**
* Bare references in plain text that get autolinked (outside links,
* headings and code):
* - "gh-156293" → python/cpython issue
* - "CVE-2026-19445" → cve.org record
*/
const BARE_REF = /\b(?:(CVE-\d{4}-\d{4,})|gh-(\d+))\b/g;
const PY_RELEASE = /^https?:\/\/(?:www\.)?python\.org\/downloads\/release\/(python-[\w.]+)\/?/i;
const GITHUB =
/^https?:\/\/github\.com\/([\w.-]+)(?:\/([\w.-]+))?\/?$/i;
Expand Down Expand Up @@ -330,6 +341,48 @@ export default function remarkPythonRefs() {
}
});

// Pass 3: Autolink bare gh-NNNN issue refs and CVE IDs in text → badges
visit(tree, (node: any, index, parent: any) => {
// Don't touch text that is already a link (or a reference definition),
// or headings — Astro builds heading ids from text nodes only, so
// injecting HTML there would change the anchor slug.
if (
node.type === "link" ||
node.type === "linkReference" ||
node.type === "definition" ||
node.type === "heading"
) {
return SKIP;
}
if (node.type !== "text" || index == null || !parent) return;

const value: string = node.value;
const parts: any[] = [];
let lastIndex = 0;
BARE_REF.lastIndex = 0;
let m: RegExpExecArray | null;
while ((m = BARE_REF.exec(value)) !== null) {
if (m.index > lastIndex) {
parts.push({ type: "text", value: value.slice(lastIndex, m.index) });
}
const [label, cve, ghNum] = m;
const match: Match = cve
? { type: "cve", icon: shieldIcon, label, url: `https://www.cve.org/CVERecord?id=${cve}` }
: { type: "gh-issue", icon: issueIcon, label, url: `https://github.com/python/cpython/issues/${ghNum}` };
collectRef(match.type, match.label, match.url);
parts.push({ type: "html", value: buildBadgeHtml(match) });
lastIndex = m.index + m[0].length;
}
if (parts.length === 0) return;
if (lastIndex < value.length) {
parts.push({ type: "text", value: value.slice(lastIndex) });
}

parent.children.splice(index, 1, ...parts);
// Continue after the nodes we just inserted
return index + parts.length;
});

// Expose collected references via remarkPluginFrontmatter
if (!file.data.astro) file.data.astro = {};
if (!file.data.astro.frontmatter) file.data.astro.frontmatter = {};
Expand Down
Loading