Back to blog
GitLabOjRCEJupytercorrectif silencieuxagents IA

GitLab RCE via Oj: Notebook Chain, Silent Fix

Published on 2026-07-25 · Updated on 2026-10-294 min read
In short: A chain of two memory corruption bugs in Oj, a Ruby JSON parser, lets any authenticated user who can push to a project run commands as the git user on an unpatched self-managed GitLab. Fixed versions: 18.10.8, 18.11.5 and 19.0.2. The June 10, 2026 fix was not presented as a security fix and no CVE is assigned. depthfirst published a working exploit on July 24, 2026.

What does this GitLab chain allow?

According to depthfirst and The Hacker News, GitLab's Jupyter notebook rendering engine (ipynbdiff) passes the JSON of a repository-controlled .ipynb file to Oj::Parser.usual.parse, inside a long-lived Puma worker. Two Oj bugs chain together: an overflow of a fixed-size nesting stack that ends up controlling the parser's start callback, and a truncation of a very long object key into a signed 16-bit field, which returns a live heap pointer rendered in the diff display. After several attempts to locate the C library in memory, additional notebooks trigger command execution.

No administrator rights are needed, nor CI or runner access, victim interaction or access to another user's project: push rights and viewing a commit diff are enough.

Which versions are affected?

All GitLab CE and EE editions:

  • 15.2.0 to 18.10.7, fixed in 18.10.8;
  • 18.11.0 to 18.11.4, fixed in 18.11.5;
  • 19.0.0 to 19.0.1, fixed in 19.0.2.

The Oj gem is affected from 3.13.0 to 3.17.1 and fixed in 3.17.3 (3.17.2 does not contain both fixes). GitLab 15.1 and earlier used JSON.parse on this path and are outside the chain. GitLab.com was already patched and Dedicated customers had no action to take. Versions 15.2 to 18.9 get no backport: they must move to a supported version.

With Helm or the Operator, check the GitLab version in the Webservice image running Puma, not the chart's.

Why did the fix go unnoticed?

The timeline published by depthfirst: report to Oj on May 21, 2026, fixes merged on May 27, Oj 3.17.3 published on June 4, report to GitLab on June 5, confirmation on June 8, GitLab fixes on June 10. Yet the Oj version bump sat in the bug fixes section of the June 10 release, with no CVE or score, and the notes do not mention the chain. Teams that triage updates from the security fixes table had no urgency signal; the public exploit arrived six weeks later.

How do you detect exposure or exploitation?

  1. Read the GitLab version (interface footer or gitlab-rake gitlab:env:info) and compare it with the fixed versions.
  2. Audit who can push to your projects, in particular external contributors and service accounts.
  3. Search access logs for views of notebook diffs and unusual commits, and for Puma worker restarts: the memory search phase takes several minutes and leaves traces.
  4. Look for commands run as the git user: unexpected child processes of the worker, outbound connections, new files.

How do you fix it?

Move to 18.10.8, 18.11.5 or 19.0.2. GitLab and depthfirst offer no validated workaround for operators who cannot update. Until you are up to date, tighten push rights. If exposure is plausible, treat the instance's secrets as exposed: CI/CD variables, deploy keys, runner registration tokens, Rails secrets and service credentials, then rotate them.

What changes when an AI agent has access to GitLab?

The chain's prerequisite is "an authenticated user who can push." Coding agents increasingly have that right: an agent opens branches, pushes commits, adds notebooks and data files, sometimes from a service account. If that account is hijacked by a prompt injection (OWASP LLM01) in an issue, a merge request or a file it reads, the attacker obtains the only prerequisite needed. The agent itself may push the booby-trapped file, with no human reviewing a JSON notebook.

GitLab is also where secrets concentrate: CI/CD variables, deploy keys, API tokens. Code execution on the instance hands them to the attacker, and so hands over the tools CI agents are connected to (LLM02, LLM06). See the neighboring case Azure DevOps MCP and PR comment hijacking and MCP security.

The governance gap transposes too: a dependency update bot or an agent that triages release notes applies upgrades based on the "security" label. Here that label was missing. Treat updates to sensitive parsers (JSON, XML, images) as security fixes, even without a CVE. Useful agent-side controls: push rights limited to working branches, protected main branches, mandatory human review of binary or structured files, secrets kept out of the agent's reach, and human approval of merges. On the GitLab Oj chain, see also AI agent security.

How do you triage updates that have no CVE?

Add a simple rule to your process: any version bump of a library that parses untrusted data (JSON, XML, YAML, images, archives, PDF) is reviewed as a potential security fix. Read the dependency's changelog and linked tickets, not only the vendor's security table. When a critical component such as GitLab embeds the dependency, also follow its bug-fix releases on maintained trains, and set a maximum delay between a release and its deployment. An automated dependency bot can open the pull request, but a person must still decide what counts as urgent.

What should you check on an agent with the GitLab Oj chain?

An agent red team places a booby-trapped instruction in an issue or a file the coding agent reads, and observes what it pushes, with which rights and which secrets it sees. On the offer side, the Agent Red Team Express looks at whether a booby-trapped notebook can lead a GitLab agent to code execution (5 days, 1,900 euros). The method details the approach.

What is the lesson?

Not every security fix is announced as one. Triage version bumps of components that parse untrusted data as security fixes, and treat every account able to push code, human or agent, as an entry point.

Does your product ship an AI agent? CleanIssue tests what a stranger can make it do with the Agent Red Team Express (5 days, €1,900), or a custom red team for several agents and MCP servers. First step: a free 30-minute discovery call.

Know what your agent can do before an attacker does.

A free 30-minute discovery call: you describe your agent, I tell you what I would test and what it costs. Five case studies are published.

Book a call