GitLab RCE Chain via Malicious Jupyter Notebooks Exploiting Oj Ruby JSON Parser Flaws

GitLab RCE Chain via Malicious Jupyter Notebooks Exploiting (TL-2026-1715), also tracked as GitLab Oj Notebook-Diff Authenticated RCE, is a critical-severity software vulnerability, first published 2026-07-27. It has no confirmed attribution, affects GitLab GitLab CE/EE, maps to 19 MITRE ATT&CK techniques (T1005, T1021, T1059.004), and is covered by 9 detection rules and 27 indicators of compromise.

Key facts for TL-2026-1715

Threat ID
TL-2026-1715
Also known as
GitLab Oj Notebook-Diff Authenticated RCE, Going depthfirst
Severity
CRITICAL
Status
ACTIVE
Category
VULNERABILITY
First published
2026-07-27
Last reviewed
2026-07-27
Attribution confidence
LOW
Motivation
UNKNOWN
Target sectors
technology, softwaredevelopment, financialservices, government administration, health, criticalinfrastructure, telecoms, education
Target regions
Global
Detection rules
9
Indicators of compromise
27

Malware and tooling in GitLab RCE Chain via Malicious Jupyter Notebooks Exploiting

Malware and tooling: gitlab-rce-demo

A public exploit chain combines an unchecked nesting-stack write and a 16-bit key-length integer-truncation heap-pointer leak in the Oj Ruby JSON parser, reached through GitLab's ipynbdiff Jupyter Notebook diff renderer, to give any authenticated user with commit/push access remote code execution as the 'git' OS account on self-managed GitLab CE/EE.

How GitLab RCE Chain via Malicious Jupyter Notebooks Exploiting works

Security researcher Yuhang Wu of depthfirst AI (Open Defense Initiative) published "Going depthfirst: Achieving GitLab RCE via Two Ruby Memory Corruption Vulnerabilities," documenting an authenticated remote-code-execution chain in self-managed GitLab Community and Enterprise Edition. GitLab renders diffs of committed Jupyter Notebook (.ipynb) files by handing repository-controlled JSON to the ipynbdiff gem, which calls Oj::Parser.usual.parse — Oj being a native-C-extension Ruby JSON parser. Two long-standing memory-safety bugs in Oj, present since an August 2021 commit (Oj 3.13.0) and reachable in GitLab since notebook-diff parsing switched to Oj in GitLab 15.2.0 (July 2022), combine into a full exploit primitive.

The first bug is an unchecked nesting-stack write inside Oj::Parser.usual.parse: opening a JSON array increments a depth counter and writes a one-byte ARRAY_FUN collection selector (0x01) into a fixed-size 1,024-byte in-struct parser stack without bounds checking. A crafted notebook nesting 2,132 JSON array brackets sweeps past that boundary; depth 1,024 produces the first out-of-bounds write at offset P+0x414, and the sweep of 0x01 bytes continues toward and corrupts the parser's buf.head pointer at offset P+0x868 (from P+0x880 to P+0x801). A companion 4,001-digit JSON number literal forces the parser to realloc() its internal buffer, moving the forged/corrupted pointer through jemalloc's tcache free-list, where it is reclaimed by a subsequent 446-element Ruby Array allocation (rb_ary_new_from_values()); array elements 176-177 assemble the target callback-pointer value via immediate Float/Fixnum encoding. The second bug is an unsafe narrowing of a JSON object key length (a size_t) into a signed 16-bit field: a 65,565-byte (0x10000+29) key truncates its stored length to 29, but Oj still allocates and copies the full external buffer while later reading it through the truncated inline view, leaking 8 bytes of a live heap pointer (at inline offsets buf[6]-buf[13]) that GitLab renders into the commit-diff HTML via Ruby's Hash#inspect representation.

