Skip to main content

They Patched GitLab. The Bug Stayed.

Alpine Linux did the responsible thing — it upgraded on time — and stayed vulnerable for four more days. The fix was never in GitLab's code at all.

Updated 6 min readMarkdown
They Patched GitLab. The Bug Stayed.

On 20 October, a brand-new account signed up to Alpine Linux's GitLab server and started probing it. Then the crafted CI configurations arrived, and GitLab's worker processes started crashing. Eight times.

In four of those crashes, Alpine says, the attacker got partway through the exploit and failed at the next step. Partway. That word does a lot of work in this story. It means the attack was not a theoretical paper exercise. It was close enough that Alpine could watch it climb the stairs and stop, one step short of the room it wanted.

The flaw was CVE-2026-97229, scored a full 10.0. In plain words: a specially built regular expression — a pattern-matching rule — tucked into a CI configuration could let someone with no special privileges run code on the GitLab server. The bug itself lived in Onigmo, the regular-expression engine inside Ruby, the language GitLab is built on. GitLab had published fixed releases on 12 October.

Alpine had almost done everything right. On 13 October it upgraded — to 19.3.4 instead of 19.3.5, the release that carried the fix. A one-digit mistake, the kind anyone running infrastructure at midnight recognises. That was the open door the attacker walked up to a week later.

Here is where the story stops being a normal patching tale and turns into something worth remembering.

On 22 October, Alpine upgraded again, to 19.3.6, the newest release. Job done, ticket closed — or so it seemed. The server stayed vulnerable, and nobody knew it for four more days.

The reason is simple. GitLab's fix was not a change to GitLab's own code. It was a patch to the Ruby that GitLab bundles inside its official packages and container images. Alpine's image did not use that bundled Ruby; it used standard Ruby, installed separately. So upgrading GitLab changed everything except the one component that was actually broken — like replacing a door lock while the faulty hinge is what lets someone in.

Alpine found the truth on 26 October: still vulnerable, after the upgrade. The next day it closed GitLab to everyone except its developers and build servers and started again from scratch. The rebuild finished on 28 October. Every password was reset. GitLab's secret keys were replaced. The rebuilt server runs Ruby 3.3.13 or later, which carries the fix — upstream Ruby shipped its own fixed versions, 3.3.13, 3.4.12 and 4.0.9, on 23 October.

And here is the part Alpine refuses to soften. It found no evidence the attacker actually ran code on the server — and it cannot rule it out. A successful exploit would leave no crash and no trace in the web logs, and some logs from the attack days are gone, including background-job logs and the old container's filesystem. There was no logging of outbound connections either. So Alpine treated the server as compromised and rebuilt it anyway. When you cannot prove you are clean, you act as if you are not.

What could have been exposed is a sobering list, published by Alpine: users' emails, names and IP addresses, password hashes, two-factor secrets, CI/CD variables and runner tokens, webhook credentials, personal access tokens, private repositories, confidential issues and merge requests. Not just one server — the keys to a whole ecosystem of builds.

The good news, verified the hard way, is narrower than it sounds. Alpine checked its package repository and 21 October releases against records the attacker could not reach — a developer's clone, all 45 builders — and found no sign of tampering. The keys that sign Alpine's packages and releases were never stored on the GitLab server at all. That separation, decided long before anyone attacked, is what kept a close call from becoming a supply-chain disaster.

On 29 October, CISA added CVE-2026-97229 to its Known Exploited Vulnerabilities catalogue, with a 1 November deadline for US federal agencies — a formal way of saying this is not a hypothetical bug anymore. But the lesson here is not "patch faster," though Alpine now plans to apply critical GitLab releases within a day. It is more specific, and more uncomfortable.

Patching is not the same as verifying. When you upgrade a product, ask what actually changed inside it. Did the fix live in the application, or in a library, a runtime, a bundled component your own build replaces with something else? If you build from source or maintain your own container image, the vendor's patched package may never reach your vulnerable part. Alpine's warning is blunt: upgrading GitLab is not enough. You also need the fixed Ruby.

There is a second lesson, about evidence. Alpine is now keeping logs longer, recording outbound connections, and moving to signed release tags so releases can be verified independently of GitLab. Those are the changes you make after learning that "we found no evidence" and "we are sure" are two very different sentences — and in incident response, the gap between them is where the real risk lives.

So check your stack, not just your app. If you run GitLab on your own Ruby, make sure that Ruby is 3.3.13, 3.4.12, 4.0.9 or later. If you use Alpine's container image, pull 19.3.6 again — only the image published on 27 October carries the fixed Ruby. And if you ever find yourself saying "but we patched," pause, and ask the question Alpine learned to ask four days late: patched what, exactly?

Sources: Alpine Linux, "GitLab security incident: attempted exploitation of CVE-2026-97229" (28 October 2026) — https://alpinelinux.org/posts/GitLab-security-incident-CVE-2026-97229.html ; The Hacker News, "Attacker Tried to Exploit Alpine Linux's GitLab via CVSS 10.0 Flaw Its Ruby Left Open" — https://thehackernews.com/2026/10/attacker-tried-to-exploit-alpine-linuxs.html ; CISA Known Exploited Vulnerabilities catalogue entry for CVE-2026-97229, added 29 October 2026 (reported by multiple outlets; due date 1 November 2026 for US federal agencies).

What is confirmed, and what is not: The attack attempts, the eight crashes, the failed upgrade, the rebuild, the password reset and the key replacement are all from Alpine's own post-mortem. Whether the attacker ever ran code is explicitly unproven either way — Alpine says no evidence of success, but it cannot be ruled out. No tampering with Alpine packages or releases was found. No victim count beyond the server's user base is claimed, because Alpine does not give one.

No comments yet. Be the first to comment.