Skip to content

fix(deps): update security dependencies and container trust stores - #1805

Merged
phernandez merged 4 commits into
mainfrom
deps-security-floors
Oct 22, 2026
Merged

phernandez merged 4 commits into
mainfrom
deps-security-floors

Conversation

@phernandez

@phernandez phernandez commented Oct 22, 2026 •

Copy link
Copy Markdown
Member

Why

pip-audit of the origin/main lock (all extras, 2026-10-21) found 60 known vulnerabilities in 8 packages. The lock only protects core's own CI. Users who install basic-memory from PyPI get whatever the pyproject.toml floors allow, so the direct dependencies get raised floors. Transitive packages get a lock refresh only.

Changes

Package Old New Kind Advisories Does core reach the vulnerable path?
pyjwt 2.13.0 (floor >=2.10.1) 2.15.1 (floor >=2.15.0) direct 14 (HMAC/asymmetric key confusion, Base64URL signature malleability, OKP from_jwk, ReDoS, JWKS redirect/refetch DoS, options dict mutation) Indirectly. Core src never imports jwt; fastmcp and mcp[crypto] use it for MCP bearer auth.
litellm 1.91.3 (floor >=1.60.0,<1.92.0) 1.91.5 (floor >=1.91.5,<1.92.0) direct 1 (PYSEC-2026-4066) No. The advisory covers the LiteLLM proxy server. Core uses the SDK only. The fix is in the 1.91.x line, so the Python 3.14 <1.92.0 cap stays.
aiohttp 3.14.1 3.14.5 transitive (litellm) 11 Through litellm HTTP calls to embedding/rerank providers.
urllib3 2.7.0 2.8.0 transitive (requests, docker, sentry-sdk) 3 Through requests.
multidict 6.7.1 6.9.1 transitive (aiohttp, yarl) 1 Through aiohttp. Locked to the fixed 6.9.1 on purpose, not 7.x, to skip a major bump.
cryptography 49.0.0 50.0.2 transitive (pyjwt[crypto], authlib, joserfc) 2 No. The 50.0.0 fix is in PKCS7 decrypt, which core does not use.
certifi 2026.6.17 2026.10.19 transitive 1 (distrusted eMudhra root) Yes, for every outbound TLS call.
yarl 1.24.2 1.25.1 transitive 0 Pulled in with the aiohttp/multidict refresh.

I did not add floors for transitive packages. A fresh install resolves current versions anyway, and pinning other projects' dependencies ties core's releases to theirs.

Not fixed: pillow (24 advisories, fixed only in 13.0.0)

Pillow 13 is not possible yet. Every fastembed release, including 0.9.0 and current main, pins pillow<13. Pillow has no 12.x backport. A [tool.uv] override-dependencies entry would only change core's own lock, not what PyPI users install, and would run fastembed on a Pillow version it was never tested with. So the pillow floor stays where it is.

Core does reach this path: read_content calls PIL.Image.open() on project files and auto-detects the format (TIFF/GIF/EPS/APNG are among the affected decoders). Possible follow-ups:

  • Bump pillow once fastembed lifts its cap (worth an upstream issue).
  • Pass formats= to Image.open in read_content so only the formats we display get decoded.

Breaking-change review

  • pyjwt 2.14/2.15: JWKSetCache now stores a parsed PyJWKSet, and PyJWKClient.fetch_data() raises on non-object JWKS. Core does not use either. fastmcp's JWT provider imports and the auth tests pass.
  • cryptography 50: FFDH is deprecated and SCT list parsing is stricter. Core uses neither.

How tested

  • uv run ty check src tests test-int with all extras: passes.
  • just fix / just format: no changes to the diff.
  • Targeted tests with all extras installed (285 passed, 0 skipped): tests/mcp/test_tool_read_content.py (PIL image path), tests/mcp/test_tool_utils_cloud_auth.py, tests/document_ingestion (pdf-inspector and markitdown), litellm embedding/rerank provider tests, tests/repository/test_milvus_repository.py.
  • An earlier run also covered tests/cli: 447 passed.
  • Re-ran the audit: uv export --frozen --no-hashes --no-emit-project --all-extras, stripped markers and duplicates, then pip-audit --no-deps --disable-pip.
    • Before: 60 vulnerabilities in 8 packages.
    • After: 24 vulnerabilities in 1 package (pillow 12.3.0 only).

CI runs the full suite.

Pillow mitigation (commit b883932)

Pillow stays on 12.x because fastembed pins pillow<13, so its 24 advisories remain in the lock. read_content is the only place core decodes images, and it trusted the stored content type while Pillow sniffs the bytes, so a TIFF/EPS/PDF saved as .png reached the vulnerable decoders. Image.open now takes formats=("PNG", "JPEG", "WEBP") and returns a clear error otherwise. New test test_read_content_refuses_non_displayable_image_formats fails without the change.

🤖 Generated with Claude Code

GIF mitigation follow-up

GIF is now rejected before decoding because GHSA-74r2-7ff9-mjj2 causes quadratic CPU work inside Image.open(), before resizing. Regression coverage rejects both an actual .gif and GIF bytes disguised as .png, alongside TIFF rejection. Focused image tests: 24 passed. just typecheck and targeted Ruff checks passed. Removing/replacing LiteLLM and/or Pillow is tracked separately in #1806.

