FileBrowser has Path Traversal in Public Share Links that Exposes Files Outside Shared Directory

Description

Summary

When a user creates a public share link for a directory, the withHashFile middleware in http/public.go (line 59) uses filepath.Dir(link.Path) to compute the BasePathFs root. This sets the filesystem root to the parent directory instead of the shared directory itself, allowing anyone with the share link to browse and download files from all sibling directories.

Details

In http/public.go lines 52-64, the withHashFile function handles public share link requests:

basePath := link.Path    // e.g. "/documents/shared"
filePath := ""

if file.IsDir {
    basePath = filepath.Dir(basePath)  // BUG: becomes "/documents" (parent!)
    filePath = ifPath
}

d.user.Fs = afero.NewBasePathFs(d.user.Fs, basePath)

When a directory at /documents/shared is shared, filepath.Dir("/documents/shared") evaluates to "/documents". The BasePathFs is then rooted at the parent directory /documents/, giving the share link access to everything under /documents/ - not just the intended /documents/shared/.

This affects both publicShareHandler (directory listing via /api/public/share/{hash}) and publicDlHandler (file download via /api/public/dl/{hash}/path).

PoC

  1. Set up filebrowser with a user whose scope contains:
    • /documents/shared/public-file.txt (intended to be shared)
    • /documents/secrets/passwords.txt (NOT intended to be shared)
    • /documents/private/financial.csv (NOT intended to be shared)
  2. Create a public share link for the directory /documents/shared (via POST /api/share/documents/shared)
  3. Access the share link: GET /api/public/share/{hash}
    • Expected: Lists only contents of /documents/shared/
    • Actual: Lists contents of /documents/ (parent), revealing secrets/, private/, and shared/ directories
  4. Download sibling files: GET /api/public/dl/{hash}/secrets/passwords.txt
    • Expected: 404 or 403 (file outside share scope)
    • Actual: 200 with file contents (sibling file downloaded successfully)
      Standalone Go test reproducing the exact vulnerable code path with afero.NewBasePathFs:
func TestShareScopeEscape(t *testing.T) {
    baseFs := afero.NewMemMapFs()
    afero.WriteFile(baseFs, "/documents/shared/public.txt", []byte("public"), 0644)
    afero.WriteFile(baseFs, "/documents/secrets/passwords.txt", []byte("admin:hunter2"), 0644)

    linkPath := "/documents/shared"
    basePath := filepath.Dir(linkPath) // BUG: "/documents"
    scopedFs := afero.NewBasePathFs(baseFs, basePath)

    // Sibling file is accessible through the share:
    f, err := scopedFs.Open("/secrets/passwords.txt")
    // err is nil - file accessible! Content: "admin:hunter2"
}

This test passes, confirming the vulnerability.

Impact

Unauthenticated information disclosure (CWE-200, CWE-706). Anyone with a public share link for a directory can:
- Browse all sibling directories and files of the shared directory
- - Download any file within the parent directory scope
- - This works without authentication (public shares) or after providing the share password (password-protected shares)
All filebrowser v2.x installations that use directory sharing are affected.

Recommended Fix

Remove the filepath.Dir() call and use link.Path directly as the BasePathFs root:

if file.IsDir {
    // Don't change basePath - keep it as link.Path
    filePath = ifPath
}
d.user.Fs = afero.NewBasePathFs(d.user.Fs, basePath)

Affected commit: e3d00d591b567a8bfe3b02e42ba586859002c77d (latest)
File: http/public.go, line 59

Basic information

Type
reviewed
Severity
high
Advisory on GitHub
Open advisory ↗
Repository advisory
Open repository advisory ↗
Source code
Browse source ↗
Published (advisory)
2026-03-02 20:15:46 UTC
Updated
2026-03-05 22:49:48 UTC
GitHub reviewed
2026-03-02 20:15:46 UTC
NVD published
2026-03-05

EPSS Score

Score Percentile
0.04% 12.44%

CVSS Scores

Base score Version Severity Vector
7.1 4.0
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N Click to expand
Attack vector (AV:N)
Could be attacked over the internet or any normal routed network.
Attack complexity (AC:L)
Exploitation conditions are straightforward and stable.
Attack requirements (AT:N)
No additional preconditions are required beyond normal reachability.
Privileges required (PR:L)
Low privileges are required.
User interaction (UI:N)
No user interaction is required.
Vulnerable system confidentiality impact (VC:H)
High confidentiality impact on the vulnerable system.
Vulnerable system integrity impact (VI:N)
No integrity impact on the vulnerable system.
Vulnerable system availability impact (VA:N)
No availability impact on the vulnerable system.
Subsequent system confidentiality impact (SC:N)
No confidentiality impact on subsequent systems.
Subsequent system integrity impact (SI:N)
No integrity impact on subsequent systems.
Subsequent system availability impact (SA:N)
No availability impact on subsequent systems.

Identifiers

CWEs

CWE id Name
CWE-200 Exposure of Sensitive Information to an Unauthorized Actor

Credits

  • uug4na (reporter)
  • hacdias (remediation_developer)

Affected packages (1)

Vulnerable version ranges and first patched releases as published by GitHub.

Ecosystem Package Vulnerable range First patched Vulnerable functions
go github.com/filebrowser/filebrowser/v2 <= 2.60.0 2.61.0

References

cvelogic Threat Intelligence