
An attacker tried to exploit a critical GitLab vulnerability on the Alpine Linux project's own GitLab server a week after GitLab released a fix, Alpine Linux said on 28 October.
The flaw, CVE-2026-97229 (CVSS score: 10.0), can let an attacker run code on a GitLab server through a crafted regular expression in a CI configuration. Alpine found no evidence that the attack worked but cannot rule it out, so it rebuilt the server from scratch and reset every account's password.
GitLab's fix is a set of patches to the Ruby that GitLab ships in its own packages and container images. Alpine's GitLab image used standard Ruby, so upgrading the server to GitLab 19.3.6 on 22 October did not fix the flaw.
For anyone running GitLab on their own Ruby, built from source or in their own container image, "upgrading GitLab is not enough," Alpine said. Those servers also need Ruby 3.3.13, 3.4.12, 4.0.9 or later, and users of Alpine's alpinelinux/gitlab image need to pull 19.3.6 again.
The server gitlab.alpinelinux.org hosts aports, the repository from which Alpine's packages are built. Packages built from 20 to 24 October, and the 21 October releases, came from aports changes verified against records outside GitLab, according to Alpine.
Those releases include the minirootfs files that the official Alpine Docker images are built from. Alpine is extending the checks to 27 October, when it closed the server. The keys that sign its packages and releases have never been on the GitLab server.
How the Attack Unfolded
On 13 October, Alpine upgraded the server to GitLab 19.3.4 instead of 19.3.5, which it calls a mistake. The server was still on that version, without the 12 October fix, when a newly registered account began probing it on 20 October.
The account sent crafted CI configurations to the server on 20 and 21 October. They crashed GitLab worker processes 8 times, and the main attack on 21 October also caused 502 errors and caused CI jobs to fail.
In 4 of those crashes, the attacker got partway through the exploit and failed at the next step, according to Alpine. The attacker also downloaded Alpine's GitLab container image, which Alpine said: "suggests they were tuning the exploit to our exact build."
Alpine blocked the account on 23 October. The attacker came back on 25 and 26 October and tried to get back in, but those attempts failed, Alpine said.
On 26 October, Alpine found that the server was still vulnerable after its 22 October upgrade to 19.3.6. The next day, it closed GitLab to everyone except its developers and build servers and started rebuilding it.
The rebuild finished on 28 October. Alpine also replaced GitLab's secret keys, and the rebuilt server runs Ruby 3.3.13 or later, which has the fix. Alpine is testing it before reopening it to the public.
What Alpine Can and Cannot Rule Out
Alpine found no sign that the attacker's code ran on the server. Timing probes showed no delays;; there were no unexpected files, keys, hooks, or processes; and no private data was sent back to the attacker via any web or API request that Alpine can see.
It cannot be sure, though. "A successful exploit would leave no crash and no trace in the web logs," Alpine said. Some logs from the attack day are gone, including background job logs and the old container's filesystem, and neither Alpine nor its hosting provider logged outbound network connections.
Because the evidence needed to confirm code execution no longer exists, Alpine treated the server as compromised and rebuilt it to remove any foothold a successful exploit could have left.
If the attack succeeded, these could have been exposed:
- 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, which are stored as hashes
- Private repositories, and confidential issues and merge requests
Beyond the password reset and the new secret keys, Alpine has not said whether runner tokens, CI/CD variables, access tokens or integration credentials stored on the server have been replaced.
To check its packages, Alpine confirmed that every aports change added from 20 to 22 October arrived through a recorded push by a known developer. It checked this against records it says the attacker could not reach: a developer's copy of the repository and all 45 build servers. Every package built from 20 to 24 October came from aports changes as published on git.alpinelinux.org.
Why the GitLab Upgrade Did Not Fix It
GitLab compiles the regular expressions in CI configurations with Ruby, and the bug behind CVE-2026-97229 is in Onigmo, the regular expression engine built into Ruby.
GitLab's 12 October release fixed it by patching the Ruby inside GitLab's Linux package and container images. Ruby's own fixed versions came out on 22 and 23 October.
A GitLab upgrade does not change a server's own Ruby, so a GitLab install on standard Ruby keeps the flaw until Ruby itself is updated to a fixed version, as Alpine found.
GitLab's fixed Linux packages and its official container images carry the patched Ruby. A self-compiled install, or a container image that installs Ruby separately as Alpine's did, does not get it.
As of 29 October, neither of GitLab's patch release posts for 12 and 21 October tells administrators of self-compiled installs to update Ruby. GitLab's self-compiled installation guide still lists Ruby 3.2 as its minimum version, and Ruby 3.2 reached end of life in April and will get no fix.
Which GitLab Servers Are Exposed
GitLab's advisory says that, "under certain conditions," the flaw could have allowed an unauthenticated user to run code on the server. GitLab.com and GitLab Dedicated are already patched.
Rapid7 built a working exploit in a lab and published proof-of-concept code on 13 October. The exploit ran commands as GitLab's git user on an unpatched official GitLab 19.4.1 image, but the same input did not run on the patched 19.4.2 image.
That exploit needs write access first: the attacker must commit a malicious .gitlab-ci.yml file and a file path with UTF-8 characters to a branch of a public project. That requirement does not apply on servers where new users can register themselves and create projects.
In Rapid7's tested route, "only the final CI lint request is unauthenticated." GitLab's own detection notes also say the attacker must first create that file path through ordinary repository APIs. Rapid7 does not yet know how the attack in the original report to GitLab, which is still private, avoids the write step.
Alpine has not said how its attacker's CI configurations reached GitLab, or whether new accounts could create public projects on its server.
CVE-2026-97229 was not in CISA's Known Exploited Vulnerabilities catalog as of the catalog's 28 October update.
What GitLab Administrators Should Do
GitLab's 21 October releases are the newest on each branch listed below, and they also fix CVE-2026-110264, a separate regex flaw.
| Branch | Fixes CVE-2026-97229, per GitLab's advisory | Newest release (21 October) |
|---|---|---|
| 19.5 | Not listed as affected | 19.5.1 |
| 19.4 | 19.4.2 | 19.4.3 |
| 19.3 | 19.3.5 | 19.3.6 |
| 19.2 | 19.2.8 | 19.2.9 |
| 19.1, 19.0 and 18.11 | Not listed as affected | 19.1.9, 19.0.10 and 18.11.13 |
Which release fixes a server depends on how GitLab is installed:
- GitLab's Linux package or official container images: upgrade to the newest release for your branch.
- Self-compiled installs, or images that install their own Ruby: upgrade GitLab and update Ruby to 3.3.13, 3.4.12, 4.0.9, or later. Ruby 3.2 will not receive the fix, so servers running 3.2 need to upgrade to one of those versions.
GitLab's advisory named 19.3.4 as the fixed version for the 19.3 branch when it was published on 12 October. It now names 19.3.5 and lists 19.3.4 as affected, so servers still on 19.3.4 should move to 19.3.6.
If a server cannot be upgraded right away, Rapid7 suggests restricting anonymous access to public projects, stopping untrusted users from creating or writing to public projects, or blocking the CI lint route. Those steps cover only Rapid7's exploit route and do not fix the vulnerable regular expression compiler, the company said.
GitLab has published six detection rules for exploitation attempts against self-managed servers, written in the Sigma format. Four of them, which GitLab marks as experimental, look for hostile patterns in CI regexp warnings and GraphQL ciLint requests, unusually long file paths with non-ASCII characters, and Ruby crash reports that point to Onigmo.
The guidance with those rules warns that a successful exploit can leave no crash, and it gives these further steps:
- Look for files owned by the git user in /tmp, unexpected child processes of Puma or Sidekiq, outbound connections, and changed crontabs or SSH keys for the git user.
- If there are signs of code execution, treat the server as compromised and rotate the secrets in gitlab-secrets.json, all CI/CD variables, all runner tokens and all access tokens.
- Limit who can create accounts and personal access tokens on the server.
What Alpine Users Should Do
Account holders will need to set a new password with "Forgot your password?" on the sign-in page when gitlab.alpinelinux.org reopens, Alpine said. It has also seen automated login attempts against its GitLab using passwords leaked from other sites, and anyone who used their gitlab.alpinelinux.org password elsewhere should change it there.
Users of the alpinelinux/gitlab image should pull alpinelinux/gitlab:19.3.6 again. The image published on 27 October contains Ruby 3.3.13, while any 19.3.6 image pulled before then, and every older tag, is vulnerable.
Alpine's own Ruby packages already have the fix: Ruby 3.4.12 on Alpine 3.22, 3.23, 3.24 and edge, and Ruby 3.3.13 on Alpine 3.21. Running apk upgrade installs it.
Ruby's maintainers say the bug matters only for programs that compile a regular expression from text an attacker controls, and that Ruby's Regexp.timeout setting does not protect against it.