Key Takeaways
- A remote‑code‑execution (RCE) flaw exists in the Oj JSON library used by GitLab’s notebook‑diff feature, allowing any authenticated user who can commit to a project to execute OS commands as the
gitservice account. - The exploit chains two memory‑corruption bugs in Oj: an out‑of‑bounds write via deep JSON nesting and an information leak via oversized object keys, together defeating ASLR and enabling arbitrary code execution.
- No administrative privileges, GitLab Runner access, or interaction from another user are required; the attacker controls both the malicious notebook and the commit‑diff view that triggers the vulnerable parser.
- The vulnerable Oj version was present in GitLab from 15.2.0 through 18.9.x; the fix (Oj 3.17.3) was shipped in the June 10 2026 releases (19.0.2, 18.11.5, 18.10.8) but was listed only as a routine dependency update, not in the security‑fix table.
- Public proof‑of‑concept code was released on July 24 2026, lowering the barrier for attackers; while no wild exploitation has been confirmed, the disclosure raises the risk significantly.
- Administrators must upgrade to the latest supported GitLab version (or at least Oj 3.17.3) on every node, verify container images in Kubernetes deployments, and monitor for anomalous notebook‑diff activity, unexpected Puma worker behavior, or outbound connections from the GitLab service account.
- Until patching, limiting untrusted account creation and project‑creation rights can reduce exposure but does not replace the need to apply the Oj fix.
Overview of the Vulnerability
Security researchers from depthfirst disclosed a remote‑code‑execution vulnerability affecting all self‑managed GitLab installations (Community and Enterprise Editions, Free, Premium, and Ultimate tiers). The flaw resides in the Oj high‑performance JSON‑processing library, a native C extension used by Ruby. By exploiting two distinct memory‑corruption defects in Oj, an authenticated user with commit rights can execute arbitrary operating‑system commands on the underlying server, running under the git service account that powers GitLab’s Puma application workers.
Attack Vector via Jupyter Notebook Diff
GitLab provides a specialized notebook‑diff feature that renders changes to Jupyter Notebook (.ipynb) files for easier review. Internally, this functionality calls ipynbdiff, which passes the notebook’s JSON content to Oj::Parser.usual.parse. Because an attacker can commit a notebook version they control and then immediately view the resulting commit‑diff page, they control the JSON supplied to the vulnerable parser without needing any additional interaction, administrative privileges, or access to a CI/CD pipeline. The attack therefore requires only an authenticated account capable of committing to a project—a low‑privilege user, contractor, or compromised credential suffices.
Technical Details: Two Memory‑Corruption Defects
The exploit chains two independent Oj bugs.
-
Nesting‑depth out‑of‑bounds write – Oj’s parser tracks nested arrays/objects in a fixed 1,024‑byte array. In vulnerable versions, the parser does not verify that the nesting depth stays within this boundary. A JSON document with thousands of nested arrays can cause the parser to write past the end of the array, overwriting adjacent memory. Although the initial overwrite repeats a selector value, researchers showed they could manipulate the allocator so that a later Ruby array allocation overlapped the corrupted data, giving control over an internal buffer pointer.
- Oversized‑key information leak – When processing exceptionally long JSON object keys, Oj truncates the length into a signed 16‑bit field. A key of 65,565 bytes is interpreted as 29 bytes, causing the parser to return data that overlaps an internal pointer rather than the intended key content. Because GitLab embeds this parser output in the rendered notebook diff, the leaked pointer becomes visible in the HTTP response.
The leaked pointer defeats address‑space layout randomization (ASLR) by providing a heap address reference, allowing the attacker to locate loaded libraries (e.g., libc, Ruby runtime). The out‑of‑bounds write is then used to overwrite a function callback inside the Oj parser structure with the address of system(), turning a malicious JSON document into arbitrary command execution.
Exploitation Context and Potential Impact
Successful execution runs as the git OS user, the account under which GitLab’s Puma workers operate. While this does not grant immediate root privileges, the git account is highly trusted within a self‑managed GitLab environment and may have access to source code, configuration files, Rails secrets, service tokens, CI/CD data, and internal services such as databases, storage, or Gitaly nodes. Consequently, compromise could pivot into the broader software supply chain, especially if the GitLab service shares networks or secrets with other components. The actual impact depends on deployment specifics—containerization, separation of services, mounted secrets, and network restrictions—but organizations should treat any git‑level code execution as a serious breach.
Public Proof‑of‑Concept and Limitations
The released proof‑of‑concept targets GitLab 18.11.3 on a 64‑bit x86 platform, relying on specific library offsets, Ruby object behavior, and jemalloc allocation patterns. This makes the exploit less portable; attackers must first leak memory addresses to calculate offsets, a process that takes roughly five to ten minutes on a fresh installation with two Puma workers, or up to one to two hours on systems with longer‑running workers and fragmented memory. The leaked layout is only valid while the targeted Puma process remains alive; restarting the Puma master invalidates the addresses. Nevertheless, publishing the technical analysis provides a foundation for others to adapt the exploit to different builds, and the public repository lowers the effort needed to reproduce the attack against the original environment.
Patch Communication and Management Concerns
Oj 3.17.3, which contains fixes for both defects, was incorporated into GitLab via a routine dependency update committed to the source tree. The June 10 2026 release notes listed “Update dependency oj to v3.17.3” under the bug‑fix section for versions 19.0.2, 18.11.5, and 18.10.8, but did not place it in the dedicated security‑fix table that includes CVE identifiers, CVSS scores, and impact descriptions. Consequently, many security teams that prioritize updates based on CVE feeds or vendor security tables may have overlooked the change, even though it addresses a potential server compromise. GitLab’s announcement urged immediate upgrades but did not publicly link the Oj update to authenticated RCE, and the absence of a CVE means scanners relying solely on CVE data will not flag vulnerable installations. Administrators must therefore verify product and dependency versions directly rather than waiting for scanner signatures.
Deployment‑Specific Considerations (Kubernetes, Helm, Operator)
Organizations running GitLab on Kubernetes should not rely solely on the version of the Helm chart or Kubernetes Operator; those components use separate versioning schemes. The critical factor is the Webservice container image that runs Puma and loads the Oj native extension. Administrators must inventory all Webservice replicas, confirm each image contains a supported GitLab version bundling Oj 3.17.3 or later, and ensure no older image persists in rollback configurations, secondary sites, or stale deployments, or secondary sites. Mixed‑version environments can leave pockets of exposure even if the orchestration layer appears up‑to‑date.
Absence of Wild Exploitation and Evolving Risk
Depthfirst reported no known exploitation in the wild at the time of disclosure, and GitLab confirmed it reproduced the RCE before issuing the patch. However, the lack of observed attacks does not guarantee safety; the exploit runs within normal GitLab processes and may not produce distinctive crashes. The publication of working exploit code materially raises the risk, enabling attackers to create more portable payloads, scan for exposed instances, and target organizations that delayed the June update. Internet‑facing GitLab instances, those serving large numbers of external contributors, and repositories holding high‑value proprietary code should be prioritized for remediation.
Historical Exposure Timeline
The vulnerable Oj parser logic was introduced in August 2021 (Oj 3.13.0). GitLab began using the affected Oj::Parser.usual.parse call for notebook validation in July 2022, making the flaw reachable starting with GitLab 15.2.0. Depthfirst calculated that the Oj defects remained unpatched for 1,753 days (≈ 4.8 years) before the upstream fixes were merged, meaning the notebook‑rendering path exposed the vulnerability for nearly four years. The issues were discovered during depthfirst’s Open Defense Initiative audit of Oj’s native code, which yielded eighteen findings; subsequent human analysis validated the two bugs used in the GitLab RCE chain.
Coordinated Disclosure Timeline
- May 21, 2026: Oj vulnerabilities reported to the project.
- May 27, 2026: Oj maintainer merged fixes for nesting‑depth and oversized‑key problems.
- June 4, 2026: Oj 3.17.3 released with both corrections.
- June 5, 2026: depthfirst privately reported the reachable GitLab RCE chain to GitLab.
- June 8, 2026: GitLab confirmed the vulnerability.
- June 10, 2026: GitLab released patched versions 19.0.2, 18.11.5, and 18.10.8.
- July 17, 2026: GitLab marked the report as resolved.
- July 24, 2026: depthfirst published detailed technical analysis and proof‑of‑concept code.
The timeline shows that patches were available before public disclosure, but the manner in which the Oj update was communicated (as a routine bug fix) likely delayed uptake among administrators who rely on security‑focused release notes.
Guidance for Administrators
- Version Verification: Identify the exact GitLab version running on every node, pod, or container. Any instance older than the fixed releases (or any version between 15.2.0 and 18.9.x that has not been upgraded to a supported branch) must be updated immediately to the latest supported release containing Oj 3.17.3 or later.
- Container Image Checks: For Kubernetes deployments, inspect the Webservice image tags and digest values; ensure each replica runs a patched GitLab image.
- Monitoring: Review GitLab and system logs for abnormal notebook‑diff requests, unusually large .ipynb files, repeated Puma worker crashes/restarts, or unexpected outbound connections from the
gitaccount. - Incident Response: If compromise is suspected, treat the event as an application‑server breach: isolate the host, preserve forensic evidence, rotate accessible secrets and tokens, review repository access, and examine connected CI/CD pipelines and internal services.
- Interim Mitigations: While upgrading is essential, limiting untrusted account creation, tightening project‑creation permissions, and disabling notebook rendering (if not needed) can reduce the attack surface but do not replace patching.
- Dependency Management: For teams that manage Oj independently, upgrade to at least version 3.17.3, preferably the newest stable release compatible with the GitLab version in use.
By promptly applying the Oj fix, validating versions across all deployment vectors, and maintaining vigilant monitoring, organizations can close this nearly‑four‑year‑old exposure window and protect their GitLab environments from remote code execution.

