{"id":2004,"date":"2026-07-25T08:54:44","date_gmt":"2026-07-25T08:54:44","guid":{"rendered":"https:\/\/thedigitalfortress.us\/?p=2004"},"modified":"2026-07-25T08:54:44","modified_gmt":"2026-07-25T08:54:44","slug":"researcher-publishes-gitlab-rce-poc-letting-authenticated-users-run-commands-as-git","status":"publish","type":"post","link":"https:\/\/thedigitalfortress.us\/?p=2004","title":{"rendered":"Researcher Publishes GitLab RCE PoC Letting Authenticated Users Run Commands as Git"},"content":{"rendered":"<div>\n<p><span class=\"p-author\"><i class=\"icon-font icon-user\">\ue804<\/i><span class=\"author\">Swati Khandelwal<\/span><i class=\"icon-font icon-calendar\">\ue802<\/i><span class=\"author\">Jul 25, 2026<\/span><\/span><span class=\"p-tags\">Vulnerability \/ Application Security<\/span><\/p>\n<\/div>\n<div id=\"articlebody\">\n<div class=\"separator\" style=\"clear: both;\"><a href=\"https:\/\/blogger.googleusercontent.com\/img\/b\/R29vZ2xl\/AVvXsEgRIN1sheAdScq7AX9pLc07esRzQ18-0vBJ7hz9DlVhggVAImXrhYM_zxN0N6hJ2inDkBCnzRCXHR3Kv3I0QwyiVWkAMu7p949JSjgK611r48deMbrSN8iDD78aJdfxEeO_Jy6JFwOfPL_8M0RKEBl1RFO7ufvop1XG9-tdms7VRyvONXoteuCYp9Rg-FM\/s1700-e365\/gitlab.gif\" style=\"display: block;  text-align: center; clear: left; float: left;\"><\/a><\/div>\n<p>Security researcher Yuhang Wu at depthfirst has published a working proof-of-concept (PoC) exploit that executes commands as <code>git<\/code> on an unpatched self-managed GitLab <code>18.11.3<\/code> server.<\/p>\n<p>An ordinary authenticated user triggers it by committing two crafted Jupyter notebooks and requesting their diff. The chain needs no administrator rights, continuous integration (CI) runner access, victim interaction, or access to another user&#8217;s project.<\/p>\n<p>The public exploit is build-specific to GitLab <code>18.11.3<\/code> on x86-64; the underlying Oj bugs affect broader releases. The affected ranges are GitLab Community Edition (CE) and Enterprise Edition (EE) <code>15.2.0<\/code> through <code>18.10.7<\/code>, <code>18.11.0<\/code> through <code>18.11.4<\/code>, and <code>19.0.0<\/code> through <code>19.0.1<\/code>.<\/p>\n<p>The first fixed releases are <code>18.10.8<\/code>, <code>18.11.5<\/code>, and <code>19.0.2<\/code>. Oj is a high-performance JSON parser for Ruby with substantial native C code.<\/p>\n<p>Published gems <code>3.13.0<\/code> through <code>3.17.1<\/code> are vulnerable; <code>3.17.3<\/code> is the first published release containing both fixes. The flaws affect Free, Premium, and Ultimate. Ruby itself is not affected.<\/p>\n<div class=\"dog_two clear\">\n<div class=\"cf\"><a href=\"https:\/\/thehackernews.uk\/ai-vuln-protection-d\" rel=\"nofollow noopener sponsored\" target=\"_blank\"><img loading=\"lazy\" decoding=\"async\" class=\"lazyload\" alt=\"Cybersecurity\" src=\"https:\/\/blogger.googleusercontent.com\/img\/b\/R29vZ2xl\/AVvXsEjQl2axNwsfhbXOFynrg_uAZsvHi3OvNGSA8KJO-BKR8Xm3x7yjKV3EvfY4v5mwXx6LF0uWFb9h9d9iAV_Pi-YYhqimX9wx4OaLdDJEdR215Xrxq_PAtXkaLfQso4pTSjbj6fvh_ZTliLpzWZSZfcoZgyXtKwhN-SSDDlmbtUqGLshc0KqYQGWYHMN52Sl1\/s728-e100\/zz-d.jpg\" width=\"729\" height=\"91\"\/><\/a><\/div>\n<\/div>\n<p>Successful exploitation runs as <code>git<\/code>. Its effective reach depends on deployment isolation, but may include source code, Rails secrets, service credentials, CI\/CD data, and internal services reachable from the application. GitLab.com was patched by June 10.<\/p>\n<p><a name=\"more\"\/><\/p>\n<p>Dedicated customers need no action. Self-managed operators should move to a supported release containing the fix. Helm and Operator users need to check the GitLab version inside the Webservice image, not only the chart or Operator version. depthfirst said it was unaware of in-the-wild exploitation as of July 24.<\/p>\n<p>Neither the <a href=\"https:\/\/depthfirst.com\/gitlab-rce-oj-spill\" target=\"_blank\">depthfirst disclosure<\/a> nor GitLab&#8217;s June 10 release notes list CVE identifiers or CVSS scores for the two chain bugs. Neither provides a temporary workaround; both direct self-managed operators to upgrade.<\/p>\n<p>The Hacker News has asked GitLab about CVE status, classification, and exploitation evidence. It also asked depthfirst about exploit portability and whether a supported temporary mitigation exists. Responses are pending. depthfirst lists nine CVEs for other Oj flaws found in the same review.<\/p>\n<div class=\"separator\" style=\"clear: both;\"><a href=\"https:\/\/blogger.googleusercontent.com\/img\/b\/R29vZ2xl\/AVvXsEiiKTyaaLkhwstQr3NKKNz65EvIXQgyvfFLQ-FJU7bXyQu8z40Wjm_CNFPnYSNqUOqYXgT0ClkMj-FG-E1KYhlD5y0NOUUTo8Z3s7YECp1045Gm3MqxsXVckEbtGCAw_94koZXNPhNmlz6aQ5VTTTxfpNMIai4APKbZNYUQrsQpXdLvdoosjhWRauoy1GQ\/s1700-e365\/git-exploited.png\" style=\"display: block;  text-align: center; clear: left; float: left;\"><img decoding=\"async\" src=\"https:\/\/blogger.googleusercontent.com\/img\/b\/R29vZ2xl\/AVvXsEiiKTyaaLkhwstQr3NKKNz65EvIXQgyvfFLQ-FJU7bXyQu8z40Wjm_CNFPnYSNqUOqYXgT0ClkMj-FG-E1KYhlD5y0NOUUTo8Z3s7YECp1045Gm3MqxsXVckEbtGCAw_94koZXNPhNmlz6aQ5VTTTxfpNMIai4APKbZNYUQrsQpXdLvdoosjhWRauoy1GQ\/s1700-e365\/git-exploited.png\" alt=\"\" border=\"0\" data-original-height=\"1570\" data-original-width=\"3016\"\/><\/a><\/div>\n<p>GitLab&#8217;s notebook renderer passes repository-controlled <code>.ipynb<\/code> JSON to <code>Oj::Parser.usual.parse<\/code> inside a long-lived Puma worker. That sends attacker-controlled notebook data into Oj&#8217;s native parser state inside GitLab&#8217;s application process.<\/p>\n<p>depthfirst&#8217;s <a href=\"https:\/\/depthfirst.com\/research\/going-depthfirst-achieving-gitlab-rce-via-two-ruby-memory-corruption-vulnerabilities\" target=\"_blank\">technical analysis<\/a> shows how one bug controls a callback pointer, while the other leaks a heap address needed to narrow the address space layout randomization (ASLR) search.<\/p>\n<p>Oj stores nesting state in a fixed 1,024-byte stack but never checks whether the depth exceeds it. Deeply nested arrays can therefore write <code>0x01<\/code> bytes into adjacent parser state. The exploit corrupts <code>buf.head<\/code>, causing Oj to pass a forged interior pointer to <code>realloc()<\/code>. A later Ruby Array allocation reclaims the same 3,584-byte jemalloc region and overwrites <code>p-&gt;start<\/code>.<\/p>\n<p>Oj allocates a 65,565-byte object key, truncates its length to 29 in a signed 16-bit field, and returns 29 bytes containing the live key-allocation pointer. GitLab carries that pointer into the rendered notebook diff, giving the exploit the address leak needed to narrow the ASLR search. On the profiled two-worker GitLab <code>18.11.3<\/code> installation, the search usually took five to ten minutes. The researchers projected one to two hours across the widest mature-worker range.<\/p>\n<div class=\"dog_two clear\">\n<div class=\"cf\"><a href=\"https:\/\/thn.news\/sygnia-webinar\" rel=\"nofollow noopener sponsored\" target=\"_blank\"><img loading=\"lazy\" decoding=\"async\" class=\"lazyload\" alt=\"Cybersecurity\" src=\"https:\/\/blogger.googleusercontent.com\/img\/b\/R29vZ2xl\/AVvXsEhrEy9jEFSadp95ztaH87-97Z_U9V94nUsE-BsrdwSR8ETPJDyCjy63vNxc-O26z6VhA3nDOrU24lJqNdy24bfNxGPxGxXNRvM_XCwnZ7ukY5wDnXKsvDZN42aCT1JFYXZZGoZFEtSQgbba742oPTEgEbtoa0GBYWWkkkU43P1wPq-LByZPJfbzwZsb1RiI\/s728-e100\/sygnia-d-1.png\" width=\"729\" height=\"91\"\/><\/a><\/div>\n<\/div>\n<p>Two lexically ordered notebook files in one <code>diffs_stream<\/code> request keep both stages inside the same Puma worker, which reuses the process-global Oj parser. The first file corrupts the callback and raises an error that GitLab catches before continuing the diff. The next parse invokes the overwritten pointer and reaches <code>system()<\/code> through a build-specific gadget sequence.<\/p>\n<p>The <a href=\"https:\/\/github.com\/wupco\/gitlab-rce-demo\/tree\/main\" target=\"_blank\">public demonstration<\/a> packages the chain in a local GitLab <code>18.11.3<\/code> x86-64 lab and makes the Puma worker connect back as <code>git<\/code>.<\/p>\n<p>depthfirst reported the Oj bugs on May 21, and the maintainer <a href=\"https:\/\/github.com\/ohler55\/oj\/pull\/1014\" target=\"_blank\">merged the fixes<\/a> on May 27. <a href=\"https:\/\/github.com\/ohler55\/oj\/releases\/tag\/v3.17.3\" target=\"_blank\">Oj <code>3.17.3<\/code><\/a> shipped on June 4. The researchers reported the GitLab chain on June 5; depthfirst said GitLab confirmed it on June 8.<\/p>\n<p>GitLab <a href=\"https:\/\/docs.gitlab.com\/releases\/patches\/patch-release-gitlab-19-0-2-released\/\" target=\"_blank\">released the fixed versions<\/a> on June 10 and resolved the report on July 17, according to depthfirst. A review by The Hacker News found GitLab listed the Oj <code>3.17.3<\/code> bump under bug fixes rather than in the security-fix table and did not describe the notebook-diff RCE chain.<\/p>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>\ue804Swati Khandelwal\ue802Jul 25, 2026Vulnerability \/ Application Security Security researcher Yuhang Wu at depthfirst has published a working proof-of-concept (PoC) exploit that executes commands as git on an unpatched self-managed GitLab&hellip;<\/p>\n","protected":false},"author":1,"featured_media":2005,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[1831,195,1462,2717,2101,1730,2716,316,1824,1774,826],"class_list":["post-2004","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-authenticated","tag-commands","tag-git","tag-gitlab","tag-letting","tag-poc","tag-publishes","tag-rce","tag-researcher","tag-run","tag-users"],"_links":{"self":[{"href":"https:\/\/thedigitalfortress.us\/index.php?rest_route=\/wp\/v2\/posts\/2004","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/thedigitalfortress.us\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/thedigitalfortress.us\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/thedigitalfortress.us\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/thedigitalfortress.us\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2004"}],"version-history":[{"count":0,"href":"https:\/\/thedigitalfortress.us\/index.php?rest_route=\/wp\/v2\/posts\/2004\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/thedigitalfortress.us\/index.php?rest_route=\/wp\/v2\/media\/2005"}],"wp:attachment":[{"href":"https:\/\/thedigitalfortress.us\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2004"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/thedigitalfortress.us\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2004"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/thedigitalfortress.us\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2004"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}