```html ``` GitLab Fixed This in June and Filed It Under 'Bug Fixes.' A PoC Landed Six Weeks Later. There Is Still No CVE.
top of page

GitLab Fixed This in June and Filed It Under 'Bug Fixes.' A PoC Landed Six Weeks Later. There Is Still No CVE.

  • Writer: Patrick Duggan
    Patrick Duggan
  • 2 hours ago
  • 4 min read

On June 10, GitLab shipped a release. Somewhere in it, under bug fixes, was a change that closed a remote code execution chain.


Not under security fixes. Under bug fixes. No CVE. No CVSS score. No mention of the attack path.


On July 24 — six weeks later — Yuhang Wu at depthfirst published working exploit code for it.



What the exploit does


An ordinary authenticated user commits two crafted Jupyter notebooks to a project they already have access to, then asks GitLab for the diff between them. Rendering that diff runs two chained memory-corruption bugs in the Oj JSON parser, and the attacker gets command execution as the git user.


Read the preconditions, because they are the story:


No administrator rights. No CI or runner access. No interaction from any victim. No access to anybody else's project. Just a normal account on a self-managed instance that has not taken the June 10 update.


An account on a self-managed GitLab is not a high bar. That is every contractor, every intern, every service account, every developer at a company you acquired, and — increasingly — every AI agent you have handed a token to. On many instances, self-registration means it is anyone at all.



The part that should bother you more than the bug


The bug is a memory-safety issue in a JSON parser. Those happen. What is worth arguing about is the label.


A defender's entire triage model runs on vendor severity metadata. You cannot manually read every changelog for every tool in your estate — so you subscribe to security advisories, you feed CVEs into a scanner, you patch on severity. That system is not stupid. It is the only thing that scales.


And that system saw nothing here. There was no CVE to ingest, no CVSS to sort by, no security advisory to alert on. The fix went out labelled as a bug, so to every automated pipeline in the world it was a bug. Anyone deferring a routine version bump for six weeks — which is normal, sane behaviour for a self-hosted developer platform — had no signal telling them this one was different.


Then the PoC dropped and the six-week grace period ended in an afternoon.


This is the same shape we wrote about with Gitea, where a container-registry authorization bypass sat in thirty thousand deployments for roughly four years, and with the GitHub Enterprise semicolon RCE. The developer platform tier keeps producing this pattern: enormous blast radius, deep trust, and disclosure hygiene that does not match the stakes. We have been calling it soft-surface bleed. An unlabelled RCE fix is the purest version of it — the patch existed, the protection existed, and the information did not.


To be clear and fair: GitLab wrote the fix and shipped it. That is the hard part and they did it. The failure is one of classification, not engineering. But classification is how the rest of us find out.



What to do


Check your GitLab version against the June 10 release, today. If you run self-managed and have not applied it — including if you are sitting on 18.11.3 — you are exposed to public exploit code right now. This is not a "next maintenance window" item any more; the PoC is out.


Stop treating "bug fixes" as non-security on developer platforms. For your source-control, CI, and artifact-registry tier specifically, patch current rather than patch-by-severity. The severity metadata on this class of tool has now failed publicly at least three times this year, and those are only the ones somebody bothered to publish a PoC for.


Count the accounts on your instance. Every authenticated user is in the blast radius of this class of bug. If self-registration is on, turn it off. Audit dormant accounts, contractor accounts, and any token you have issued to an automated agent. The preconditions here were "have an account," and most organizations have no idea how many accounts they have.


Watch for what runs as `git`. Command execution as the git user on a GitLab host reaches repositories, hooks, and whatever credentials that account can touch. If you have host-level telemetry, unexpected child processes under that user during diff rendering is the thing to alert on.



The uncomfortable generalization


We do not know how many other unlabelled security fixes are sitting in the changelogs of tools we all run. Structurally, we cannot know — that is what unlabelled means. Every one of them is a PoC away from becoming urgent, and the clock does not start when the vendor commits the fix. It starts when a researcher decides to publish.


Which means the honest defensive posture for the developer-tooling tier is not "patch fast when told." It is patch current, because you will not always be told.


We are 95 percent confident more no-CVE RCE fixes surface in this tier before year end, because nothing about the incentives has changed — a vendor labels conservatively, a researcher publishes on their own schedule, and the gap between those two is the defender's exposure. The remaining five percent is the chance the reaction to this one moves someone's disclosure policy. That would be worth more than the patch.


Credit to Yuhang Wu and depthfirst for the research and for publishing it clearly.


Free IP, domain, hash, and malicious-package blocklists at analytics.dugganusa.com.




Every indicator in this post is in the feed. Free.

1.58M+ IOCs, STIX 2.1 / TAXII, 88% novel vs ThreatFox, exploited-CVE leads ahead of CISA. No credit card — a free API key in 30 seconds, and you can audit every claim above against the live endpoints.


bottom of page