Exploitation requires only an ordinary authenticated GitLab user who can push commits and view commit diffs — no administrator rights, CI/CD runner access, or victim interaction. The attacker commits two crafted notebooks in one push: the first (a01.ipynb, with the nested-array and oversized-key payloads) corrupts the parser's start callback pointer and leaks the heap address when its diff is rendered via GET /<project>/-/commit/<sha>/diffs_stream; the leaked pointer is used as a landmark to search a band of page-aligned candidate library bases (probing each with a callback write to candidate_base+0x8470e, a libruby 'eb fe' infinite-jmp gadget, so an incorrect guess hangs the parse and a correct one returns quickly — a process the depthfirst writeup describes taking roughly 5-10 minutes against a fresh worker). Once the libruby/libc bases are resolved, a second notebook (a02.ipynb), processed by the same vulnerable Oj::Parser.usual.parse singleton instance in the same long-lived Puma worker (shared across threads), supplies a NUL-terminated command blob (staged at register R12, max 39 bytes) and drives execution through two libruby gadgets — G1 at libruby+0x269b4a (moves the command blob into RDI and calls the function pointer at offset 0x28) and G2 at libruby+0x22d565 (adjusts the stack for System V ABI compliance) — into a final call to libc's system() at libc+0x58750, executing the attacker-supplied OS command as the git account that owns the Puma worker process. A public, MIT-licensed proof of concept (github.com/wupco/gitlab-rce-demo) demonstrates the full chain end-to-end against GitLab 18.11.3 on x86-64 inside a disposable Docker Compose lab, using a precomputed offset lookup table (table.json) and listener/exploit driver scripts (run_poc.sh, setup_env.sh); per the researcher, retargeting another GitLab build on the same architecture would generally need only minor adjustments to the hardcoded gadget/symbol offsets, not a change to the underlying reachable path.

depthfirst reported the two Oj bugs to the Oj maintainer on 2026-05-21; fixes merged 2026-05-27 and shipped in Oj 3.17.3 on 2026-06-04. depthfirst privately disclosed the full end-to-end GitLab exploit chain on 2026-06-05; GitLab confirmed it on 2026-06-08 and shipped GitLab 18.10.8, 18.11.5, and 19.0.2 (bundling Oj 3.17.3) on 2026-06-10 — notably filed as a bug fix rather than a security advisory, so it does not appear in GitLab's own security release notes. No CVE or CVSS score was requested or assigned to either of the two chained bugs or to the GitLab exploit chain itself; the broader Oj security audit behind this research reportedly triaged 181 candidate vulnerabilities, confirming 77 as memory-safety flaws, of which ten were published as separate GitHub Security Advisories (one on 2026-06-05, nine on 2026-06-16) covering stack/heap buffer overflows, multiple use-after-frees, a negative-size memcpy, and an integer overflow — none of which is the specific write/read primitive used in this GitLab chain. Successful exploitation exposes GitLab repository source code, Rails application secrets, CI/CD and service credentials (personal, project, group, deploy, OAuth, runner, and registry tokens), and any internal service reachable from the git account; there is no public evidence of in-the-wild exploitation and the vulnerability chain is not listed in the CISA KEV catalog as of publication, but the public PoC materially lowers the bar for exploitation of any unpatched self-managed instance.

MITRE ATT&CK techniques used in TL-2026-1715

Collection

T1005 Data from Local System; T1213.003 Code Repositories

Lateral Movement

T1021 Remote Services

Execution

T1059.004 Unix Shell

Privilege Escalation

T1068 Exploitation for Privilege Escalation

Initial Access

T1078 Valid Accounts; T1190 Exploit Public-Facing Application

Discovery

T1082 System Information Discovery

Persistence

T1098 Account Manipulation

Defense Evasion

T1211 Exploitation for Stealth; T1620 Reflective Code Loading

Credential Access

T1528 Steal Application Access Token; T1552 Unsecured Credentials; T1552.001 Credentials In Files

Command and Control

T1571 Non-Standard Port

Resource Development

T1587.004 Exploits; T1588.005 Exploits; T1588.006 Vulnerabilities

Reconnaissance

T1592.002 Software

Affected products and versions in GitLab RCE Chain via Malicious Jupyter Notebooks Exploiting

  • GitLab — GitLab CE/EE
    Vulnerable versions: 15.2.0-18.10.7; 18.11.0-18.11.4; 19.0.0-19.0.1
    Fixed in: 18.10.8; 18.11.5; 19.0.2
  • ohler55 (Oj maintainers) — Oj Ruby gem
    Vulnerable versions: 3.13.0-3.17.1
    Fixed in: 3.17.3

Remediation for GitLab RCE Chain via Malicious Jupyter Notebooks Exploiting

Patches

  • GitLab CE/EE 18.10.8
  • GitLab CE/EE 18.11.5
  • GitLab CE/EE 19.0.2
  • Oj gem 3.17.3

Immediate actions

  • Upgrade all self-managed GitLab CE/EE instances to 18.10.8, 18.11.5, or 19.0.2 or later immediately
  • Verify the actual GitLab application version running inside Puma workers directly (Helm/Operator chart or orchestration version metadata can obscure the real running version)
  • Restrict Jupyter Notebook commit and commit-diff viewing permissions for low-trust or external contributors on any instance that cannot be patched immediately
  • Review accounts with commit/push permissions during the vulnerable window (GitLab 15.2.0 onward) for suspicious .ipynb commits or repeated requests to diffs_stream endpoints

