GitHub Security Advisory: GHSA-mr74-928f-rw69
Package: github.com/filebrowser/filebrowser/v2 (GO)
Severity: HIGH (CVSS 0.0)
CWE: CWE-200: Exposure of Sensitive Information to an Unauthorized Actor
Vulnerable versions: <= 2.60.0
Patched in: 2.61.0

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

Details:
### 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:

```go
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:
2.    - `/documents/shared/public-file.txt` (intended to be shared)
3.    - `/documents/secrets/passwords.txt` (NOT intended to be shared)
4.    - `/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}`
4.    - **Expected**: Lists only contents of `/documents/shared/`
5.    - **Actual**: Lists contents of `/documents/` (parent), revealing `secrets/`, `private/`, and `shared/` directories
4. 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)
**Standalone Go test** reproducing the exact vulnerable code path with `afero.NewBasePathFs`:

```go
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
- - Do