GitHub Advisoryadvisory · Go
GHSA-j48m-h7xq-2xpj goshs: Share-link ?token=… redemption races past download limit
MEDIUM
Official page ↗
- Aliases
- CVE-2026-50139
- Ecosystem
- Go
- Packages
- goshs.de/goshs/v2
- Severity
- Moderate
- CVSS vector
- CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N
- Weaknesses
- CWE-362
- Reviewed
- 2026-07-01
Affected packages
• Go goshs.de/goshs/v2: < 2.1.0 → fixed in 2.1.0
Description
Share-link `?token=…` redemption races past download limit
Ecosystem: Go
Package: `goshs.de/goshs/v2` (`github.com/patrickhener/goshs`)
Affected: ` 0 || entry.DownloadLimit == -1 {
// ...serve file... // = current.DownloadLimit { delete(fs.SharedLinks, token) }
fs.sharedLinksMu.Unlock()
```
Between line 978 (`RUnlock`) and line 1008 (`Lock`), any number of goroutines can interleave and each observes the same pre-increment limit.
Proof of concept
```bash
goshs -p 18000 -d /tmp/r -b admin:pw &
echo data > /tmp/r/f.txt
operator issues a one-shot share
SHARE=$(curl -su admin:pw "http://localhost:18000/f.txt?share&limit=1")
TK=$(echo "$SHARE" | sed -n 's/.*token=\([^"]*\)".*/\1/p')
attacker races two redemptions
curl -so /dev/null -w "%{http_code}\n" "http://localhost:18000/?token=$TK" & \
curl -so /dev/null -w "%{http_code}\n" "http://localhost:18000/?token=$TK" & \
wait
observed: 200 / 200 (both succeed) -> limit=1 redeemed twice
```
Reproduced 5/5 times in a row on a 2026-era M-series Mac during verification.
Impact
A "single-use" share intended to deliver a one-shot secret can be redeemed N times by N concurrent clients. Combined with any token-leak vector (mail forwarding, browser history, intercepted link, etc.) this multiplies the exfiltration window.
Suggested fix
Reserve under the write lock *before* serving — refund only if the serve fails:
```go
fs.sharedLinksMu.Lock()
entry, ok := fs.SharedLinks[token]
if !ok || time.Now().After(entry.Expires) ||
(entry.DownloadLimit != -1 && entry.Downloaded >= entry.DownloadLimit) {
fs.sharedLinksMu.Unlock(); http.NotFound(w, r); return
}
entry.Downloaded++
if entry.DownloadLimit != -1 && entry.Downloaded >= entry.DownloadLimit {
delete(fs.SharedLinks, token)
} else {
fs.SharedLinks[token] = entry
}
fs.sharedLinksMu.Unlock()
// ...serve...
```
Add a regression test that races two requests against a `limit=1` token and asserts exactly one `200`.
Reporter: Nishant Verma. Reproduced against `goshs v2.0.9` (commit `8fc1e91`) on 2026-05-27.
Related
Alias · CVE (1)
- CVE-2026-50139 goshs is a SimpleHTTPServer written in Go. vulnerability
Weakness · CWE (1)
- CWE-362 Concurrent Execution using Shared Resource with Improper Synchronization weakness