GitLab Authenticated RCE PoC Enables Command Execution as git User

0
3

Key Takeaways

  • A chained exploit using two crafted Jupyter notebooks can achieve remote code execution as the git user on unpatched self‑managed GitLab instances.
  • The vulnerability stems from bugs in the Oj JSON parser (versions 3.13.0‑3.17.1) that are bundled with GitLab; Oj itself is not a Ruby core component.
  • Affected GitLab releases span Community and Enterprise Editions from 15.2.0 through 18.10.7, 18.11.0‑18.11.4, and 19.0.0‑19.0.1; the first fixed versions are 18.10.8, 18.11.5, and 19.0.2.
  • No administrator privileges, CI runner access, or victim interaction are required; the attack only needs an ordinary authenticated user who can commit notebooks and request a diff.
  • Successful exploitation can leak source code, Rails secrets, service credentials, CI/CD data, and reach internal services, depending on deployment isolation.
  • GitLab.com was patched on June 10, 2026; self‑managed operators must upgrade to a fixed release and verify the Oj version inside the Webservice image (Helm/Operator users should check the container, not just the chart).

Overview of the Vulnerability
Security researcher Yuhang Wu of depthfirst published a working proof‑of‑concept (PoC) that executes arbitrary commands as the git user on an unpatched self‑managed GitLab 18.11.3 server. The attack does not require administrative rights, access to a CI runner, or any interaction from the victim; an ordinary authenticated user can trigger it by committing two specially crafted Jupyter notebooks and then requesting their diff. The exploit is specific to the x86‑64 build of GitLab 18.11.3, but the underlying Oj parser bugs affect a broader range of releases.

How the Exploit is Triggered
The attacker creates two notebook files (.ipynb JSON) that contain deeply nested arrays and a malformed key field. When GitLab renders a diff of these notebooks, it passes the repository‑controlled JSON to Oj::Parser.usual.parse inside a long‑lived Puma worker. The first notebook triggers a parse error that GitLab catches, leaving the parser’s internal state corrupted but the worker alive. The second notebook is then parsed in the same worker, causing the corrupted state to be dereferenced and leading to a controlled call to system(). Because the two notebooks are processed in a single diffs_stream request, the same Oj parser instance is reused, which is essential for chaining the two bugs.

Affected GitLab Versions and Patch Timeline
The vulnerable Oj versions (3.13.0‑3.17.1) are shipped with GitLab Community Edition (CE) and Enterprise Edition (EE) releases ranging from 15.2.0 through 18.10.7, 18.11.0‑18.11.4, and 19.0.0‑19.0.1. The first patched GitLab releases that include the fixed Oj 3.17.3 are 18.10.8, 18.11.5, and 19.0.2, all made available on June 10, 2026. GitLab.com was updated on that date, but self‑managed installations remain exposed until operators upgrade. depthfirst reported the Oj bugs to the maintainer on May 21, 2026; the fixes were merged on May 27 and released as Oj 3.17.3 on June 4. The GitLab chain was reported on June 5, confirmed by GitLab on June 8, and the public advisory followed on July 24, 2026.

Role of the Oj JSON Parser
Oj is a high‑performance JSON parser for Ruby that contains a substantial amount of native C code. In GitLab’s notebook renderer, the parser is invoked per request within a Puma worker that lives for the lifetime of the worker process. The parser maintains a fixed‑size 1,024‑byte stack to track nesting depth while parsing JSON arrays. Because Oj does not validate whether the nesting depth exceeds this buffer, a deeply nested array can write past the end of the stack, overwriting adjacent parser fields. This overflow permits an attacker to corrupt a callback pointer (buf.head) and later leak a heap address via a manipulated key‑allocation length field.

Technical Details of the Two‑Bug Chain
The first bug is an out‑of‑bounds write that lets the attacker overwrite buf.head, a pointer used by Oj when reallocating its internal buffer. By crafting a JSON payload that forces Oj to treat the overwritten pointer as a valid memory address, the attacker causes a subsequent realloc() call to return a pointer under their control. The second bug abuses Oj’s handling of object keys: it allocates a 65,565‑byte object, truncates its length to a signed 16‑bit field (yielding 29), and returns those 29 bytes—which contain a live pointer to the original key allocation—back to the caller. GitLab forwards this pointer into the rendered notebook diff, giving the attacker an address leak that narrows the ASLR search space. On a typical two‑worker GitLab 18.11.3 host, the brute‑force search for the correct address takes five to ten minutes; across the widest range of mature workers the researchers estimated one to two hours. Once the address is known, the corrupted callback pointer is invoked during the second notebook’s parse, leading to a build‑specific gadget chain that calls system() and executes attacker‑supplied commands as the git user.

Potential Impact and Data at Risk
Because the exploit runs with the privileges of the GitLab git user, an attacker can read or modify any data accessible to that user. This includes the source code of all repositories hosted on the instance, Rails secret keys used for session signing and encryption, service credentials stored in environment variables or configuration files, CI/CD job logs and artifacts, and any internal services reachable from the GitLab application process (e.g., PostgreSQL, Redis, or internal APIs). The extent of the impact depends on how tightly the GitLab deployment is isolated; in a typical deployment where the git user has broad filesystem and network access, the breach could lead to full compromise of the codebase and supply‑chain poisoning.

Disclosure, Patch Release and CVE Situation
depthfirst disclosed the Oj bugs to the maintainer on May 21, 2026, and the fixes were merged on May 27, with Oj 3.17.3 released on June 4. The GitLab exploit chain was reported on June 5, confirmed by GitLab on June 8, and the patched GitLab versions (18.10.8, 18.11.5, 19.0.2) were released on June 10. Notably, neither the depthfirst advisory nor GitLab’s June 10 release notes assigned CVE identifiers or CVSS scores to the two chain bugs, and no temporary workaround was provided—both parties advise self‑managed operators to upgrade. The Hacker News has contacted GitLab for clarification on CVE status and exploitation evidence, and has asked depthfirst about exploit portability and possible mitigations; responses are pending. depthfirst also noted that it discovered nine additional CVEs for other Oj flaws during the same review.

Guidance for Administrators and Mitigation Steps
Self‑managed GitLab operators should immediately upgrade to a fixed release (18.10.8, 18.11.5, 19.0.2, or newer). Because the vulnerability resides in the Oj library bundled with GitLab, simply updating the Helm chart or Operator version is insufficient; administrators must verify that the Webservice container image contains the patched Oj version (3.17.3 or later). For installations using custom images, rebuild the image with the updated Oj gem. If an immediate upgrade is not feasible, the only reliable mitigation is to restrict the ability of untrusted users to create or modify Jupyter notebooks in repositories, though this does not address the underlying parser flaw. Monitoring for unexpected git‑user processes or outbound connections can help detect active exploitation. Finally, organizations should review their internal network segmentation to limit what the git user can reach, thereby reducing the potential impact of a successful breach.

SignUpSignUp form

LEAVE A REPLY

Please enter your comment!
Please enter your name here