Workarounds

  • Restrict repository push and commit-diff access to trusted users only on unpatched self-managed GitLab instances
  • Alert on unusual process execution, or shell/network utility invocation, as the git OS account originating from Puma worker processes
  • Rotate Rails secrets, application secrets, and personal/project/group/deploy/OAuth/runner/registry/service credentials if compromise is suspected
  • Preserve GitLab Rails, Workhorse, and reverse-proxy logs plus process trees and container state before restarting infrastructure if compromise is suspected

Longer-term hardening

  • Independently upgrade the Oj gem to >=3.17.3 in every Ruby/Rails application that parses untrusted or repository-controlled JSON, not only GitLab
  • Inventory internal Ruby services for native-C-extension JSON/YAML/XML parsers and audit their exposure to attacker-controlled input
  • Add nesting-depth limits, key-length bounds checks, and fuzzing coverage for native JSON parsers as a standing CI regression gate
  • Deploy GitLab with process- and container-level isolation to limit lateral movement and blast radius if the git account is compromised

Weaknesses (CWE) in GitLab RCE Chain via Malicious Jupyter Notebooks Exploiting

CWE-787, CWE-125, CWE-197, CWE-200

Timeline of GitLab RCE Chain via Malicious Jupyter Notebooks Exploiting

  • The vulnerable nesting-stack parsing logic is merged into the Oj Ruby gem, first shipping in Oj 3.13.0.
  • GitLab 15.2.0 switches notebook-diff validation from JSON.parse to Oj::Parser.usual.parse via the ipynbdiff gem, making the Oj bugs reachable through repository-controlled .ipynb diffs.
  • depthfirst reports the two Oj memory-safety vulnerabilities (nesting-stack write and key-length integer truncation) to the Oj maintainer.
  • The Oj maintainer merges fixes for the reported vulnerabilities, 1,753 days after the vulnerable code was first merged.
  • Oj 3.17.3 is published containing the fixes for the exploited nesting-stack and key-length bugs.
  • GHSA-3v45-f3vh-wg7m (Stack Buffer Overflow in Oj.dump via Large Indent) is published, the earliest of ten unrelated Oj security advisories issued from the same broader research effort.
  • depthfirst privately discloses the full end-to-end GitLab RCE exploit chain to GitLab.
  • GitLab confirms the reported vulnerability chain.
  • GitLab ships patched releases 18.10.8, 18.11.5, and 19.0.2 bundling Oj 3.17.3; the fix is filed as a bug fix rather than a security advisory.
  • Nine additional, unrelated Oj memory-safety GitHub Security Advisories from the same research effort are published (buffer overflows, use-after-frees, negative-size memcpy, and an integer overflow), including CVE-2026-54592 (GHSA-3m6q-jj5j-38c9) and CVE-2026-54900 (GHSA-9cv6-qcjw-4grx).
  • The published research discloses that the underlying Oj security audit triaged 181 candidate vulnerabilities and confirmed 77 as memory-safety flaws, of which only the two chained here (nesting-stack write and key-length truncation) were required for the GitLab RCE.
  • depthfirst publishes "Going depthfirst" with full technical analysis and a public MIT-licensed proof-of-concept (wupco/gitlab-rce-demo) demonstrating the chain against GitLab 18.11.3 on x86-64.
  • Security outlets (GBHackers, The Hacker News, Cybersecurity News, Cyber Kendra, threat.wiki) report on the public exploit and patch-without-CVE disclosure.

Sources cited for GitLab RCE Chain via Malicious Jupyter Notebooks Exploiting

Threats related to GitLab RCE Chain via Malicious Jupyter Notebooks Exploiting

Detection coverage for TL-2026-1715

As of 2026-07-27, Threadlinqs Intelligence publishes 9 detection rule(s) for TL-2026-1715 across Splunk SPL, Microsoft KQL and Sigma, covering 27 indicator(s) of compromise. The whole corpus is readable without an account; a free account unlocks full detection query text in Splunk SPL, Microsoft KQL and Sigma; paid tiers add raw indicator values, correlation and the MCP server. Threadlinqs MCP server · View plans.

Threadlinqs Intelligence — Real-Time Threat Detection Platform

[ 0 threats ] [ 0 det ] [ CRIT: 0 ] [ HIGH: 0 ]
// threat_feed
$ sort --newest
Showing all threats

Latest Threats