Skip to content

fix(deps): bump multidict 6.7.1 -> 6.9.1 for CVE-2026-104874 [PILOT-8488] - #218

Merged
Mihaiii merged 1 commit into
mainfrom
fix/multidict-cve-2026-104874
Oct 6, 2026
Merged

Mihaiii merged 1 commit into
mainfrom
fix/multidict-cve-2026-104874

Conversation

@Mihaiii

@Mihaiii Mihaiii commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

Issue

PILOT-8488

Summary

Blocker for every open PR and for main. Since 2026-10-05 23:40 UTC, the Quality Gate (Format, Lint, Type, Test, Security) job fails on every run, in the step Security - Dependency vulnerabilities (pip-audit). Merge this first. Then re-run the Quality Gate on the open PRs.

  • Bump the transitive multidict 6.7.1 → 6.9.1 in uv.lock. 6.9.1 fixes CVE-2026-104874 / GHSA-54p9-h82j-f925 (a reference leak in the items-view union and subtraction operators of 6.7.0 to 6.9.0).
  • uv lock --upgrade-package multidict only. The lock changes no other package: all 193 changed lines are multidict's version and wheel list.
  • No pyproject.toml change. multidict comes only through aiohttp (from litellm and uipath) and yarl (from harbor → supabase).

Why the date is 2026-10-05 23:40 UTC

  • pip-audit reads the PyPA advisory database. OSV records GHSA-54p9-h82j-f925 as published at 2026-10-05 23:40:58 UTC.

  • The last green Quality Gate was on main at 2026-10-05 17:16 UTC (run 37347251438), before the advisory.

  • Every Quality Gate after it failed with the same finding:

    Found 1 known vulnerability, ignored 1 in 1 package
    multidict 6.7.1   CVE-2026-104874 6.9.1
    

Runs that failed (every Quality Gate run since the advisory)

Run Date (UTC) Branch / PR Job
37436743522 2026-10-06 08:32 #207 chore/move-delegate-sdk-2 Quality Gate
37440346678 2026-10-06 09:03 #207 Quality Gate
37441640549 2026-10-06 09:14 #207 Quality Gate
37442576027 2026-10-06 09:23 #207 Quality Gate

No other branch has run the workflow since the advisory. These open PRs into main last ran before it, so their next run will fail the same way: #211, #210, #209, #208, #181, #173, #160, #149, #117, #67, #47. So will the next push to main, and #53, which has no recorded run yet. #183 and #184 are stacked on feature branches, so this workflow does not run on them until they target main.

Testing

  • uv sync --frozen --extra dev --extra uipath --extra codex --extra litellm --extra harbor (the Quality Gate's install line) installs multidict 6.9.1.
  • The Quality Gate's pip-audit command (same --ignore-vuln list as pr-checks.yml:126) reports No known vulnerabilities found, 1 ignored.
  • Unit tests (-m "not live and not lint", Windows): 5985 passed, 10 failed. All 10 failures come from the local machine, not from this change: 8 need symlink rights (WinError 1314), and 2 find a node_modules folder in a parent directory. CI runs the suite on Linux.
  • Not checked locally: the runner's safe-chain minimum package age. 6.9.1 was published on 2026-09-21, so it is 15 days old.

🤖 Generated with Claude Code

pip-audit in the Quality Gate fails on every run since the PyPA
advisory GHSA-54p9-h82j-f925 (CVE-2026-104874) was published on
2026-10-05 23:40 UTC: a reference leak in the items-view union and
subtraction operators of multidict 6.7.0 to 6.9.0, fixed in 6.9.1.

multidict is transitive only (aiohttp via litellm and uipath; yarl via
harbor -> supabase). `uv lock --upgrade-package multidict` changes no
other package.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

Claude finished @Mihaiii's task in 1m 22s —— View job


Reviewing PR #218: Fix CVE-2026-104874 in multidict dependency

Review Checklist:

  • Read .github/code_review.md for review standards
  • Read CLAUDE.md for project conventions
  • Analyze the git diff (origin/main...HEAD)
  • Read the full uv.lock file for context
  • Verify the change only affects multidict and its wheel entries
  • Check for potential breaking changes or compatibility issues
  • Verify the fix properly addresses CVE-2026-104874
  • Perform cross-file consistency checks
  • Complete "What's Missing" analysis
  • Provide comprehensive review feedback

@uipreliga uipreliga left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: coder_eval — pr:218 — fix(deps): bump multidict 6.7.1 -> 6.9.1 for CVE-2026-104874 [PILOT-8488] · PR #218 by @Mihaiii · fix/multidict-cve-2026-104874 → main · OPEN

Scope: pr:218 — fix(deps): bump multidict 6.7.1 -> 6.9.1 for CVE-2026-104874 [PILOT-8488] · PR #218 by @Mihaiii · fix/multidict-cve-2026-104874 → main · OPEN · branch fix/multidict-cve-2026-104874 · 9b1da89 · 2026-10-06T10:51Z · workflow variant

Change class: trivial — lockfile-only dependency bump (transitive multidict 6.7.1 → 6.9.1); no code path changes

The codebase is healthy on all eight axes (10/10 overall), and no finding can change a task's score or final_status; the only risk is one low-severity lockfile churn (uv.lock:2 revision 5 -> 3 from an older local uv), so the bottom line is to merge after you revert that one line.

Summary

Axis Score 🔴 🟠 🟡 🔵 Top Issue
1. Code Quality & Style 10 / 10 0 0 0 0 —
2. Type Safety 10 / 10 0 0 0 0 —
3. Test Health 10 / 10 0 0 0 0 —
4. Security 10 / 10 0 0 0 0 —
5. Architecture & Design 10 / 10 0 0 0 0 —
6. Error Handling & Resilience 10 / 10 0 0 0 0 —
7. API Surface & Maintainability 9.9 / 10 0 0 0 1 Lockfile header revision regressed 5 -> 3 (out-of-scope churn from an older local uv; contradicts PR body)
8. Evaluation Harness Quality 10 / 10 0 0 0 0 —

Overall Score: 10 / 10 · Weakest Axis: API Surface & Maintainability at 9.9 / 10
Totals: 🔴 0 · 🟠 0 · 🟡 0 · 🔵 1 across 8 axes.

Blockers

None.

Non-blocking, but please consider before merge

None.

Nits

  1. [Axis 7] Lockfile header revision regressed 5 -> 3 (out-of-scope churn from an older local uv; contradicts PR body) (uv.lock:2) — The diff changes -revision = 5 to +revision = 3 at uv.lock:2. This line has nothing to do with the multidict 6.7.1 -> 6.9.1 bump. It is an artifact of relocking with an older local uv than the one release.yml uses (setup-uv v4.2.0, which installs the latest uv). It also contradicts the PR body's claim that 'all 193 changed lines are multidict's version and wheel list'. Nothing breaks, because uv sync --frozen accepts revision 3. But the header will flip back: release.yml:238 runs uv lock followed by git add uv.lock on the next semantic-release, which rewrites it to revision = 5. That creates lockfile churn in a bot commit, and the header will keep going back and forth between contributors on different uv versions. Fix: restore revision = 5 (relock with the same uv version CI's release job uses, or hand-revert line 2), so that the diff contains only the multidict stanza. Optional: pin a minimum uv version (e.g. [tool.uv] required-version in pyproject.toml), which stops older local uv from relocking and downgrading the format revision.

What's Missing

Daily/nightly:

  • 🔵 The PR does not say what happens to the nightly run. The multidict 6.7.1 -> 6.9.1 bump does not stay in the dev venv. Both container images install from this lockfile: docker/Dockerfile:97 and docker/Dockerfile.runtime:63 run uv export --frozen ... | uv pip install. So the next image rebuild ships the new multidict (an aiohttp/yarl transitive) into every driver: docker task in the nightly. Add one line to the PR that names the image-rebuild blast radius. Also record that the bump was checked against the docker path, not only against uv sync --frozen in pr-checks. (trigger: uv.lock)

Parallel paths:

  • 🔵 The uv version is not pinned on any path that writes or reads this lockfile. Local contributors use whatever uv they have installed. release.yml:195/238 runs uv lock under setup-uv v4.2.0 with no version input, and docker/Dockerfile:45 and Dockerfile.runtime:38 run curl astral.sh/uv/install.sh at latest. The revision 5 -> 3 regression came from the contributor path. Nothing aligns the other three paths, so the same flip can come back from any of them. A [tool.uv] required-version in pyproject.toml covers all four in one place. (trigger: uv.lock) (restates: Axis 7: Lockfile header revision regressed 5 -> 3)

Harness & Lint Improvements

Static checks (lint / type):

  • [ce-lint] CE069 (next free number; CE067 is retired per .claude/harness-candidates.md:958), 'uv toolchain pin parity'. This is a whole-tree rule, so it goes in a @pytest.mark.lint class in tests/test_custom_lint.py, not in tests/lint/rules/ + runner.py. It parses pyproject.toml, uv.lock and .github/workflows/*.yml and fails in three cases. (a) pyproject.toml [tool.uv] (line 214) has no required-version. (b) Any astral-sh/setup-uv step has no with: version: input, or that input is outside required-version. Today release.yml:112, pr-checks.yml:265, publish-testpypi.yml:58 and verify-published-action.yml:261 all install the latest uv. (c) The revision = N header on uv.lock line 2 is lower than the revision that the pinned uv version writes. Store that number once beside the rule, for example EXPECTED_LOCK_REVISION = 5, and update it when the uv pin moves. Add the required-version setting in the same change. Then an older local uv refuses to relock (do not delete before guarding), and the rule keeps the pin and the CI installs from drifting apart. Prevents: Axis 7 (low): the uv.lock:2 header went from revision = 5 to revision = 3 because the relock used an older local uv than CI. Check (c) fails on that diff directly. Checks (a) and (b) remove the cause: with required-version, the local uv refuses to run uv lock. With setup-uv pinned to the same version, the uv lock + git add uv.lock at release.yml:238 cannot flip the header back in a bot commit.

Harness improvements (not statically reachable):

  • Add a 'lockfile is canonical' job to pr-checks.yml, run only when a PR touches uv.lock or pyproject.toml. It installs the pinned uv version (the same one CE069 enforces), runs uv lock, and fails on git diff --exit-code uv.lock. Also add a matching make lock-check target so contributors can run the same check before they push. Why not static: To show that a lockfile is exactly what the pinned resolver produces, uv must resolve against the package index (network, index state). CE069 can see only the header revision and the version pins. It cannot see the other churn that a different uv version or resolver setting puts in the package stanzas. Prevents: Axis 7 (low): the out-of-scope uv.lock churn (the revision header, and any other relock artifacts) gets caught at PR time, before the release.yml:238 uv lock rewrites the file in a semantic-release bot commit.
  • Add a review-checklist item (or a light PR-template prompt) for dependency-bump PRs: list the package stanzas changed in git diff uv.lock and compare them with the packages the PR body names. A one-package bump that changes the file header or other packages needs a stated reason. Why not static: The mismatch is between the diff and a prose claim in the PR description ('all 193 changed lines are multidict's version and wheel list'). The PR body is not in the tree, and a judgment call is needed to say if extra churn is intended. Prevents: Axis 7 (low): this catches a PR body that does not match its uv.lock diff, here a revision 5 -> 3 header change in a PR described as touching only multidict.

Top 5 Priority Actions

  1. No confirmed finding can change a task's score or final_status for identical agent output, so grading needs no action in this change.
  2. Restore revision = 5 at uv.lock:2 (hand-revert the line or relock with the uv version that CI's release job uses), so that the diff contains only the multidict 6.7.1 -> 6.9.1 stanza.
  3. Add [tool.uv] required-version in pyproject.toml, so that an older local uv cannot relock and downgrade the lockfile format revision.
  4. Pin the uv version in the release job's setup-uv step (release.yml, before the uv lock + git add uv.lock at release.yml:238) to the same minimum, so that the semantic-release bot commit does not rewrite the uv.lock header.
  5. Correct the PR body claim that 'all 193 changed lines are multidict's version and wheel list', or make it true by reverting uv.lock:2, so that the PR description agrees with the diff.

Stats: 0 🔴 · 0 🟠 · 0 🟡 · 1 🔵 across 8 axes reviewed.

@uipreliga uipreliga left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: coder_eval — pr:218 — fix(deps): bump multidict 6.7.1 -> 6.9.1 for CVE-2026-104874 [PILOT-8488] · PR #218 by @Mihaiii · fix/multidict-cve-2026-104874 → main · OPEN

Scope: pr:218 — fix(deps): bump multidict 6.7.1 -> 6.9.1 for CVE-2026-104874 [PILOT-8488] · PR #218 by @Mihaiii · fix/multidict-cve-2026-104874 → main · OPEN · branch fix/multidict-cve-2026-104874 · 9b1da89 · 2026-10-06T10:51Z · workflow variant

Change class: trivial — lockfile-only dependency bump (transitive multidict 6.7.1 → 6.9.1); no code path changes

The codebase is healthy on all eight axes (10/10 overall), and no finding can change a task's score or final_status; the only risk is one low-severity lockfile churn (uv.lock:2 revision 5 -> 3 from an older local uv), so the bottom line is to merge after you revert that one line.

Summary

Axis Score 🔴 🟠 🟡 🔵 Top Issue
1. Code Quality & Style 10 / 10 0 0 0 0 —
2. Type Safety 10 / 10 0 0 0 0 —
3. Test Health 10 / 10 0 0 0 0 —
4. Security 10 / 10 0 0 0 0 —
5. Architecture & Design 10 / 10 0 0 0 0 —
6. Error Handling & Resilience 10 / 10 0 0 0 0 —
7. API Surface & Maintainability 9.9 / 10 0 0 0 1 Lockfile header revision regressed 5 -> 3 (out-of-scope churn from an older local uv; contradicts PR body)
8. Evaluation Harness Quality 10 / 10 0 0 0 0 —

Overall Score: 10 / 10 · Weakest Axis: API Surface & Maintainability at 9.9 / 10
Totals: 🔴 0 · 🟠 0 · 🟡 0 · 🔵 1 across 8 axes.

Blockers

None.

Non-blocking, but please consider before merge

None.

Nits

  1. [Axis 7] Lockfile header revision regressed 5 -> 3 (out-of-scope churn from an older local uv; contradicts PR body) (uv.lock:2) — The diff changes -revision = 5 to +revision = 3 at uv.lock:2. This line has nothing to do with the multidict 6.7.1 -> 6.9.1 bump. It is an artifact of relocking with an older local uv than the one release.yml uses (setup-uv v4.2.0, which installs the latest uv). It also contradicts the PR body's claim that 'all 193 changed lines are multidict's version and wheel list'. Nothing breaks, because uv sync --frozen accepts revision 3. But the header will flip back: release.yml:238 runs uv lock followed by git add uv.lock on the next semantic-release, which rewrites it to revision = 5. That creates lockfile churn in a bot commit, and the header will keep going back and forth between contributors on different uv versions. Fix: restore revision = 5 (relock with the same uv version CI's release job uses, or hand-revert line 2), so that the diff contains only the multidict stanza. Optional: pin a minimum uv version (e.g. [tool.uv] required-version in pyproject.toml), which stops older local uv from relocking and downgrading the format revision.

What's Missing

Daily/nightly:

  • 🔵 The PR does not say what happens to the nightly run. The multidict 6.7.1 -> 6.9.1 bump does not stay in the dev venv. Both container images install from this lockfile: docker/Dockerfile:97 and docker/Dockerfile.runtime:63 run uv export --frozen ... | uv pip install. So the next image rebuild ships the new multidict (an aiohttp/yarl transitive) into every driver: docker task in the nightly. Add one line to the PR that names the image-rebuild blast radius. Also record that the bump was checked against the docker path, not only against uv sync --frozen in pr-checks. (trigger: uv.lock)

Parallel paths:

  • 🔵 The uv version is not pinned on any path that writes or reads this lockfile. Local contributors use whatever uv they have installed. release.yml:195/238 runs uv lock under setup-uv v4.2.0 with no version input, and docker/Dockerfile:45 and Dockerfile.runtime:38 run curl astral.sh/uv/install.sh at latest. The revision 5 -> 3 regression came from the contributor path. Nothing aligns the other three paths, so the same flip can come back from any of them. A [tool.uv] required-version in pyproject.toml covers all four in one place. (trigger: uv.lock) (restates: Axis 7: Lockfile header revision regressed 5 -> 3)

Harness & Lint Improvements

Static checks (lint / type):

  • [ce-lint] CE069 (next free number; CE067 is retired per .claude/harness-candidates.md:958), 'uv toolchain pin parity'. This is a whole-tree rule, so it goes in a @pytest.mark.lint class in tests/test_custom_lint.py, not in tests/lint/rules/ + runner.py. It parses pyproject.toml, uv.lock and .github/workflows/*.yml and fails in three cases. (a) pyproject.toml [tool.uv] (line 214) has no required-version. (b) Any astral-sh/setup-uv step has no with: version: input, or that input is outside required-version. Today release.yml:112, pr-checks.yml:265, publish-testpypi.yml:58 and verify-published-action.yml:261 all install the latest uv. (c) The revision = N header on uv.lock line 2 is lower than the revision that the pinned uv version writes. Store that number once beside the rule, for example EXPECTED_LOCK_REVISION = 5, and update it when the uv pin moves. Add the required-version setting in the same change. Then an older local uv refuses to relock (do not delete before guarding), and the rule keeps the pin and the CI installs from drifting apart. Prevents: Axis 7 (low): the uv.lock:2 header went from revision = 5 to revision = 3 because the relock used an older local uv than CI. Check (c) fails on that diff directly. Checks (a) and (b) remove the cause: with required-version, the local uv refuses to run uv lock. With setup-uv pinned to the same version, the uv lock + git add uv.lock at release.yml:238 cannot flip the header back in a bot commit.

Harness improvements (not statically reachable):

  • Add a 'lockfile is canonical' job to pr-checks.yml, run only when a PR touches uv.lock or pyproject.toml. It installs the pinned uv version (the same one CE069 enforces), runs uv lock, and fails on git diff --exit-code uv.lock. Also add a matching make lock-check target so contributors can run the same check before they push. Why not static: To show that a lockfile is exactly what the pinned resolver produces, uv must resolve against the package index (network, index state). CE069 can see only the header revision and the version pins. It cannot see the other churn that a different uv version or resolver setting puts in the package stanzas. Prevents: Axis 7 (low): the out-of-scope uv.lock churn (the revision header, and any other relock artifacts) gets caught at PR time, before the release.yml:238 uv lock rewrites the file in a semantic-release bot commit.
  • Add a review-checklist item (or a light PR-template prompt) for dependency-bump PRs: list the package stanzas changed in git diff uv.lock and compare them with the packages the PR body names. A one-package bump that changes the file header or other packages needs a stated reason. Why not static: The mismatch is between the diff and a prose claim in the PR description ('all 193 changed lines are multidict's version and wheel list'). The PR body is not in the tree, and a judgment call is needed to say if extra churn is intended. Prevents: Axis 7 (low): this catches a PR body that does not match its uv.lock diff, here a revision 5 -> 3 header change in a PR described as touching only multidict.

Top 5 Priority Actions

  1. No confirmed finding can change a task's score or final_status for identical agent output, so grading needs no action in this change.
  2. Restore revision = 5 at uv.lock:2 (hand-revert the line or relock with the uv version that CI's release job uses), so that the diff contains only the multidict 6.7.1 -> 6.9.1 stanza.
  3. Add [tool.uv] required-version in pyproject.toml, so that an older local uv cannot relock and downgrade the lockfile format revision.
  4. Pin the uv version in the release job's setup-uv step (release.yml, before the uv lock + git add uv.lock at release.yml:238) to the same minimum, so that the semantic-release bot commit does not rewrite the uv.lock header.
  5. Correct the PR body claim that 'all 193 changed lines are multidict's version and wheel list', or make it true by reverting uv.lock:2, so that the PR description agrees with the diff.

Stats: 0 🔴 · 0 🟠 · 0 🟡 · 1 🔵 across 8 axes reviewed.

@Mihaiii
Mihaiii merged commit 2fc1ae0 into main Oct 6, 2026
21 of 22 checks passed
@Mihaiii
Mihaiii deleted the fix/multidict-cve-2026-104874 branch October 6, 2026 11:37
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.

4 participants