Skip to content

CVE-2025-15367 (poplib) — accepted risk on any interpreter below 3.15 #52

Description

@tyler-rich

Summary

ci/grype.yaml waives CVE-2025-15367 (MEDIUM, poplib command injection) on Scrye's CPython
interpreter binary. This is a standing acceptance on any interpreter below 3.15, not a deferral
with a pending action behind it: the fix exists only on main, it has not been backported to any
maintenance branch, and no 3.14.x point release will clear it.

This issue is the tracking reference for that acceptance. It is not a plan to upgrade.

The CVE

  • CVE-2025-15367 (MEDIUM) — poplib command injection. POP3._putcmd() writes its argument
    straight to the socket via _putline(), so control characters and CRLF in user-controlled input
    can terminate the intended command and inject additional POP3 commands.

Upstream: gh-143923, fixed on main by
GH-143924 (commit b234a2b, 2026-01-20).

Reported-but-non-gating under the dogfood gate (grype --only-fixed --fail-on high): it is a
Medium and does not trip --fail-on high. It is waived for a clean report, not to pass the gate.

Source verification (2026-07-26; re-verified 2026-08-11)

Confirmed at the source per CLAUDE.md § Dependency hygiene, not from Grype's FIXED IN column —
Lib/poplib.py fetched from each ref and compared:

ref _putcmd() guard
main present — if re.search(b'[\x00-\x1F\x7F]', line): raise ValueError('Control characters not allowed in commands')
3.14 branch absent
3.13 branch absent
v3.14.7 (the pinned runtime) absent

gh-143923 lists no backport pull requests. PR #143924 (the main fix) originally carried backport
labels for 3.10–3.14; all were removed before merge on 2026-01-20 over a stated
backward-compatibility concern — control characters such as tab/backspace are RFC-violating but in
current use, and rejecting them would break that. The fix is on main only, so nothing on the
3.14 line will carry it.

Re-verified 2026-08-11, independently of this table, Grype's FIXED IN column, or #195's
archive entry, after the runtime moved from 3.14.6 to 3.14.7 (PR #195): Lib/poplib.py fetched
directly from the released v3.14.7 tag and from main. Result unchanged — the guard is present
on main and absent from v3.14.7. gh-143923 still lists no backport PR as of 2026-08-11. See
docs/ARCHIVE.md §14 (2026-08-11) for the full method and result.

Why this is an acceptance and not a deferral

  • No backport exists or is proposed for any branch below 3.15, so no point release on the line
    Scrye runs will fix it.
  • Scrye does not use poplib — a repo-wide search of backend/ finds no reference to it (checked
    again 2026-08-11; still none). This covers Scrye's own code, not a claim that no bundled
    third-party dependency ever imports it. The module ships in the interpreter's stdlib and is never
    imported by Scrye itself.
  • The residual risk is therefore the presence of unreachable vulnerable stdlib code in the image,
    not an exploitable path in Scrye.

Do not scope a 3.15 upgrade as a reaction to this CVE. A 3.15 move should be justified on
support-lifecycle, ecosystem, or dependency-currency grounds if and when it happens — per
CLAUDE.md § Dependency hygiene, an interpreter bump argued as a CVE fix must first be verified at
the source, and the 3.13 → 3.14 bump is the cautionary case (docs/ARCHIVE.md §14, 2026-07-25).

Review cadence

Annual re-confirmation — next 2027-07-25. Unchanged by the 2026-08-11 re-verification. The
review confirms the acceptance still holds: severity unchanged, no backport appeared on the branch
in use, and Scrye still does not use poplib. It is not a prompt to schedule an upgrade.

Waiver

ci/grype.yaml, Group B block:

- vulnerability: CVE-2025-15367   # poplib command injection (MEDIUM)

Reclassified out of this issue: CVE-2025-15366 (imaplib)

CVE-2025-15366 was tracked here as the other half of Group B, on the rationale that upstream had
declined the backport to 3.10–3.14. That rationale no longer holds. The fix is present on both
the 3.14 and 3.13 maintenance branches and absent from v3.14.6:

  • Lib/imaplib.py on 3.14 defines _control_chars = re.compile(b'[\x00\r\n]') and raises
    ValueError("NUL, CR and LF not allowed in commands") in IMAP4._command() before appending
    each argument. v3.14.6 has neither line.
  • 3.14 backport: GH-153137, commit 2981822,
    merged 2026-07-07. 3.13 backport: GH-153287, commit 71926d9.
  • Misc/NEWS.d/next/Security/2026-01-16-11-41-06.gh-issue-143921.AeCOor.rst is present on 3.14
    and 3.13 and absent from v3.14.6 — still in next/, so it is queued for the next point
    release and shipped in none.

Why the two companion fixes diverged. The original main fix
(GH-143922) rejected all control characters,
which is what drew the regression concern behind the original no-backport decision. A follow-up,
GH-153067, narrowed the check to NUL, CR and LF
only — other control characters are valid in quoted strings and are sent quoted — and it is the
narrowed version that was backported. poplib's fix still rejects the full
[\x00-\x1F\x7F] range and has had no equivalent narrowing, which is consistent with it remaining
un-backported.

CVE-2025-15366 therefore now has a real resolution trigger: the next 3.14.x point release
(3.14.7)
— the same trigger as the #98 pair.

Follow-ups:

Group A tracker

The Group A interpreter CVEs — CVE-2026-15308 (html.parser), CVE-2026-12003 (getpath.py) and
CVE-2025-15366 (imaplib) — were tracked in #98 through 2026-08-11. That day, all three were
verified fixed in the pinned interpreter (3.14.7) by reading CPython at the source, and #98 was
closed — its resolution trigger (a 3.14.x release carrying the backports) had fired. Group A
tracking now lives in ci/grype.yaml's Group A-1 block plus docs/ARCHIVE.md §14 (2026-08-11),
not a numbered issue; #98 remains only as a historical link. This issue never covered #116
(the Group A-2 tarfile set, closed the same day for the same reason) directly, but the same
retargeting applies to it: #116 is also closed, and its tracking lives in ci/grype.yaml's
Group A-2 block plus the same §14 entry.

Closing this issue

Closing keywords will not fire on merge. GitHub only auto-closes on a merge into the
repository's default branch, which is main; day-to-day PRs here target dev and reach main
only via a squashed promotion. A Closes #52 in a PR body is therefore inert. This issue must be
closed by hand
when the acceptance no longer holds — i.e. when the runtime moves to an
interpreter carrying the poplib fix, or the waiver is removed.

Ref: docs/ARCHIVE.md §14 (2026-07-13, 2026-07-25, 2026-07-26, 2026-08-11), CLAUDE.md § Dependency
hygiene, and #98 / #116 (both closed 2026-08-11 — Group A tracking now lives in ci/grype.yaml +
docs/ARCHIVE.md §14; kept here only as historical links).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions