Skip to content

Commit 96264fb

Browse files
authored
docs(ci): regroup CVE-2025-15366 from Group B to Group A — the imaplib backport landed on 3.14 (#100)
Group B's rationale — upstream declined the backport to 3.10-3.14, so these are fixed only in 3.15+ — is no longer true of CVE-2025-15366. Lib/imaplib.py on the 3.14 and 3.13 branches carries the _control_chars guard in IMAP4._command() (python/cpython#153137, commit 2981822, merged 2026-07-07); v3.14.6 does not, and the gh-143921 NEWS entry is still under Misc/NEWS.d/next/Security. That is Group A shape: merged, unreleased, closing on 3.14.7. poplib is unchanged — its guard is on main only, and gh-143923 lists no backport PR. The two diverged because imaplib's check was narrowed to NUL/CR/LF (python/cpython#153067), clearing the regression concern behind the original decline; poplib's still rejects the full control-character range. Group B keeps its standing-acceptance framing, its annual review date (2027-07-25), and the do-not-scope-a-3.15-move instruction, now for CVE-2025-15367 alone. The waiver list is unchanged at four entries. The 2026-07-25 entry is superseded on this one point and left unedited; its reading of 3.14.6 was correct, but the backport had already merged 18 days before it was written. See docs/ARCHIVE.md § Deviations (2026-07-26) for the evidence.
1 parent 543b47e commit 96264fb

2 files changed

Lines changed: 108 additions & 27 deletions

File tree

‎ci/grype.yaml‎

Lines changed: 37 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -36,50 +36,60 @@ ignore:
3636
# ── CPython interpreter-binary CVEs on Python 3.14 — accepted risk ──────────────
3737
# The interpreter binary in python:3.14-slim-bookworm (3.14.6, current latest
3838
# 3.14.x) carries these. Background: docs/ARCHIVE.md §14 (2026-07-25, the
39-
# 3.13 → 3.14 runtime bump; 2026-07-26, the Group A re-verification). Each group
40-
# cites its own tracking issue below — they have different triggers and are not
41-
# one decision.
39+
# 3.13 → 3.14 runtime bump; 2026-07-26, the Group A re-verification and the
40+
# CVE-2025-15366 regrouping). Each group cites its own tracking issue below — they
41+
# have different triggers and are not one decision.
4242
#
4343
# Group A — fix merged to both the 3.13 and 3.14 maintenance branches but not yet
4444
# in any released point version, so it closes on the next 3.14.x point release
45-
# (3.14.7 — 3.14.6 released 2026-06-10, both backports merged after it).
45+
# (3.14.7 — 3.14.6 released 2026-06-10, every backport below merged after it).
4646
# CVE-2026-15308 (HIGH) is the only one of the four that trips --fail-on high; the
4747
# rest are reported-but-non-gating Mediums, waived here for a clean report.
4848
#
4949
# Verified at the source on 2026-07-26, per CLAUDE.md § Dependency hygiene — not
50-
# taken from Grype's FIXED IN column, which still reports 3.15.x for both. Each
51-
# file was diffed between the `3.14` branch and the `v3.14.6` tag: the branch has
52-
# the buffered `feed()`/`_parse_threshold` rewrite in Lib/html/parser.py
53-
# (python/cpython#153039, 2026-07-04) and the BUILD_LANDMARK fallback removed from
54-
# Modules/getpath.py (python/cpython#151682, 2026-06-22); 3.14.6 has neither.
50+
# taken from Grype's FIXED IN column, which still reports 3.15.x for all three.
51+
# Each file was diffed between the `3.14` branch and the `v3.14.6` tag; the branch
52+
# has each fix and 3.14.6 has none of them:
53+
# - Lib/html/parser.py buffered `feed()`/`_parse_threshold` rewrite
54+
# (python/cpython#153039, 2026-07-04)
55+
# - Modules/getpath.py BUILD_LANDMARK fallback removed
56+
# (python/cpython#151682, 2026-06-22)
57+
# - Lib/imaplib.py `_control_chars` guard in `IMAP4._command()`
58+
# (python/cpython#153137, 2026-07-07)
5559
# Expect the waivers to outlive 3.14.7 by a Grype-DB refresh cycle.
5660
#
5761
# Tracked in issue #98 (https://github.com/tyler-rich/Scrye/issues/98), which is
58-
# Group A only. It supersedes issue #52 for these two — #52 is the older
59-
# all-four tracker, written against the 3.13 runtime and stale since the 3.14 move
60-
# (still open as of 2026-07-26; do not rely on it for Group A status).
62+
# Group A only. Note CVE-2025-15366 was a Group B entry until 2026-07-26 — the
63+
# imaplib backport landed on 3.14 once the check was narrowed to NUL/CR/LF, so it
64+
# is no longer a below-3.15 acceptance. See docs/ARCHIVE.md §14 (2026-07-26).
6165
# REVIEW BY 2026-10-25 (covers the next 1-2 CPython point releases at their
6266
# ~2-month cadence, plus Grype-DB refresh lag on the backport).
6367
- vulnerability: CVE-2026-15308 # html.parser quadratic-complexity CPU DoS (HIGH)
6468
- vulnerability: CVE-2026-12003 # getpath.py in-tree search-path fallback (MEDIUM)
69+
- vulnerability: CVE-2025-15366 # imaplib command injection (MEDIUM)
6570
#
6671
# Group B — ACCEPTED RISK ON ANY INTERPRETER BELOW 3.15. Not "pending an upgrade":
67-
# upstream declined the backport to 3.10 THROUGH 3.14, so these are fixed only in
68-
# 3.15+ and no 3.14.x point release will ever clear them. This is a standing
69-
# acceptance, not a deferral with a pending action behind it.
72+
# the fix exists only on `main`, upstream issue gh-143923 lists no backport PR for
73+
# any maintenance branch, and no 3.14.x point release will clear it. This is a
74+
# standing acceptance, not a deferral with a pending action behind it.
75+
#
76+
# Verified at the source on 2026-07-26: `POP3._putcmd()` in Lib/poplib.py raises on
77+
# `re.search(b'[\x00-\x1F\x7F]', line)` on `main` only — the `3.14` branch, the
78+
# `3.13` branch and the `v3.14.6` tag all still hand the line straight to
79+
# `_putline()` with no validation.
7080
#
71-
# They were expected to clear when the runtime moved to 3.14 — both the 3.14
72-
# scoping doc and issue #52's resolution-trigger line claimed 3.14.6 already
73-
# carried the fixes. It does not: the CI dogfood scan reports them against
74-
# interpreter 3.14.6 with `FIXED IN 3.15.0a6`, and reading 3.14.6's own stdlib
75-
# confirms it — `imaplib._command()` and `poplib._putcmd()` still concatenate
76-
# arguments onto the wire with no CRLF/control-character validation.
81+
# This waiver covered imaplib as well until 2026-07-26. It no longer does: that
82+
# fix WAS backported and moved to Group A above. The two diverged because imaplib's
83+
# check was narrowed to NUL/CR/LF (python/cpython#153067), which cleared the
84+
# regression concern behind the original decline; poplib's still rejects the whole
85+
# [\x00-\x1F\x7F] range and has had no such narrowing.
7786
#
7887
# REVIEW ANNUALLY — next 2027-07-25. The review is a re-confirmation that the
79-
# acceptance still holds (severity unchanged, no in-line fix appeared, Scrye still
80-
# doesn't use imaplib/poplib), NOT a prompt to schedule a 3.15 move. A 3.15 upgrade
81-
# should be justified on support-lifecycle grounds if and when it happens; per
82-
# CLAUDE.md § Dependency hygiene, do not scope an interpreter bump as a reaction to
83-
# these two. See docs/ARCHIVE.md §14 (2026-07-25) for the full correction.
84-
- vulnerability: CVE-2025-15366 # imaplib command injection (MEDIUM)
88+
# acceptance still holds (severity unchanged, no backport appeared on the branch in
89+
# use, Scrye still doesn't use poplib), NOT a prompt to schedule a 3.15 move. A
90+
# 3.15 upgrade should be justified on support-lifecycle grounds if and when it
91+
# happens; per CLAUDE.md § Dependency hygiene, do not scope an interpreter bump as
92+
# a reaction to this one. Tracked in issue #52
93+
# (https://github.com/tyler-rich/Scrye/issues/52); see docs/ARCHIVE.md §14
94+
# (2026-07-25, 2026-07-26).
8595
- vulnerability: CVE-2025-15367 # poplib command injection (MEDIUM)

‎docs/ARCHIVE.md‎

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3353,3 +3353,74 @@ that never happened.
33533353
§ Dependency hygiene. Configuration and documentation only — no application code, schema,
33543354
API-contract, security-model, job-model, or auth change, and no change to the waiver list itself
33553355
(still four entries).
3356+
3357+
### 2026-07-26 — Infra/Process — CVE-2025-15366 (imaplib) regrouped from Group B to Group A: the backport did land on 3.14
3358+
**What changed:** `ci/grype.yaml`'s Group B waiver block covered two CVEs on the rationale that
3359+
upstream had declined the backport to 3.10–3.14, making them permanently unfixable below 3.15.
3360+
Checking that rationale at the source before restating it in the re-scoped tracking issue showed it
3361+
is **no longer true of CVE-2025-15366**. The waiver moved to Group A; Group B is now
3362+
CVE-2025-15367 alone. No CVE was un-waived — the list goes from four entries to four entries, three
3363+
in Group A and one in Group B.
3364+
3365+
**The evidence, not just the conclusion.** `Lib/imaplib.py` and `Lib/poplib.py` were fetched from
3366+
the `3.14` branch, the `3.13` branch, the `v3.14.6` tag and `main`, and compared:
3367+
- **imaplib — fix is on the maintenance branches.** `3.14` and `3.13` both define
3368+
`_control_chars = re.compile(b'[\x00\r\n]')` and raise
3369+
`ValueError("NUL, CR and LF not allowed in commands")` inside `IMAP4._command()`'s argument loop,
3370+
before each argument is appended to the wire buffer. `v3.14.6` has neither the constant nor the
3371+
guard. Upstream issue **gh-143921**; 3.14 backport **python/cpython#153137**, merge commit
3372+
`2981822`, merged **2026-07-07**; 3.13 backport **python/cpython#153287**, merge commit
3373+
`71926d9`, same day.
3374+
- **It is queued, not released.** `Misc/NEWS.d/next/Security/2026-01-16-11-41-06.gh-issue-143921.AeCOor.rst`
3375+
("Reject NUL, CR and LF characters in IMAP commands. Other control characters are allowed and
3376+
sent quoted.") is present on `3.14` and `3.13` and **404s on `v3.14.6`**. Still under `next/`, so
3377+
it ships in the next point release and has shipped in none — exactly the Group A shape.
3378+
- **poplib was NOT backported.** `POP3._putcmd()`'s
3379+
`re.search(b'[\x00-\x1F\x7F]', line)` → `ValueError('Control characters not allowed in commands')`
3380+
guard exists on `main` only; the `3.14` branch, the `3.13` branch and `v3.14.6` all still pass the
3381+
line to `_putline()` unvalidated. Upstream issue **gh-143923** lists a single PR
3382+
(**python/cpython#143924**, commit `b234a2b`, 2026-01-20, `main`) and no backport PR against any
3383+
maintenance branch.
3384+
- **Why the companion fixes diverged** — this is the part that makes the split make sense rather
3385+
than look arbitrary. The original imaplib fix (**python/cpython#143922**) rejected *all* control
3386+
characters, and that breadth is what drew the compatibility-regression concern behind the original
3387+
no-backport decision. A follow-up, **python/cpython#153067**, narrowed the check to NUL, CR and LF
3388+
only — other control characters are legal in quoted strings and are sent quoted — and it is the
3389+
**narrowed** version that was backported (the 3.14 commit message records it as a combined
3390+
backport of GH-143922 and GH-153067). poplib's fix still rejects the full `[\x00-\x1F\x7F]` range
3391+
and has had no equivalent narrowing, which is consistent with it remaining un-backported. So the
3392+
two were never going to move together, despite the identical stated reasoning in our own record.
3393+
3394+
**On the 2026-07-25 entry: superseded for CVE-2025-15366 only, and left in place unedited.** That
3395+
entry's own reading was correct and is not being retracted — it verified **3.14.6**, the released
3396+
interpreter, and 3.14.6 genuinely lacks both guards; that remains true today. What does not survive
3397+
is the *generalisation* it drew from that reading: "upstream declined the backport to 3.10–3.14, so
3398+
these are fixed only in 3.15+ and no 3.14.x point release will ever clear them." The honest
3399+
chronology is that the imaplib backport merged on **2026-07-07**, **18 days before** that entry was
3400+
written — so the claim was already stale when recorded, not overtaken afterwards. The check looked
3401+
at the released tag and concluded something about the maintenance *branch*, which the tag cannot
3402+
tell you. **Nothing in the 2026-07-25 entry was edited**; it stands as written and this entry
3403+
supersedes it on that one point.
3404+
3405+
**The lesson is narrower than "verify at the source," which was already the rule.** Source
3406+
verification was performed on 2026-07-25 and still produced a wrong standing conclusion, because
3407+
the ref it read could not answer the question being asked. A claim about whether a fix *will ever*
3408+
arrive on a line is a claim about the **branch**; only a claim about what is shipping *today* can be
3409+
settled from a tag. Both refs are cheap to check — this pass read four — and a waiver whose
3410+
rationale is "permanently unfixable" should be pinned to the branch, not the release.
3411+
3412+
`ci/grype.yaml` changes: CVE-2025-15366 moved into the Group A list with the imaplib backport added
3413+
to the Group A source-verification block; Group B rewritten for poplib alone, with its own
3414+
source-verification lines, the divergence explanation, and issue #52 as its tracker; the shared
3415+
header's ARCHIVE pointer extended to this entry. The Group B **review cadence (annual, next
3416+
2027-07-25)**, the standing-acceptance framing, and the explicit "do not scope a 3.15 move as a
3417+
reaction to this" instruction are all carried over unchanged — the acceptance itself was not
3418+
re-opened, only its membership.
3419+
**Why:** A waiver is only as good as the rationale beside it, and this one had drifted from
3420+
"accepted because unfixable" to "accepted because unfixable, except it was fixed three weeks ago."
3421+
Regrouping keeps the two blocks meaning what they say — Group A has a trigger and a review date
3422+
tied to a release, Group B is a standing acceptance with an annual re-confirmation — so a reviewer
3423+
arriving on either date knows which question they are being asked.
3424+
**Plan section affected:** §9.1 (base image / dogfood self-scan), §12 (Phase 6 self-scan),
3425+
CLAUDE.md § Dependency hygiene. Configuration and documentation only — no application code, schema,
3426+
API-contract, security-model, job-model, or auth change.

0 commit comments

Comments
 (0)