CVE-2026-52811
Summary
(*Repository).UploadRepoFiles checks for symlinks only on the leaf of the upload target (osx.IsSymlink(targetPath)). The siblings UpdateRepoFile, DeleteRepoFile, and GetDiffPreview use hasSymlinkInPath, which lstats every component — UploadRepoFiles is the lone outlier. An attacker with repo-write access plus a multipart upload whose filename contains a literal backslash (preserved by filepath.Base on Linux, then converted to / by pathx.Clean) redirects the write through a previously-committed directory symlink. iox.CopyFile opens the destination with os.Create (no O_NOFOLLOW), so the kernel follows the parent symlink and writes attacker bytes anywhere the gogs UID can write — ~git/.ssh/authorized_keys → SSH foothold, or <repo>.git/hooks/post-receive → next-push RCE.
Windows builds are unaffected: filepath.Base treats \ as a separator (strips the multi-segment trick) and git defaults core.symlinks=false at checkout (committed mode-120000 entries become text files, not real symlinks).
Details
The asymmetric check at internal/database/repo_editor.go:601-612:
targetPath := path.Join(dirPath, upload.Name)
if osx.IsSymlink(targetPath) { // ← LEAF-ONLY
return errors.Newf("cannot overwrite symbolic link: %s", upload.Name)
}
if err = iox.CopyFile(tmpPath, targetPath); err != nil { ... }
vs. UpdateRepoFile's correct walker at internal/database/repo_editor.go:163:
if hasSymlinkInPath(localPath, opts.OldTreeName) || hasSymlinkInPath(localPath, opts.NewTreeName) {
return errors.New("cannot update file with symbolic link in path")
}
hasSymlinkInPath (internal/database/repo_editor.go:120-131) lstats every component; osx.IsSymlink (internal/osx/osx.go:35-41) is os.Lstat mode-bit on the leaf — fine inside the loop, wrong as a single call.
Multi-segment upload.Name reaches the loop because: (1) c.Req.FormFile("file") returns *multipart.FileHeader whose Filename is filepath.Base(filename) — Linux only treats / as separator, so backslashes are preserved; (2) NewUpload
⚡ Watch CVE-2026-52811
Get an email if CVE-2026-52811 is added to CISA KEV, gains public exploit code, or a new advisory cites it — max one per day, one-click unsubscribe.
Exploitation outlook
- Low exploitation risk0.46% 30-day exploitation probability — currently an unlikely target, but scores change as exploit code circulates. Riskier than 37% of all EPSS-scored CVEs.
Advisory coverage (1)
- criticalGHSA-89mr-xqfv-758m: Gogs: UploadRepoFiles writes outside repo working tree via committed parent symghsa · 2026-06-23
External references
Embed the live status
— this badge updates automatically when the KEV or exploit status changes. How to embed it →
[](https://www.csirts.com/cve/CVE-2026-52811)