Skip to content

Back to the catalog

GHSL-2026-203: Same-second TOCTOU in jupyterlab/maintainer-tools
securitylab.github.comadvisory

GHSL-2026-203: Same-second TOCTOU in jupyterlab/maintainer-tools

GitHub Security Lab discloses GHSL-2026-203 / CVE-2026-84973, a same-second time-of-check-to-time-of-use race condition in the jupyterlab/maintainer-tools update-snapshots-checkout GitHub Action. The action compares one-second-precision pushed_at and comment created_at timestamps to detect post-authorization pushes, but a strict greater-than check lets an attacker push a malicious commit in the same second as an authorized "please update snapshots" comment, causing the action to check out and later execute attacker-controlled code (including a local composite action and jlpm-driven package scripts) with the workflow's GITHUB_TOKEN (contents: write, pull-requests: write) in the jupyter/notebook repository. The issue was fixed in v1.0.0 and is a variant of the "pwn request" class of GitHub Actions vulnerabilities.

TL;DR A one-second race condition in jupyterlab/maintainer-tools' update-snapshots-checkout Action let PR authors sneak malicious commits past a timestamp-based authorization check, enabling attacker-controlled code execution with write-scoped GITHUB_TOKEN in jupyter/notebook workflows.
Document

What it is

GHSL-2026-203 / CVE-2026-84973 / GHSA-wwhg-p79f-vfvm: a same-second TOCTOU in the update-snapshots-checkout composite action in jupyterlab/maintainer-tools, fixed in v1.0.0. The vulnerable code was tested at commit b48fcdb87e70c45789abd80d4042b06641e47b46 — which is what the @v1 tag pointed to in the affected jupyter/notebook workflow. Reported by GHSL's @JarLob; PVR filed 2026-08-27, fixed and disclosed 2026-09-03.

How it works

The action authenticates the commenter (must be OWNER, COLLABORATOR, or MEMBER) and then tries to reject any push made after the authorizing comment by comparing the PR head repo's pushed_at against the comment's created_at:

if [[ $(date -d "$pushed_at" +%s) -gt $(date -d "$COMMENT_AT" +%s) ]]; then
    exit 1
fi

Both timestamps are one-second precision, and the guard uses strict -gt. A push landing in the same second as the comment compares equal, passes the guard, and the attacker-controlled head SHA is recorded. A later check confirms the checkout HEAD equals that recorded SHA — but that only validates against the post-race SHA, not the commit the maintainer meant to approve, so it adds no protection.

In jupyter/notebook, execution then flows through a local composite action (./.github/actions/build-dist) and jlpm run against PR-controlled package metadata — both attacker-controllable execution paths.

Preconditions / Affected

  • update-snapshots-checkout before v1.0.0, in a workflow that executes code from the checked-out PR tree.
  • A trigger comment from a privileged association, and an attacker able to poll for it and push within the same one-second window.
  • In the demonstrated case the job's GITHUB_TOKEN had contents: write and pull-requests: write; impact is bounded by those permissions plus branch protection. The PoC did not use unrelated secrets or modify a protected branch.

What to do

Update the action to v1.0.0. If you pin by SHA, replace references to b48fcdb87e70c45789abd80d4042b06641e47b46. Audit any workflow that calls this action and subsequently runs code from the checkout (local composite actions, jlpm/npm lifecycle scripts).

Caveats

The race is unreliable by the authors' own account: because of one-second granularity, a comment created late in a second leaves too little time to alter the fork. GHSL nonetheless verified several successful PoC runs with an optimized script, confirming the guard bypass is real.

Organisations named here

  • CWE-829
  • GHSA-wwhg-p79f-vfvm
  • GitHub Security Lab
  • JarLob

CVEs named here

  • CVE-2026-84973

Technologies named here

  • jupyterlab/maintainer-tools update-snapshots-checkout action
  • update-snapshots-checkout action
  • jupyter/notebook
  • update-snapshots action
  • base-setup action
  • gh
  • jlpm
  • Playwright
  • GitHub Actions
  • GitHub

Techniques named here

  • Same-second TOCTOU race condition
  • Inclusion of Functionality from Untrusted Control Sphere
  • Pwn Request
  • Time-of-check Time-of-use Race Condition