WRITEUP · PLATFORM · GITLAB · CVE-2026-85706 · @YNSMROZTAS

Unauthenticated file-read class

● liveclk --:--:--CWE-22 · CVSS 10.0

Self-managed GitLab CE/EE opened an absolute path from a repository upload field before authenticate!. Workhorse missed the route. Puma decoded it. This page is the class and the classifier. The public helper stays on GitHub.

gitlab // workhorseobserve
radar--:--:--
CVE-2026-85706GitLab CE/EEWorkhorseCWE-22

Summary

CVE-2026-85706 is an unauthenticated local file read on self-managed GitLab Community Edition and Enterprise Edition. Three repository endpoints sit behind Workhorse requestBodyUploader. Rails takes the raw file.path field and runs File.open before authenticate!.

require_gitlab_workhorse! is not a gate here. Workhorse already stamps a valid Gitlab-Workhorse-Api-Request JWT on anything it proxies. The bug is the parser split: Workhorse matches EscapedPath() and a path.Clean clone that never percent-decodes. Puma decodes %XX before Grape routing. One side misses. The other routes. Rails opens the path.

gitlab.com and GitLab Dedicated are out of scope. The patch window is 19.1.8 / 19.2.6 / 19.3.2 (2026-09-10).

Redacted GitLabSniper session
Lab still. Host is gitlab.lab.local. File bytes, project ids and secrets painted out. Classifier tape, not a request list.

The split

Workhorse EscapedPath · no %XX decode Puma / Grape decodes · routes to Rails Rails File.open before auth echo urlencoded branch · invalid %-encoding (file bytes) id project id is a URL piece. file.path is an absolute server path. fix 19.1.8 / 19.2.6 / 19.3.2. Hunt logs for repository POST with a file.path field.

Confirm signal (class)

A honest confirm is not “GitLab HTML 200.” On an authorized lab the operator looked for the leak substring in the 400 body:

invalid %-encoding (
file bytes after the paren · that is FILE LEAK

Files with no lone % can still be opened. That returns read-noecho. That is an oracle. Do not file a critical on an oracle.

Verdicts

CVE-2026-85706  GitLab CE/EE self-managed
class            CWE-22  path used before auth
impact           unauthenticated local file read
auth             none
patched          19.1.8 · 19.2.6 · 19.3.2
lab              gitlab.lab.local

affected         18.7–19.1.7 · 19.2.0–19.2.5 · 19.3.0–19.3.1
out of scope     gitlab.com · GitLab Dedicated

mitsec@gitlab:

What GitLabSniper does on the wire

The public helper fingerprints GitLab, enumerates public project ids, walks the Workhorse-miss matrix, and only prints FILE LEAK when the 400 body carries the encoding echo. Pipeline mode accepts raw hosts and httpx lines.

This page does not reprint the request matrix or a ready-to-paste request. Those live in the repo for people who already have scope.

Fix

Repo

GitLabSniper stays on GitHub. Classifier model: guneykabel/cve-2026-85706. Vendor report credit: s3ntago via GitLab HackerOne.

Open github.com/ynsmroztas/GitLabSniper →

YUNUS EMRE ÖZTAŞ · MITSEC · AUTHORIZED TESTING ONLY