FastMCP and container trust-store follow-up

FastMCP and fastmcp-slim are pinned to 4.1.3, including the Claude/Codex hook script environments. The targeted lock refresh also raises openapi-pydantic to 0.6.0 as required by FastMCP. FastAPI remains unchanged.

The Dockerfile now installs Debian's CA updates and fails the build unless ca-certificates is at least 20250419~deb12u2, pins uv to 0.13.5, and uses that patched uv to update the base Python's independent pip bundle to >=26.2.2. This covers system trust used by FastMCP 4 as well as package-installer trust; certifi remains 2026.10.19 in the lock. Sources: FastMCP security guidance, patched distribution/tool versions.

Verification for this follow-up:

  • UV_NO_SYNC=1 just fast-check, UV_NO_SYNC=1 just test-smoke, and UV_NO_SYNC=1 just doctor passed. Unrelated importer formatting was reverted.
  • UV_NO_SYNC=1 just package-check passed through OpenClaw; Tau initially lacked its isolated dependencies because syncing was disabled. just package-check-tau package-check-pi then passed, completing all package targets.
  • UV_NO_SYNC=1 just typecheck and targeted hook Ruff checks passed after pin alignment.
  • docker build --pull -t basic-memory:security-1805 . passed locally (arm64), and the image's CLI version command passed.
  • From that image, Python default TLS and HTTPX2 both reject dv-g3b-emudhra.we-have-a-problem.com and dv-g3b-aaa-emudhra.we-have-a-problem.com with certificate-verification errors; normal HTTPS to pypi.org succeeds (HTTPX2 HTTP 200). These are actual verification failures, not timeouts.
  • uv run --frozen --all-extras pytest tests/mcp tests/cli/test_mcp_command.py -q --no-cov — 1,571 passed in 366.37 seconds.

Existing deployed images require a rebuild/redeployment; this PR does not deploy them. The amd64 image build remains CI/release verification.

pip-audit of the lock (all extras) found 60 advisories in 8 packages.

- pyjwt >=2.15.0 (direct): key confusion, Base64URL malleability,
  OKP from_jwk, ReDoS, JWKS redirect and refetch DoS, options mutation
- litellm >=1.91.5,<1.92.0 (direct): PYSEC-2026-4066 is fixed in the
  1.91.x line, so the Python 3.14 cap stays
- lock refresh for transitive deps: aiohttp 3.14.5, urllib3 2.8.0,
  multidict 6.9.1, cryptography 50.0.2, certifi 2026.10.19

pillow 13 cannot be adopted yet: every fastembed release (0.9.0 and
main) pins pillow<13, and no 12.x backport of the fixes exists.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Signed-off-by: phernandez <[email protected]>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-22T15:45:03.591151Z bff390a Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

read_content trusts the stored content type and Pillow sniffs the bytes, so a
TIFF, EPS or PDF saved under a .png name reached Pillow's other decoders, which
carry memory-safety advisories we cannot upgrade past yet (fastembed pins
pillow<13). Image.open now accepts only PNG, JPEG, GIF and WebP and returns a
clear error for anything else.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Signed-off-by: phernandez <[email protected]>
@phernandez

Copy link
Copy Markdown
Member Author

Removed GIF from the decoder allowlist to block GHSA-74r2-7ff9-mjj2 before Image.open invokes the GIF parser. Regression cases cover real .gif files and GIF bytes under a .png name. Focused image tests: 24 passed; just typecheck and targeted Ruff checks passed. Broader dependency removal/replacement is tracked in #1806. CI/current-head review pending.

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 🚀

Reviewed commit: b05f5856e5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@phernandez phernandez changed the title fix(deps): raise security floors for pyjwt and litellm, refresh lock fix(deps): update security dependencies and container trust stores Oct 22, 2026
@phernandez

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 🚀

Reviewed commit: bff390acbc

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@phernandez

Copy link
Copy Markdown
Member Author

Validation completed for bff390a: 1,571 MCP/CLI tests passed; smoke, doctor, static/type checks, all package targets, local arm64 Docker build, and runtime certificate-chain rejection probes passed. The PR body records commands and details.

CI's Static Checks and Pi package jobs failed during extractions/setup-just@v4 with no release for just matching version specifier, before product checks ran. Retried package jobs: Shared skills recovered, Pi hit the same setup failure. Static-check retry is blocked while its parent workflow is running. Codex review is pending on this head; no merge or deployment performed.

@phernandez
phernandez merged commit 263fe5e into main Oct 22, 2026
67 of 71 checks passed
@phernandez
phernandez deleted the deps-security-floors branch October 22, 2026 16:17
phernandez added a commit that referenced this pull request Oct 23, 2026
Date the v0.24.0 entry 2026-10-22, add a Security section for
GHSA-4gfv-c2mm-mvj2 (DNS rebinding, #1697) and GHSA-pqm2-2wxw-p5hx
(host symlink probing, #1807), plus #1804 and #1805, and cover the
changes merged since the entry was last edited (#1761 through #1807).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_018CoZ3jWnMJsyQsik4tPySk
Signed-off-by: phernandez <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant