CVE-2026-33620 — pinchtab
MEDIUMCVE-2026-33620 is a medium-severity (CVSS 4.3) CWE-598 vulnerability in github.com/pinchtab/pinchtab. A fix is available for github.com/pinchtab/pinchtab — see the affected versions and patch details below.
PinchTab: API Bearer Token Exposed in URL Query Parameter via Server Logs and Intermediary Systems
Exploitation Status
Proof-of-concept exploit code exists
- CISA’s SSVC triage found public proof-of-concept exploit code for this CVE, though no confirmed active exploitation.
Exploitation and automatability from CISA’s SSVC triage for CVE-2026-33620.
EPSS Exploitation Probability
EPSS (Exploit Prediction Scoring System) is a daily probability model maintained by FIRST.org. It estimates the likelihood a CVE will be exploited in production environments within the next 30 days, derived from real-world threat intelligence signals.
How urgent is this, really
CVE-2026-33620 plotted by exploitation likelihood (EPSS) against impact (CVSS). The shaded corner — EPSS 50%+ and CVSS 7.0+ — is where this CVE doesn't sit, though severity or exploitability alone can still warrant action.
Where this sits among everything scored
Of 378,567 CVEs with a current EPSS score, this one falls in the < 10% band (highlighted). Real counts from FIRST.org, not a sample — log-scaled since the landscape is heavily right-skewed.
Real-World Exposure
github.com/pinchtab/pinchtabReal-time download stats are indexed for npm and PyPI packages. This vulnerability affects Go packages — download data is not available via public APIs for these ecosystems.
Description
Summary
PinchTab v0.7.8 through v0.8.3 accepted the API token from a token URL query parameter in addition to the Authorization header. When a valid API credential is sent in the URL, it can be exposed through request URIs recorded by intermediaries or client-side tooling, such as reverse proxy access logs, browser history, shell history, clipboard history, and tracing systems that capture full URLs.
This issue is an unsafe credential transport pattern rather than a direct authentication bypass. It only affects deployments where a token is configured and a client actually uses the query-parameter form. PinchTab's security guidance already recommended Authorization: Bearer <token>, but v0.8.3 still accepted ?token= and included first-party flows that generated and consumed URLs containing the token.
This was addressed in v0.8.4 by removing query-string token authentication and requiring safer header- or session-based authentication flows.
Details
Issue 1 — Query-string token accepted in v0.7.8 through v0.8.3 (internal/handlers/middleware.go):
The v0.8.3 authentication middleware accepted credentials from the URL query string:
// internal/handlers/middleware.go — v0.8.3
auth := r.Header.Get("Authorization")
qToken := r.URL.Query().Get("token")
if auth == "" && qToken == "" {
web.ErrorCode(w, 401, "missing_token", "unauthorized", false, nil)
return
}
provided := strings.TrimPrefix(auth, "Bearer ")
if provided == auth {
if qToken != "" {
provided = qToken
} else {
provided = auth
}
}
if subtle.ConstantTimeCompare([]byte(provided), []byte(cfg.Token)) != 1 {
web.ErrorCode(w, 401, "bad_token", "unauthorized", false, nil)
return
}
This means any client sending GET /health?token=<secret> in v0.8.3 would authenticate successfully without using the Authorization header. I verified the same query-token auth pattern is present in the historical tag range starting at v0.7.8, and it is removed in v0.8.4.
Issue 2 — First-party setup and dashboard flows in v0.8.3 generated and consumed ?token= URLs:
The v0.8.3 setup flow generated dashboard URLs containing the token in the query string:
// cmd/pinchtab/cmd_wizard.go — v0.8.3
func dashboardURL(cfg *config.FileConfig, path string) string {
host := orDefault(cfg.Server.Bind, "127.0.0.1")
port := orDefault(cfg.Server.Port, "9867")
url := fmt.Sprintf("http://%s:%s%s", host, port, path)
if cfg.Server.Token != "" {
url += "?token=" + cfg.Server.Token
}
return url
}
The v0.8.3 dashboard frontend also supported one-click login from that same query-string token:
// dashboard/src/App.tsx — v0.8.3
const params = new URLSearchParams(window.location.search);
const urlToken = params.get("token");
if (urlToken) {
setStoredAuthToken(urlToken);
clean.searchParams.delete("token");
window.history.replaceState({}, "", clean.pathname + clean.hash);
window.location.reload();
}
That combination materially increased the chance that users would open, copy, paste, bookmark, or log URLs containing live credentials before the token was scrubbed from the visible address bar.
Issue 3 — Exposure depends on surrounding systems recording the URL:
PinchTab's own request logger records r.URL.Path, not the full raw query string, so the leak is not primarily through PinchTab's structured application log. The risk comes from surrounding systems or client tooling that record the full request URI, such as:
- reverse proxies and load balancers
- browser history or bookmarks
- shell history containing full
curlcommands - clipboard or terminal history when the wizard prints and copies a tokenized URL
- tracing or monitoring systems that capture full request URLs
PoC
Step 1 — Confirm auth is required
curl -i http://localhost:9867/health
Expected in token-protected affected deployments:
HTTP/1.1 401 Unauthorized
Step 2 — Authenticate using the vulnerable query-parameter pattern
curl -i "http://localhost:9867/health?token=supersecrettoken"
Expected:
HTTP/1.1 200 OK
This demonstrates that the token is accepted from the URL.
Step 3 — Observe the exposure vector If the request traverses a system that records the full URI, the token may appear in logs or local history, for example:
GET /health?token=supersecrettoken HTTP/1.1
In v0.8.3, a first-party reproduction path also exists without any external proxy: run the setup wizard, copy the printed dashboard URL containing ?token=..., and note that the live credential is now present in clipboard history and any place that URL is pasted.
Impact
- Exposure of a valid API token through unsafe URL-based transport when a client uses the
?token=authentication form. - Lower barrier for credential compromise where reverse proxies, browser history, shell history, clipboard history, or tracing systems retain full request URIs.
- The
v0.8.3wizard/dashboard flow increased the practical likelihood of this exposure by generating and consuming tokenized URLs as a first-party login pattern. - Practical risk depends on actual use of the query-token pattern; deployments that use only
Authorization: Bearer <token>are not affected by this issue in practice. - This is not a direct authentication bypass. An attacker still needs access to a secondary source that captured the URL containing the token.
Suggested Remediation
- Reject query-string token authentication and accept credentials only through the
Authorizationheader or controlled session mechanisms. - Avoid generating user-facing URLs that contain live credentials.
- Document header-based auth as the only supported non-browser API authentication pattern.
- Recommend token rotation for users who may previously have used query-parameter authentication.
Screenshot Capture <img width="1162" height="164" alt="ภาพถ่ายหน้าจอ 2569-03-18 เวลา 12 46 08" src="https://github.com/user-attachments/assets/e68b4469-dafd-400d-a6e1-f74d368cc8ac" />
Affected Packages
| Ecosystem | Package | Vulnerable range | Fix |
|---|---|---|---|
| 🐹Go | github.com/pinchtab/pinchtab | ≥ 0.7.8&&< 0.8.4 | 0.8.4go get github.com/pinchtab/pinchtab@v0.8.4 |
Detection & mitigation playbook
Open-source dependencyDetect
Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for github.com/pinchtab/pinchtab, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.
Fix
Update github.com/pinchtab/pinchtab to 0.8.4 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms CVE-2026-33620 is resolved across your whole dependency graph.
Workarounds
If you can't upgrade right away: gate or disable the affected feature, validate untrusted input at the boundary, and avoid passing attacker-controlled data into the vulnerable path. O3's runtime protection blocks exploitation in production as an interim safeguard until the upgrade lands.
How O3 protects you
O3 Security's impact-aware SCA analyses which vulnerable code paths your application actually calls, so a match like CVE-2026-33620 can be triaged on real exposure rather than presence alone.
Tailored to CVE-2026-33620. Runtime protection reduces exposure until a permanent patch is applied and verified — it complements patching, it doesn't replace it.
Frequently Asked Questions
Is CVE-2026-33620 in your dependencies?
O3 Security finds CVE-2026-33620 across Go dependencies, including transitive ones, and its impact-aware SCA ranks findings by whether your code actually calls the vulnerable path.