- What: GitLab patched CVE-2026-85706, a CVSS 10.0 path traversal in the repository commits API that allows an unauthenticated attacker to read arbitrary files from a self-managed GitLab server.
- Impact: A read primitive against GitLab config and log files yields database credentials, CI/CD secrets and runner tokens, which is the fast path to source code theft and build pipeline poisoning.
- Fix / mitigation: Upgrade to GitLab CE or EE 19.3.2, 19.2.6 or 19.1.8, which also fix the CVSS 9.9 insecure deserialization bug CVE-2026-87719 in EE.
- Who's at risk: Any organization running a self-managed GitLab CE or EE instance from 18.7 onward that is reachable from the internet and hosts at least one public project.
GitLab shipped patches on September 11, 2026 for a path traversal flaw rated CVSS 10.0. Attackers were scanning for it the same morning. Exposure management firm watchTowr recorded in-the-wild probes starting at 06:00 UTC on September 11, and CISA added the bug to the Known Exploited Vulnerabilities catalog that same day with a remediation deadline of September 14, 2026 for Federal Civilian Executive Branch agencies. That is a three day window on an unauthenticated file read against the system that holds your source code and your pipeline secrets.
The flaw: unauthenticated arbitrary file read
CVE-2026-85706 lives in the repository commits API. GitLab attributes it to "improper path confinement and missing authentication enforcement in the repository commits API." Two failures stacked on top of each other: the path handling does not keep a request inside the repository tree, and the endpoint does not enforce authentication on the way in. The result is that an external party with no account on your instance can read files off the underlying server.
watchTowr describes the practical payoff as reading log files and GitLab specific configuration files to obtain credentials, secrets and other sensitive information. This is not remote code execution by itself, and that distinction matters less than it sounds. On a self managed instance the configuration and secrets material on disk includes database credentials, the secrets key used to decrypt stored tokens and variables, and runner registration tokens. A reliable read of those files converts into full control of the instance and everything it builds.
Affected and fixed versions
- All versions from 18.7 before 19.1.8
- All versions from 19.2 before 19.2.6
- All versions from 19.3 before 19.3.2
- Both Community Edition and Enterprise Edition are in scope
The fixed releases are 19.1.8, 19.2.6 and 19.3.2. GitLab's guidance for self managed operators is blunt: if the instance is exposed to the internet, patch as soon as possible, and if public access is not required, remove it.
One precondition, and you probably meet it
Jake Knott, head of threat intelligence at watchTowr, put the entry requirement in a single line: "Exploitation requires just one requirement, at least one public project must exist." Almost every self managed instance has one. A documentation repo, a sample pipeline, a mirror of an open source dependency, a project someone flipped to public in 2023 and forgot. Do not treat this as a meaningful barrier. Treat the precondition as satisfied unless you have enumerated public project visibility across the instance and confirmed otherwise.
Probes landed at 06:00 UTC on the day of publication. This follows CVE-2026-19478, a critical GraphQL code injection in GitLab that Knott says was almost immediately exploited after its own disclosure. His read on what comes next: "Based on the history, the transition of this vulnerability to indiscriminate mass exploitation is likely not far away, and defenders have limited time to act." Plan your maintenance window on that assumption, not on a normal patch cycle.
The second critical in the same release
The same patch set closes CVE-2026-87719, an insecure deserialization bug in GitLab EE rated CVSS 9.9. Per GitLab, it "could allow an authenticated user with Duo Chat access to obtain Advanced Search instance configurations and sensitive credentials using a specially crafted GraphQL subscription argument to bypass serialization and perform server object lookup." It sits behind authentication and a Duo Chat entitlement, so it is the lower of the two priorities. It is also fixed by the same three releases, so you get it for free with the upgrade. Weight it higher if your instance allows open sign up, because "authenticated" is then a formality.
Why GitLab keeps landing on this list
Knott spells out the attacker calculus: "unauthorized access allows an attacker to gain access to source code, CI/CD secrets, credentials, and the ability to inject code into build pipelines, gaining access or poisoning anything downstream of it, which as we've seen throughout this year has been a favorite of attackers." A GitLab server is not one asset. It is a set of credentials for your cloud accounts, your container registry, your package feeds and your production deploy path, all stored in one place that has to be reachable by developers and runners. Rank it with your identity provider, not with your wiki.
Hunt before you assume you are clean
watchTowr gives a specific artifact to look for: HTTP POST requests to /api/v4/projects/{id}/repository/commits/ URIs containing file.Path parameters. Check the bundled nginx access log and the Rails JSON log, and check the rotated and gzipped copies, since your instance may have been probed before you were aware of the advisory.
sudo grep -F 'repository/commits/' /var/log/gitlab/nginx/gitlab_access.log | grep -F 'file.Path'
sudo zgrep -F 'file.Path' /var/log/gitlab/nginx/gitlab_access.log.*.gz
sudo grep -F 'file.Path' /var/log/gitlab/gitlab-rails/production_json.log
Order of operations for the next 24 hours
- Upgrade every internet reachable self managed instance to 19.3.2, 19.2.6 or 19.1.8, matching your current minor line.
- If you cannot patch inside the window, restrict inbound access to known CIDRs or take the instance off the public internet until you can.
- Grep nginx and Rails logs for POST requests to the commits API carrying file.Path, including rotated archives.
- If the instance was exposed and unpatched before September 11 at 06:00 UTC, rotate on the assumption that configuration files were read: CI/CD variables, runner registration tokens, deploy keys, personal and project access tokens, and database credentials.
- Re-enumerate public project visibility and drop anything that does not need to be public.
Every secret an attacker pulled before you upgraded is still valid after you upgrade. The patch closes the door; it does not change the locks. Rotation is the second half of the remediation and it is the half that usually gets deferred. Sequence it into the same change ticket as the upgrade.
Fix It Yourself
Everything above is what happened. This is what to run. The check commands change nothing.
Check whether you are exposed
Print the running GitLab version on an Omnibus install and compare it against 19.1.8, 19.2.6 and 19.3.2
sudo cat /opt/gitlab/embedded/service/gitlab-rails/VERSIONCount public projects on your instance with no credentials, which is the single precondition for exploitation
curl -sS "https://gitlab.example.com/api/v4/projects?visibility=public&simple=true&per_page=100" | python3 -c 'import sys,json; print(len(json.load(sys.stdin)), "public projects visible unauthenticated")'Search current and rotated logs for the exploitation artifact watchTowr published
sudo grep -rF 'file.Path' /var/log/gitlab/nginx/ /var/log/gitlab/gitlab-rails/ 2>/dev/null | grep -F 'repository/commits/'Close it
Upgrade an Omnibus EE install and print the resulting version, which must read 19.3.2, 19.2.6 or 19.1.8 (use gitlab-ce for Community Edition)
sudo apt-get update && sudo apt-get install --only-upgrade gitlab-ee && sudo cat /opt/gitlab/embedded/service/gitlab-rails/VERSIONContainment only, if you cannot patch in the window: allow HTTPS from one trusted CIDR and drop the rest (edit the CIDR first)
sudo ufw allow from 203.0.113.0/24 to any port 443 proto tcp && sudo ufw insert 2 deny proto tcp from any to any port 443Confirm stored secrets are still decryptable after the upgrade, before you begin rotating tokens
sudo gitlab-rake gitlab:doctor:secretsPrompts for the agent you already run
You run one or more self managed GitLab servers and want to know if you are exposed before you touch anything
You have confirmed you were running a vulnerable version while internet facing and need a rotation plan
What to alert on
Alert on POST requests to the repository commits API that carry a file.Path parameter. In the Omnibus nginx access log (/var/log/gitlab/nginx/gitlab_access.log) that is the request field matching /api/v4/projects/*/repository/commits/ with file.Path present in the body or query string, and in the Rails structured log (/var/log/gitlab/gitlab-rails/production_json.log) it is the path field on the same route. Two enrichments raise the signal sharply: in production_json.log, records for this route where meta.user and meta.user_id are absent indicate an unauthenticated caller, which is the exploitation condition rather than normal API use, and any value in the parameters containing traversal sequences or absolute paths under /etc/gitlab, /var/log/gitlab or /var/opt/gitlab should page immediately. Correlate a 200 status on an unauthenticated commits API request with an unusually large body_bytes_sent or duration_s to separate successful reads from blind scanning, and pivot on the remote_addr to find every other endpoint that source touched in the same session.
Questions about your exposure?
RedEye Security provides assessments for organizations that need to understand their real risk.
Talk to us