Alpine Linux rebuilds its GitLab after an attacker exploited the GitLab flaw its own Ruby left open
On October 28, 2026, Alpine Linux revealed that an attacker had tried to exploit CVE-2026-97229 (CVSS 10.0) against its own GitLab server, a week after GitLab’s fix. The lesson goes beyond Alpine: for a GitLab install compiled with a homegrown Ruby, upgrading GitLab is not enough — you must upgrade Ruby too.
October 28, 2026. Alpine Linux revealed that an attacker had tried to exploit CVE-2026-97229 — a GitLab flaw rated CVSS 10.0 — against its own GitLab server, a week after the fix was published. The project found no evidence the attack succeeded but cannot rule it out, so it rebuilt the server from scratch and reset every account’s password. The point that matters: the flaw was not in GitLab itself, but in the Ruby that Alpine compiled on its own — and “upgrading GitLab is not enough.”
A critical server and a fix that fixed nothing
The targeted server, gitlab.alpinelinux.org, hosts aports, the repository from which every Alpine Linux package is built. It is a supply-chain node in the strongest sense: compromising it means potentially poisoning the minirootfs files that serve as the base of the official Alpine Docker images, distributed to millions of containers.
CVE-2026-97229 lets an attacker run code on a GitLab server through a crafted regular expression in a CI configuration. The fix GitLab published on October 12 consists of patches applied to the Ruby bundled inside its packages and official images. But Alpine’s GitLab image used a standard Ruby, not GitLab’s: upgrading to GitLab 19.3.6 on October 22 therefore did not close the hole.
That is where the incident becomes a lesson. For anyone running GitLab on their own Ruby — compiled from source or in a custom container image — “upgrading GitLab is not enough,” Alpine writes. Those servers also need Ruby 3.3.13, 3.4.12, 4.0.9 or later. Users of the alpinelinux/gitlab image must re-pull version 19.3.6.
Eight crashes, four attempts halfway through
The timeline Alpine published is precise, which makes it a rare document. On October 13, the project upgraded the server to GitLab 19.3.4 instead of 19.3.5 — a mistake it owns. The server was still on that version, without the October 12 fix, when a newly registered account began probing it on October 20.
That account sent crafted CI configurations on October 20 and 21. They crashed GitLab worker processes eight times. The main attack, on October 21, caused 502 errors and failing CI jobs. In four of those crashes, the attacker got partway through the exploit chain before failing at the next step. One telling detail: the attacker downloaded Alpine’s GitLab container image, which the project says “suggests they were tuning the exploit to our exact build.”
The account was blocked on October 23, then the attacker tried to return on October 25 and 26, without success. On October 26, Alpine found the server was still vulnerable despite the October 22 upgrade. The next day it closed GitLab to everyone except its developers and build servers, and began the rebuild. It finished on October 28, with new secret keys and a server running Ruby 3.3.13 or later.
What Alpine can and cannot rule out
Alpine found no sign that the attacker’s code ran: no abnormal timing-probe delays, no unexpected files, keys, hooks, or processes, no exfiltration visible in web or API requests. But the project refuses to conclude anything from that. “A successful exploit would leave no crash and no trace in the web logs,” it writes. Some logs from the attack day are gone, neither Alpine nor its host logged outbound connections, and the old container’s filesystem no longer exists.
Without proof, Alpine treated the server as compromised and rebuilt it to remove any foothold a successful exploit could have left. If the attack had succeeded, this is what could have been exposed: the email addresses, names, and IP addresses of all users, password hashes, 2FA secrets, CI/CD variables and runner tokens, webhook, integration and push-mirror credentials, personal access tokens (stored as hashes), plus private repositories and confidential issues and merge requests.
The response went beyond the software fix. Alpine confirmed that every aports change added from October 20 to 22 arrived through a recorded push by a known developer, cross-checked against records the attacker could not reach: a developer’s copy of the repository and the 45 build servers. Packages built from October 20 to 24 all come from aports changes consistent with what is published on git.alpinelinux.org. The keys that sign its packages and releases were never on the GitLab server.
The technical root: Onigmo, not GitLab
Why did the GitLab upgrade fix nothing? Because the bug behind CVE-2026-97229 lives in Onigmo, the regular-expression engine built into Ruby. GitLab compiles CI-configuration regexes with Ruby; its October 12 fix therefore patched the Ruby bundled inside its packages and images. Fixed versions of Ruby itself only shipped on October 22 and 23. A GitLab upgrade does not change the host’s Ruby: an install on standard Ruby keeps the flaw until Ruby itself is updated.
Alpine’s criticism is documented and deserves administrators’ attention: as of October 29, neither of GitLab’s patch posts (October 12 and 21) told self-compiled installs to update Ruby. The self-compiled installation guide still lists Ruby 3.2 as its minimum — yet Ruby 3.2 reached end of life in April and will get no fix. That documentation blind spot turns a patched flaw into an open one for a silent minority of deployments.
Who is actually exposed
GitLab.com and GitLab Dedicated are patched. Rapid7 built a working exploit in a lab and published a proof of concept on October 13: it runs commands as the git user on an unpatched GitLab 19.4.1 image, but not on the patched 19.4.2. That exploit needs write access first — committing a malicious .gitlab-ci.yml and a UTF-8 path to a branch of a public project — a condition that disappears on servers where open registration lets anyone create projects. CVE-2026-97229 was still absent from CISA’s KEV catalog as of October 28, meaning it is not (yet) officially recognized as exploited by tracked campaigns.
# GitLab installs on a homegrown Ruby: check the Ruby version, not just GitLab
ruby --version
# The fix requires Ruby 3.3.13, 3.4.12, or 4.0.9 (or later)
# Then upgrade GitLab to a patched branch (e.g. 19.3.6, 19.4.3, 19.5.1) Verdict
If you host GitLab on a Ruby you compiled yourself or in a custom container image, check your Ruby version today: “upgrading GitLab is not enough,” and the window is not theoretical — an attacker already attempted exploitation against the infrastructure of a project as disciplined as Alpine Linux. If you maintain a distribution or a package repository, copy Alpine’s method: keep your signing keys off the forge server and cross-check package provenance against out-of-band records the attacker cannot reach. And if you are simply a consumer of Alpine images or any other distro, the good news is mundane: the signing keys were not exposed and official releases remain intact — the lesson is for maintainers, not package consumers. This incident will stand as a reminder that supply-chain security rests not on the patch you apply, but on the patch you believe you applied.