Security researchers at depthfirst published a working remote-code-execution proof of concept on July 24 for a GitLab flaw the company quietly fixed six weeks earlier, on June 10, without ever filing it as a security issue. There is no CVE, no CVSS score, and no mention of the underlying bug chain in GitLab’s release notes — just a version bump for a bundled dependency, tucked under “bug fixes.” The PoC lets any authenticated user with push access to a single project run arbitrary commands as the git user on any unpatched self-managed instance.

What happened

The vulnerable code path is GitLab’s notebook diff renderer, an in-tree gem called ipynbdiff that generates human-readable diffs when a .ipynb Jupyter notebook file changes in a merge request or commit view. To do that, it hands the repository-controlled notebook JSON to Oj::Parser.usual.parse — the Oj gem’s C extension — inside a long-lived Puma application worker. That puts fully attacker-controlled bytes directly in front of Oj’s manually managed C memory, running in the same process that serves every other user’s requests.

Two independent bugs in Oj make that exploitable:

  1. A buffer overflow writes past a fixed 1,024-byte nesting stack. With enough nested JSON structures in a crafted notebook, an attacker can walk that overflow far enough to overwrite the parser’s start callback pointer.
  2. A truncation bug: object keys are supposed to be capped at 65,565 bytes, but the length gets truncated to a signed 16-bit field and wraps to 29. GitLab renders that corrupted value straight into the diff view — leaking a live heap pointer back to the attacker.

Chained together: the attacker commits a crafted notebook and opens its commit diff to leak a heap pointer, repeats that until they can locate libc in the worker’s address space, then commits two more notebooks that use the nesting-stack overflow to redirect the parser’s callback at system(). No CI access, no runner access, no admin rights, no victim interaction — just push access to any project and the ability to view a commit diff.

Affected versions and patch status

GitLab bundled Oj 3.17.3 in the June 10 patch releases — 19.0.2, 18.11.5, and 18.10.8 — which fixes both underlying bugs. Any self-managed instance still on 18.11.3, 18.11.4, or an earlier line in the 18.10/18.9 series remains exploitable. Because GitLab never classified this as a security fix, it didn’t get a CVE, didn’t appear in the security-release table, and won’t show up in vulnerability scanners that key off GitLab’s own advisory feed — meaning a lot of “we patch security releases promptly” shops are still exposed without knowing it. GitLab.com and GitLab Dedicated are already running patched versions; this is a self-managed problem.

depthfirst says it has no evidence of in-the-wild exploitation as of July 24, but that window is closing fast now that working exploit code is public and the bug requires nothing more privileged than a developer account.

Impact

Any user who can push to a single project — the lowest bar for authenticated access in most GitLab deployments — can pivot to code execution as the git system user inside the Rails/Puma application host. From there, an attacker has read access to every repository the instance hosts (including private ones), GitLab’s database credentials and secrets, CI/CD variables and stored deploy keys, and a foothold to escalate further inside whatever network segment the GitLab host sits in. For instances that host infrastructure-as-code, CI pipeline definitions, or credentials for downstream cloud accounts — which describes most self-managed GitLab deployments — this is a direct path from “someone with a throwaway account” to “attacker controls your build pipeline and secrets store.”

Mitigation

  • Upgrade self-managed instances to 18.10.8, 18.11.5, 19.0.2, or later immediately. This applies even if your patch cadence considers June 10 “already handled” — confirm the actual running Oj gem version (gem list oj on the GitLab host), since the fix shipped silently.
  • If you cannot patch immediately, restrict who can push to projects on the instance, or disable notebook diff rendering if your GitLab version exposes that toggle.
  • Audit Puma worker crash logs and Sentry/error-tracking output around commit-diff views for segfaults or anomalous restarts — worker crashes during failed heap-leak attempts are the most visible pre-exploitation signal.
  • Review recent commits containing .ipynb files from low-trust or newly created accounts, particularly ones with unusually deep JSON nesting or oversized object keys.
  • Rotate CI/CD variables, deploy keys, and any secrets accessible to the GitLab application host if you find evidence of exploitation or cannot rule out exposure during the window between June 10 and your patch date.

References