Skip to content

security: require Python 3.10+, dropping a vulnerable resolution branch - #14

Open
cdbartholomew wants to merge 1 commit into
mainfrom
security/drop-py39
Open

security: require Python 3.10+, dropping a vulnerable resolution branch#14
cdbartholomew wants to merge 1 commit into
mainfrom
security/drop-py39

Conversation

@cdbartholomew

Copy link
Copy Markdown
Contributor

#11 closed the critical langchain-core advisory, but had a side effect worth correcting.

The problem

langchain-core 1.6.1 requires Python 3.10+, while this package still declared requires-python = ">=3.9". uv therefore split the resolution, pinning an older set for the 3.9 branch:

urllib3   2.6.3   (python < 3.10)   vs  2.7.0    (>= 3.10)
requests  2.32.5  (python < 3.10)   vs  2.34.2   (>= 3.10)
orjson    3.11.5  (python < 3.10)   vs  3.12.0   (>= 3.10)

Anyone installing under 3.9 got the left-hand column, which carries three high and one medium advisory:

package version advisory severity
urllib3 2.6.3 GHSA-mf9v-mfxr-j63j — decompression-bomb bypass high
urllib3 2.6.3 GHSA-qccp-gfcp-xxvc — headers forwarded cross-origin high
orjson 3.11.5 GHSA-hx9q-6w63-j58v — unbounded recursion high
requests 2.32.5 GHSA-gc5v-m9x4-r6x2 — insecure temp file reuse medium

The 3.10+ path was clean throughout; only the 3.9 branch was affected. The CI matrix does test 3.9, so this was reachable.

The fix

Raising requires-python to >=3.10 collapses the split. It is also simply honest: the package's primary dependency dropped 3.9, so claiming 3.9 support was already inaccurate.

  • requires-python >=3.9>=3.10
  • removed the Programming Language :: Python :: 3.9 classifier
  • CI matrix 3.9–3.133.10–3.13

Verification

Every dual resolution is gone except websockets (16.1.1 / 17.1) — neither of those carries an advisory. Single resolutions now:

langchain-core 1.6.1    urllib3 2.7.0    requests 2.34.2
orjson 3.12.0           h11 0.16.0

uv sync --frozen --all-groups clean. Imports resolve, VectorizeRetriever still has BaseRetriever in its MRO, and urllib3 2.7.0 / requests 2.34.2 confirmed at runtime.

Note the repo's two tests still fail at setup on a 402 from api.vectorize.io — unrelated to this change, and true on every run since at least 2025-08-19.

#11 closed the critical langchain-core advisory, but had a side effect worth
correcting.

langchain-core 1.6.1 requires Python 3.10+, while this package still declared
`requires-python = ">=3.9"`. uv therefore split the resolution, pinning an
older set for the 3.9 branch:

    urllib3   2.6.3   (python < 3.10)   vs  2.7.0   (>= 3.10)
    requests  2.32.5  (python < 3.10)   vs  2.34.2  (>= 3.10)
    orjson    3.11.5  (python < 3.10)   vs  3.12.0  (>= 3.10)

Anyone installing under 3.9 got the left-hand column, which carries three high
and one medium advisory:

    urllib3 2.6.3   GHSA-mf9v-mfxr-j63j  decompression-bomb bypass      high
    urllib3 2.6.3   GHSA-qccp-gfcp-xxvc  headers forwarded cross-origin high
    orjson  3.11.5  GHSA-hx9q-6w63-j58v  unbounded recursion            high
    requests 2.32.5 GHSA-gc5v-m9x4-r6x2  insecure temp file reuse       medium

Raising `requires-python` to >=3.10 collapses the split. It is also honest:
the package's primary dependency dropped 3.9, so claiming 3.9 support was
already inaccurate.

- `requires-python` >=3.9 -> >=3.10
- removed the `Programming Language :: Python :: 3.9` classifier
- CI matrix 3.9-3.13 -> 3.10-3.13

## Verification

Every dual resolution is gone except `websockets` (16.1.1 / 17.1), and neither
of those carries an advisory. Single resolutions now:

    langchain-core 1.6.1   urllib3 2.7.0   requests 2.34.2
    orjson 3.12.0          h11 0.16.0

`uv sync --frozen --all-groups` clean; imports resolve and VectorizeRetriever
still has BaseRetriever in its MRO; urllib3 2.7.0 and requests 2.34.2 confirmed
at runtime.

Claude-Session: https://claude.ai/code/session_01SK2htrNEFAj2VuxKWqFavo
@benfrank241

Copy link
Copy Markdown
Member

Sweep 2026-09-05 — this PR now has alert numbers, and one real regression

Two things changed since this PR was opened.

1. Dependabot alerts are live now, and this PR closes all 11

The alerts endpoint returned an empty array in every state when #12 was filed. It no longer does — the repo is being scanned, and there are 11 open alerts, all on langchain/uv.lock. Every one of them is cleared by this branch. Verified by resolving both lockfiles rather than by reading the body:

alert package advisory main (py3.9 leg) this PR fix floor
#11 urllib3 GHSA-qccp-gfcp-xxvc 2.6.3 2.7.0 2.7.0
#12 urllib3 GHSA-mf9v-mfxr-j63j 2.6.3 2.7.0 2.7.0
#13 langsmith GHSA-3644-q5cj-c5c7 0.4.37 0.12.1 0.8.0
#14 langsmith GHSA-f4xh-w4cj-qxq8 0.4.37 0.12.1 0.8.18
#15 langsmith GHSA-v34v-rq6j-cj6p 0.4.37 0.12.1 0.6.3
#9 langsmith GHSA-rr7j-v2q5-chgv 0.4.37 0.12.1 0.7.31
#3 langchain-core GHSA-2g6r-c272-w58r 0.3.86 1.6.1 1.2.11
#6 langchain-core GHSA-qh6h-p6c9-ff54 0.3.86 1.6.1 1.2.22
#4 orjson GHSA-hx9q-6w63-j58v 3.11.5 3.12.0 3.11.6
#5 requests GHSA-gc5v-m9x4-r6x2 2.32.5 2.34.2 2.33.0
#8 pytest (dev) GHSA-6w46-j5rx-g56g 8.4.2 9.1.1 9.0.3

The left column is the python_full_version < '3.10' fork; collapsing it is what clears them. resolution-markers drop out entirely for these packages here (lock goes 2098 → 1532 lines), leaving only websockets 16.1.1/17.1 forked, which carries no advisory.

No competing PR was opened today — this branch already covers the whole queue.

2. ruff check regresses on this branch, and it is caused by this change

This is separate from the two environment failures documented in #12 (the 402 from api.vectorize.io, and lint.yml resolving CPython 3.14). It is change-correlated, and it reproduces locally against a main control worktree:

main   $ uv run ruff check   ->  exit 0   "All checks passed!"
pr #14 $ uv run ruff check   ->  exit 1
  langchain_vectorize/retrievers.py:112:19: UP045 Use `X | None` for type annotations
  langchain_vectorize/retrievers.py:114:18: UP045 Use `X | None` for type annotations

[tool.ruff] sets no target-version, so ruff infers it from requires-python. Moving >=3.9>=3.10 makes PEP 604 unions valid, which switches UP045 on. The two Optional[str] fields in VectorizeRetriever were compliant before and are violations now. So Lint LangChain would stay red on this branch even after the 3.14 interpreter problem is fixed.

The fix is what ruff --fix produces, and it is the whole diff:

-from typing import TYPE_CHECKING, Any, Literal, Optional
+from typing import TYPE_CHECKING, Any, Literal
@@
-    organization: Optional[str] = None
+    organization: str | None = None
-    pipeline_id: Optional[str] = None
+    pipeline_id: str | None = None

Safe under pydantic: the module already has from __future__ import annotations, so these are string annotations resolved at class construction, and str | None evaluates fine on the 3.10+ floor this PR establishes.

Verified in a worktree on this branch with that patch applied (not pushed — it is a source change to a published package's public annotations, so it is yours to take):

uv lock --check          ok (lock in sync with pyproject)
uv sync --dev            ok
ruff format --check      ok, 4 files already formatted
ruff check               ok, All checks passed!
mypy .                   ok, no issues in 4 source files
pytest --collect-only    ok, 2 tests collected

The class docstring at lines 51/53 also still says Optional[str]; cosmetic, ruff does not flag it.

3. Still outstanding, unchanged and not fixable from here

lint.yml was not touched by this PR. It still declares matrix.python-version: ['3.9', '3.13'] while passing python-version-file: "langchain/pyproject.toml" to setup-python, so both legs resolve to the newest interpreter on the runner regardless of the matrix. With requires-python now >=3.10 that stale '3.9' entry is also simply wrong. Both that and the 402 need a maintainer; neither belongs in a security bundle.

Automated daily security sweep. Findings only — nothing was merged, and no alert was dismissed.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants