high · 8.1CVE-2026-72921Sep 2, 2026

CVE-2026-72921: SeaweedFS Filer JWT allowed_prefixes Authorization Bypass

Rohit Hatagale
AI Security Researcher, SecureLayer7

A filer JWT scoped to one tenant's path prefix also grants access to sibling paths that share the same string prefix, letting one tenant read or write another tenant's data.

Packagegithub.com/seaweedfs/seaweedfs
Ecosystemgo
Affected< 0.0.0-20260512171048-05ed5c9ae8a2
Fixed in0.0.0-20260512171048-05ed5c9ae8a2
CVE-2026-72921: SeaweedFS Filer JWT allowed_prefixes Authorization Bypass

The problem

SeaweedFS filer uses JWT tokens with an allowed_prefixes list to restrict which filer paths a token can access. Before version 4.24, the check in weed/server/filer_server_handlers.go called strings.HasPrefix on the raw request path.

Because strings.HasPrefix is a byte-level match with no concept of path separators, a token scoped to /tenant1 also passes the check for /tenant1234, /tenant1-old, /tenant1backup, and any other sibling path that begins with those characters. In a multi-tenant deployment this is a full cross-tenant read and write bypass for anyone holding a valid scoped token.

Proof of concept

A working proof-of-concept for CVE-2026-72921 in github.com/seaweedfs/seaweedfs, with the exact payload below.

bash
# Token is issued with allowed_prefixes = ["/tenant1"]
# Attacker-controlled request targets a SIBLING path that is NOT a child of /tenant1

curl -s -H 'Authorization: Bearer <jwt_scoped_to_tenant1>' \
  http://filer-host:8888/tenant1234/sensitive-data.txt

# strings.HasPrefix("/tenant1234/sensitive-data.txt", "/tenant1") == true
# => authorization passes, response is returned

The root cause is CWE-863 (Incorrect Authorization): the guard used strings.HasPrefix(requestPath, allowedPrefix) without anchoring on a path separator. The string /tenant1 is a byte prefix of /tenant1234, so the check returns true even though the paths belong to completely different tenants.

The patch (PR #9439, commit 05ed5c9) replaced the raw prefix match with a component-aware comparison after calling path.Clean on the request path. The fixed logic checks that the cleaned path either equals the allowed prefix exactly, or starts with allowedPrefix + "/", so /tenant1 only authorizes /tenant1 itself and true descendants like /tenant1/file.txt.

The fix

Upgrade to SeaweedFS 4.24 (commit 05ed5c9ae8a2). The allowed_prefixes check now uses path.Clean normalization and matches on /-separated path components, preventing sibling-path bypass. As a short-term workaround, ensure no configured prefix is a string-prefix of another (for example, add a trailing-separator convention such as /tenant1/), but upgrading is the only reliable fix.

Reported by Kadir Arslan.

References: [1][2][3][4][5][6]

Related research