A newly disclosed exploit chain in GitLab shows how two long-buried memory-safety flaws in a Ruby JSON parsing library, Oj, could be combined to achieve remote code execution on default GitLab installations, exposing source code, Rails secrets, and internal services.
As part of the Open Defense Initiative, Depthfirst researcher Yuhang Wu used the automated analysis system to scan Oj, a high-performance native C-based JSON parser widely used across Ruby applications, including GitLab.
The scan surfaced 18 prioritized vulnerabilities, seven of which were memory-safety bugs, two of which had silently persisted in Oj for nearly five years before being weaponized into a working exploit chain.
The two flaws were an unchecked nesting-stack write in Oj::Parser.usual.parse and an unsafe 16-bit key-length narrowing that leaked a heap pointer.
Individually, each was limited: one offered only a repeated one-byte “write” primitive, and the other disclosed a fixed 29-byte memory slice. Chained together with careful heap-allocator manipulation, they gave attackers full control of a callback pointer and a way to defeat ASLR, ultimately enabling arbitrary code execution as the “git” system user.
GitLab Vulnerabilities Enable Code Execution
GitLab renders human-readable diffs for Jupyter Notebook (.ipynb) files using an in-tree gem called ipynbdiff. Before generating this diff, the gem parses each notebook revision using Oj’s native parser to validate that the JSON contains a “cells” field.
Because a notebook file is fundamentally a JSON document, any authenticated user who could push commits and view a commit diff could smuggle malicious JSON structures into that call.
The exploit worked by pushing two specially crafted notebook files in one commit-diff request. The first file’s oversized nesting depth abused the unchecked stack write to redirect an internal buffer pointer, and later heap operations caused a Ruby Array’s memory to overlap with a parser callback pointer, letting attackers plant a chosen address into p->start.
A second heap-pointer leak, smuggled out inside an oversized JSON object key and rendered into the diff’s HTML output, gave attackers the address needed to calculate the memory location of core libraries like libc and libruby, defeating ASLR protections.
Because Puma (GitLab’s Ruby app server) runs multiple threads sharing one native parser instance per worker, both crafted files were processed by the same vulnerable parser inside a single request, letting the second file trigger the corrupted callback and execute a shell command via system().
Unlike earlier GitLab remote code execution issues that relied on server-side request forgery against internal Redis instances, this chain bypassed GitLab’s modern SSRF defenses entirely by attacking a native memory-unsafe dependency embedded inside otherwise memory-safe Ruby code.
Any project member with ordinary push and diff-view access could trigger the chain without administrator rights, CI/CD access, or victim interaction, making it especially dangerous for shared or multi-tenant self-managed GitLab instances.
Successful exploitation allowed commands to be executed as the “git” account that powers GitLab’s Puma workers. This could potentially expose repository source code, Rails application secrets, service credentials, and any internal services accessible from the GitLab host. As a result, there is a risk of data theft, code tampering, and lateral movement, according to Depthfirst in a statement to CybersecurityNews.
Affected Versions and Fixes
| Component | Affected Versions | First Fixed Release |
|---|---|---|
| GitLab CE/EE | 15.2.0–18.10.7 | 18.10.8 |
| GitLab CE/EE | 18.11.0–18.11.4 | 18.11.5 |
| GitLab CE/EE | 19.0.0–19.0.1 | 19.0.2 |
| Oj gem | 3.13.0–3.17.1 | 3.17.3 |
GitLab.com was already patched at disclosure, and Dedicated customers required no action, but self-managed operators on the affected version ranges must upgrade immediately.
The vulnerable Oj parser code was merged in August 2021, and GitLab began using the affected parsing call in July 2022 via GitLab 15.2.0.
The researcher reported the core Oj bugs on May 21, 2026; Oj merged fixes on May 27, after the flaws had lingered for 1,753 days, with Oj 3.17.3 published June 4. The GitLab-specific chain was reported June 5, confirmed June 8, and patched on June 10, 2026, across the 19.0.2, 18.11.5, and 18.10.8 releases.
The same research effort produced nine published CVEs for Oj beyond the two used in this chain, spanning stack and heap buffer overflows, multiple use-after-free conditions in SAJ callbacks and document iterators, a negative-size memcpy, and a large-file integer overflow, underscoring how deeply memory-corruption risk can hide inside native extensions bundled with otherwise “safe” Ruby applications.
Security teams running self-managed GitLab should prioritize patching to the fixed releases above and audit Ruby dependency trees for native C extensions, since memory-unsafe code inside a trusted gem can undermine the memory-safety guarantees of an entire Ruby application stack
Strengthen Your SOC by Accelerating Threat Detection & Rapid Investigations. -> Integrate ANY.RUN With Your SOC Now.

