Eclipse Foundation GitLab incident postmortem: CVE-2026-85706
Between 12 and 14 September 2026, our GitLab instance was affected by CVE-2026-85706, a critical vulnerability in GitLab that allowed unauthenticated attackers to read files from the server. Some of those files contained sensitive credentials, and they were copied by attackers before we closed the hole. The vulnerability is now fully remediated, the exposure is contained, and our investigation is complete.
We owe the community a clear account of what happened, what we’ve done about it, and what (if anything) you need to do. This is that account.
What happened
On 10 September, GitLab disclosed CVE-2026-85706, a maximum-severity (CVSS 10.0) path-traversal flaw affecting the repository API. The fix was released only for the GitLab 19.x line. Our instance was on the previous major version, 18.x, so applying it was not a matter of installing a patch: it required a major-version upgrade, which in turn required a PostgreSQL upgrade as a prerequisite. That is the reason for the gap between the fix being published and our deploying it, and we completed both upgrades by 16 September.
We learned of the vulnerability on 11 September and, that evening, deployed an emergency block at our reverse proxy to close the vector while the upgrade was prepared. That first mitigation turned out to be incomplete. GitLab’s advisory described the issue as affecting the repository commits API, and our block targeted that endpoint faithfully. The exploitation we actually saw, however, went through a neighbouring repository files endpoint that the advisory did not name (and the block did not cover it). Built under time pressure, outside working hours, and on the information available at the time, the mitigation closed the door the advisory pointed to while the attackers were using an adjacent one. Exploitation continued for roughly three days until our own log analysis revealed the real path, at which point we widened the block, verified it from the attacker’s side, and confirmed the traffic had stopped.
What was exposed
We want to be precise here rather than reassuring. This was not a “potential” exposure. Files were read and copied. The attackers obtained configuration files that included:
- GitLab’s master encryption and signing key material,
- database, cache, and internal service passwords, and
- our single sign-on / OAuth client secret.
We have treated all of these as compromised from the outset and rotated them accordingly.
What did not happen
The value of a thorough investigation is being able to state the boundaries with confidence rather than hope. We verified the following:
- No access to our databases. Our database and cache systems were never reachable from outside the trusted internal network, so the stolen passwords had nothing to connect to.
- No account takeover or forged access. The stolen keys can, in theory, be used to forge logins. On our architecture they cannot (sessions are validated server-side against storage the attackers could not reach) and we found no instance of forged or anomalous authenticated access.
- No code execution and no persistence. There was no mechanism available to the attackers to run code on our servers or to plant any lasting foothold. The activity was confined to reading files.
- No tampering. We found no unauthorized changes: no new administrators, no created tokens, no modified configuration, no repository or pipeline manipulation.
- SSH keys to other infrastructure were not obtained. The attackers probed for them; they were not present where they looked.
In short: the attackers copied a set of secrets, and our containment, network isolation, and architecture prevented them from turning those secrets into anything further.
What we did
- Closed the vulnerability at its source by upgrading GitLab to a current, supported, patched release (following the prerequisite database upgrade), and removed the temporary block once the fix was live.
- Rotated the exposed credentials, starting with the highest-value key material and infrastructure and single sign-on secrets, and worked through application tokens and integration credentials.
- Invalidated all active sessions and revoked personal access tokens as a precaution. If you were prompted to sign in again or noticed a token stop working, this is why.
- Ran a full forensic investigation across the affected systems to establish the scope above.
What this means for you
For the vast majority of users, there is no action required. But in the interest of full transparency:
- Sign-ins and tokens: As noted, we proactively invalidated active sessions and revoked personal access tokens. If you use personal access tokens, deploy tokens, or CI/CD variables, you may have already re-created them following our earlier communication; if you have not, please do so.
- Private project contents: We have no evidence that any repository content, private project data, or user data was accessed. The confirmed activity was limited to server configuration files, and the master keys could not be used to reach stored data. We are nonetheless disclosing this openly so you can make your own risk decisions.
- Credentials you may have stored in GitLab: If you stored any of your own secrets in CI/CD variables or similar, rotating them is a reasonable precaution, though we did not find evidence they were accessed.
If you have questions about your specific projects, please reach open a help desk ticket.
What we’re changing
An honest postmortem is worth little without changes that prevent a recurrence. The lessons here are not exotic, which is rather the point:
- Keep major-version upgrades current. The gap between the fix being available and our being able to apply it came down to being one major version behind, with a database prerequisite in the way. We are changing how we schedule platform upgrades so that being on the current major line (and clearing its prerequisites early) is treated as security-critical work, not deferrable maintenance. Had we been on 19.x, this would have been a routine patch.
- Verify mitigations from the attacker’s side. Our first emergency block was built on the advisory’s description and believed effective for three days before our logs showed otherwise. We are adding the discipline and tooling to prove a mitigation works against real traffic the moment it’s deployed (not just confirm a rule is in place) and to treat a vendor’s description of an issue as a starting point for our own verification rather than the whole picture.
- Detect faster, including outside hours. We learned of the vulnerability a day after disclosure, and of the gap in our mitigation only through manual log analysis. We are improving our monitoring of security advisories and of our own request logs so that critical issues (and failed mitigations) surface in hours regardless of when they land.
Closing
We’ve shared this in full because the community that relies on our infrastructure deserves a straight account. The summary is simple: a public exploit reached us in the window between the fix being released and our completing the major upgrade needed to apply it; an initial mitigation built on the advisory’s description missed the path actually being used; secrets were exposed as a result; and our containment, architecture, and follow-up investigation kept the damage from going any further. We’ve fixed the immediate cause and are addressing the practices behind it.
We’re grateful for your trust and committed to keeping it. Questions and feedback are welcome at [email protected].

