Skip to content

Relock OpenHands onto oauthlib 4.0.0 / PyJWT 2.15.1 by 2026-10-08 (osv ignores from #517 expire 2026-10-13) #518

Open

Description

@seathatflowsinourveins

Due by 2026-10-08 (hard limit 2026-10-13). On 2026-10-13 the time-boxed osv ignores from #517 expire. They apply repo-wide by id, so the required osv-scanner check will fail on every PR again unless this is done or the ignores are renewed first.

Owner: the coordinator session that landed #525, native-agent-stack-bc (bc), unless reassigned here. The previous owner of the OpenHands lock, the runtime-worker session token-save-practice-e2e-status, is gone. Earliest start: 2026-10-05T18:40:43Z, when PyJWT 2.15.1 has left the 7-day window that the upstream workspace's exclude-newer applies; oauthlib 4.0.0 leaves it at 2026-10-05T06:01:19Z and PyJWT 2.15.0 at 2026-09-30T16:56:01Z (each measured 7 days after the later of the release's file upload times on PyPI).

Decision point 2026-09-30T16:56:01Z (owner bc): PyJWT 2.15.0 has left the window. Decide, with a recorded reason, whether the OpenHands lock moves to 2.15.0 before the joint relock. Its Security item ("Wrap recursion errors from deeply nested JWT payloads in DecodeError instead of exposing a raw RecursionError", no advisory id) is the payload counterpart of GHSA-8wjv-2p76-3863, which 2.14.0 fixed for headers; the reason has to address whether the recipe venv ever decodes attacker-controlled tokens (the 2026-09-29 search found jwt.encode in mcp only, google-auth's verify_token uncalled and the LiteLLM proxy not run).

Done (#525, 2026-09-30): the OpenHands lock (blueprints/runtime-workers/openhands/requirements.lock) is relocked onto PyJWT 2.14.0. Its sha256 is now 14e57b8d947e62ed60e7bbc69c2e6cc55638a86fa8969d528cbdf591cd42ae64 (was 02d0a7f0…). The GHSA-w6j9-cwv2-h6wq ignore and its scope entry are deleted. Nine more PyJWT advisories that failed the check are fixed by the same relock.

Remaining (OpenHands lock):

  • Relock onto oauthlib 4.0.0 (fixes GHSA-hj66-6f7g-4r5v and GHSA-xpv3-w29h-x7cv) and PyJWT 2.15.1, or record why 2.14.0 stays (2.15.0's changelog has an unnumbered Security item, recursion errors wrapped in DecodeError; 2.15.1 fixes Base64URL = padding). Use the method in research.md ("Runtime lock PyJWT relock (2026-09-30)") with --upgrade-package oauthlib==4.0.0 added and --upgrade-package pyjwt==2.14.0 replaced by --upgrade-package pyjwt==2.15.1.
  • Checks: the recipe's hashed install sequence and SDK import check; import requests_oauthlib, google_auth_oauthlib.flow and requests-oauthlib 2.0.0's unit tests under oauthlib 4.0.0 (the 2026-09-30 pre-check found the same outcome for each test as under 3.3.1: 72 passed and the same 2 failed, both timing assertions; oauthlib is reached only through requests-oauthlib from google-auth-oauthlib from browser_use's gmail integration); the recipe's offline tests; the pinned osv-scanner as .github/workflows/security-scan.yml runs it.
  • In the same PR, delete the OpenHands IGNORE_ALLOWED_LOCKS entry in tests/test_osv_lockfile_coverage.py (it pins the lock at sha256 14e57b8d…, so any lock change fails that test until the entry is updated or removed), update the two oauthlib ignores' reasons (the Lumibot lock still needs them), and re-register through the hot-file protocol.

Frozen Lumibot lock (blueprints/us-equities/engine-trials/spy-one-zero-20260926/lumibot/lockcheck/lumibot.lock; trading lane): it keeps oauthlib 3.3.1 by design. On 2026-10-13, either renew the two oauthlib ignores for this lock alone with a new dated reason, or delete the lock (as the existing nltk and setuptools entries already plan).

Evidence: evidence/receipts/osv-openhands-pyjwt-relock-20260930.json (the relock, its follow-up and the pre-check) and evidence/receipts/osv-oauthlib-pyjwt-reachability-20260929.json (the static search that found no reachable vulnerable oauthlib path, one hash-checked artifact per requirement of both locks).

Residuals recorded at the merge of #525 (found by the second review; fixed in a follow-up text PR, D1 confirmed at the 2026-09-30T16:56:01Z decision point):

  • D1. The recorded reason for staying on PyJWT 2.14.0 omitted redis 7.2.1's jwt.decode. Searched 2026-09-30 (10,746 installed .py files of the relocked venv, static): redis/auth/token.py:89 decodes with verify_signature false a token that a configured credential provider hands to redis; nothing outside redis references redis.auth.token or JWToken, and the recipe's own code imports no redis. The PyJWT importers of the venv are google-auth (oauth2/id_token.py:153, verify_token; no importer of that module outside google-auth), LiteLLM (its proxy server, not run), oauthlib (common.py:221 verify_signed_token, no caller outside oauthlib), redis and mcp (jwt.encode only). Reachability of an attacker-controlled token decode: none found.
  • D2. The receipt's timing-assertion range for the two failing requests-oauthlib tests reads 0.38 to 0.43 s; the retained outputs show 0.22 to 0.28 s.
  • Nits. Unlabelled exceptions in the returned-outputs header rule, a prose $ line, the undeclared ~ substitution, the builder script not in the repo, exit times rounded up to the next second.

Residuals recorded at #529's review (session 21, approve with nits; all low, none changes the conclusion; fix in the next text change to these files, e.g. with the joint relock's record on 2026-10-05):

  • R1. The returned-outputs header says angle brackets mark only the three path placeholders, but two abridged $ lines also carry <result lines> and <parser>:<path>: say "or abridged arguments".
  • R2. The section H loop line is missing its closing ; done (builder line 141).
  • R3. Section I shows $ sha256sum uv.lock, but the builder ran it on the downloaded grader lock piped to cut -c1-64; show the real command.
  • R4. The receipt says the 0.22 to 0.28 s run is in "this file's git history at f77612b": name the file (relock-2026-09-30.txt), since the receipt's own f77612b version carries the rejected 0.38 to 0.43 s wording.
  • R5. The section K script lists names imported by from jwt import ... but does not count calls through them (from jwt import decode; decode(t) counts 0), so "from-imports included" overstates it; no effect on this venv (only PyJWK and PyJWKSet come in that way). Its import jwt pattern has no word boundary after jwt, which can only over-count.

Activity

  1. changed the title [-]Relock OpenHands onto oauthlib 4.0.0 / PyJWT 2.14.0 before 2026-10-13 (osv ignores from #517 expire)[/-] [+]Relock OpenHands onto oauthlib 4.0.0 / PyJWT 2.15.1 by 2026-10-08 (osv ignores from #517 expire 2026-10-13)[/+] on Sep 30, 2026
  2. seathatflowsinourveins commented on Sep 30, 2026

    @seathatflowsinourveins
    CollaboratorAuthor

    Owner note (bc), 2026-09-30 10:05Z: Codex's draft PR #535 replaces the live OpenHands lock with an SDK 1.50.0 Linux x86_64 / CPython 3.13.15 wheel lock. My independent OAuthlib reachability reviews of its two heads are on main: #536 (head bb3d00dc, lock 8d257833…, historical, merged as 8edc604e560f77c9d0952a6497a2a0bca36a8440) and #537 (head 6a7b16465e50689334d9dd15ff4fed99a9cd7485, lock 383ccc5b87702174e471732872f002f1621186710402d048acc2b1910306e106, merged as 11227bfdf25b55b0481a9e78985c3fed26052472, evidence/artifacts/openhands-oauthlib-review-535-head6a7b16-20260930/). Verdict for that exact lock: no reachable path to GHSA-hj66-6f7g-4r5v or GHSA-xpv3-w29h-x7cv; no merge or exception approval given. If #535 merges, the OpenHands IGNORE_ALLOWED_LOCKS entry is bound to 383ccc5b… instead of 14e57b8d…, and this issue's joint relock (oauthlib 4.0.0 / PyJWT 2.15.1, no earlier than 2026-10-05T18:40:43Z, due 2026-10-08) deletes it and builds on whatever lock is on main then. The PyJWT 2.15.0 decision point (2026-09-30T16:56:01Z) is unchanged.

  3. seathatflowsinourveins commented on Sep 30, 2026

    @seathatflowsinourveins
    CollaboratorAuthor

    Decision at the 2026-09-30T16:56:01Z point (owner bc): move the OpenHands lock to PyJWT 2.15.0 now, ahead of the joint relock.

    Reason: overturn condition (a) of the 04:30Z choice is met. OSV lists GHSA-42vr-xj54-vc7v (CVE-2026-101918, PyJWT >= 2.0.0a1 and < 2.15.0, a raw RecursionError from a deeply nested payload) for PyJWT 2.14.0; its OSV record was published at 15:41:05Z and reaches scans from about 16:00Z, where it fails the required osv-scanner check on the OpenHands lock. Only 2.15.0 or later fixes it, and 2.15.0 left the workspace's 7-day window at 2026-09-30T16:56:00.689Z (files uploaded 2026-09-23T16:55:59Z and 16:56:00Z). A fix is available, so no ignore and no reachability argument are needed. For the record, the advisory's call path exists in the venv (google-auth oauth2/id_token.py:144-145, the JWKS branch of verify_token) and nothing in the venv outside the google package imports that module; redis token.py decodes with verify_signature false only for a provider-supplied token (the D1 residual).

    Done in PR #546 (head bd48d92, CI running; I post the merge sha here): the lock (sha256 1d11bae34f09707d1ad353e24c33d25c7b004f25de9821d434e065b10969559c, previously 14e57b8d...) changes the urllib3 (2.8.0, three advisories) and pyjwt (2.15.0) entries only; the 5-upgrade control reproduces the old lock byte for byte; the recipe's hashed install, uv pip check and the SDK import check pass; the four oauthlib source files the earlier review names hash as recorded. Recorded in research.md ("Runtime lock urllib3 and PyJWT relock (2026-09-30)"), the decision record and evidence/receipts/osv-urllib3-next-20260930.json.

    What remains for this issue: the joint oauthlib 4.0.0 and PyJWT 2.15.1 relock, no earlier than 2026-10-05T18:40:43Z, due 2026-10-08. It starts from the new lock: add --upgrade-package oauthlib==4.0.0, replace --upgrade-package pyjwt==2.15.0 with --upgrade-package pyjwt==2.15.1, keep --upgrade-package urllib3==2.8.0 unless a newer release is outside the window, and delete the OpenHands IGNORE_ALLOWED_LOCKS entry in the same change.

  4. seathatflowsinourveins commented on Sep 30, 2026

    @seathatflowsinourveins
    CollaboratorAuthor

    PR #546 is merged as 8fc8611 (2026-09-30T18:39:19Z): the OpenHands lock is on urllib3 2.8.0 and PyJWT 2.15.0 (sha256 1d11bae34f09707d1ad353e24c33d25c7b004f25de9821d434e065b10969559c), the decision point above is applied. The joint oauthlib 4.0.0 / PyJWT 2.15.1 relock starts from this lock, earliest 2026-10-05T18:40:43Z, due 2026-10-08; it deletes the OpenHands row of IGNORE_ALLOWED_LOCKS in tests/test_osv_lockfile_coverage.py in the same change. The macOS Next exception (.github/osv-scanner-frozen-macos.toml) runs to 2026-12-24.

  5. seathatflowsinourveins commented on Oct 1, 2026

    @seathatflowsinourveins
    CollaboratorAuthor

    Update 2026-10-01 (Gate A owner session): the OpenHands lock moved again before this relock. PR #562 (litellm 1.93.0 to 1.93.2, GHSA-3cv6-jpf6-8222; merge commit 74cc546) is the new starting point: sha256 e24df8328149c921f751eb93d682b3f5b66eb4efd09bf4b053ffcfca057181e1 (litellm 1.93.2, urllib3 2.8.0, PyJWT 2.15.0, oauthlib 3.3.1). Record: evidence/receipts/osv-openhands-litellm-relock-20260930.json; method and the two workspace edits: blueprints/runtime-workers/openhands/research.md, section "Runtime lock litellm relock (2026-09-30)".

    Owner: the previous owner (bc, named above) is gone. The merge-train owner said in a peer message that it takes this issue after the freeze list lands (not retained evidence): please confirm here when it is reassigned.

    What changes for the joint relock command: keep --upgrade-package litellm==1.93.2 and the two edits of the extracted workspace (litellm's exclude-newer-package cap and its ==1.93.0 pin). They can go only when pins.json source_archive and the 1.49.6 wheels are re-pinned to an SDK whose own uv.lock carries litellm 1.93.2 or later (the pinned archive's lock pins 1.93.0 for good; draft #535's candidate lock, built from another archive, already pins 1.93.2).

    What changes for the guard: the OpenHands IGNORE_ALLOWED_LOCKS entry now pins e24df832... and names the new receipt (the "delete the entry in the same PR" step stands). tests/test_openhands_lock_binding.py (new in #562) requires pins.json's two digests to equal the lock files' and the receipt of every grant to record the lock's path and the granted sha256. Draft #535 replaces this lock with its own: it conflicts with #562 in pins.json, requirements.lock, the coverage test and manifests/evidence.json, and has to keep its own grant and receipt after its rebase.

    Deferred edits (receipt limitations, owner: the Gate A owner session, before 2026-10-13): the dated paragraph of docs/decisions/2026-09-22-github-automation-closure.md (after #555 merges) and the ignore reasons in .github/osv-scanner.toml, which still name the previous owner and cite the PyJWT receipt (after #535 merges); if either has not merged by 2026-10-09 they go in a change of their own.

  6. seathatflowsinourveins commented on Oct 3, 2026

    @seathatflowsinourveins
    CollaboratorAuthor

    native-agent-stack-f9: cross-family convergence result (2026-10-03; two GPT-6 Astra and two Claude Opus votes) for the daily report's recipe:openhands-sdk row (v1.49.6): fold a move to v1.50.1 (1e1390ac) into this relock, so one updater owns the lock.

    • Why v1.50.1, not v1.51.0: v1.50.1 already carries all three fixes the agent-server needs: anyio #5361, PyJWT #5391 and the VSCode token #5282. It is also the comparison baseline and the plan's pin. v1.51.0 adds no fix the recipe needs and raises the pydantic floor.
    • Window: no earlier than 2026-10-05T18:40:43Z (upstream exclude-newer). Due 2026-10-08; the oauthlib ignores expire 2026-10-13.
    • Acceptance:
      1. Re-derive the pins.json fields.
      2. Relock, including binaryornot>=0.6.0.
      3. Handle the IGNORE_ALLOWED_LOCKS digest (tests/test_osv_lockfile_coverage.py:917-922): give it a new reachability review, or delete the entry with oauthlib 4.0.0.
      4. Add a #5345 negative control: a dead MCP server must fail the run.
      5. Re-verify the skills recipe's claims at 1e1390ac.
      6. Run a new grype scan and the full unittest suite.
    • Ownership: the thread says bc is gone, so this needs a confirmed successor. I've raised that with the user.
  7. seathatflowsinourveins commented on Oct 4, 2026

    @seathatflowsinourveins
    CollaboratorAuthor

    Command center (wsl-architecture-design), 2026-10-04T07:56:31Z: ownership and dates for the two halves of this fix.

    Two ignore groups in .github/osv-scanner.toml expire on 2026-10-13: GHSA-hj66-6f7g-4r5v and GHSA-xpv3-w29h-x7cv (oauthlib < 4.0.0). After that date, the required validate and osv-scanner checks fail on every PR.

    1. OpenHands relock (foundation): blueprints/runtime-workers/openhands/requirements.lock moves to oauthlib 4.0.0 and PyJWT 2.15.1.
      • It goes in with the NativeStack2604 runtime-worker wave, where OpenHands software-agent-sdk v1.51.0 is installed from its tag's lock.
      • It is relocked from upstream's own lock, with the upstream tests at the tag.
      • Target: merged by 2026-10-08.
    2. Frozen Lumibot lock (trading): the trading lane is stopped. By the user's 2026-10-04 decision, its remaining work is dispatched by the command center.
      • A bounded job checks whether anything still uses the lock. It then either retires the lock (renamed to .frozen and out of the scan, as the WSL retrieval lock is being retired) or renews the ignore with an evidenced reason and a new date.
      • Target: merged by 2026-10-10.

    lane:foundation stays for half 1. Half 2 gets its own lane:trading PR.

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

    lane:foundationFoundation lane: Claude/Codex setup, hosts, memory, RAG, research, workers

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions