Problem
doGetWithPayment escapes the query value and concatenates the key raw:
// base_client.go:352-353
for k, v := range query {
url += sep + k + "=" + urlQueryEscape(v)
The caller-supplied path segment is also concatenated unescaped.
Impact
Every doGetWithPayment caller passes user-controlled input:
prediction_market.go:18 — endpoint := "/v1/pm/" + path
dex.go:28 — "/v1/zerox/" + path
defi.go:26 — "/v1/defillama/" + path
surf.go:244 — "/v1/surf/" + path
A map key of a&injected=1&b produces the request path:
/v1/pm/markets?a&injected=1&b=x
so a caller-supplied key forges extra query parameters. A path containing ? or # rewrites the request target entirely.
Fix
Replace the hand-rolled escaper with net/url:
- build a
url.Values and use .Encode(), which escapes keys and values
url.PathEscape each caller-supplied path segment
base_client.go:482 justifies the hand-rolled version with "It avoids pulling in net/url just for this single use site" — net/url is stdlib and already reachable, so the tradeoff no longer holds.
Provenance
Surfaced by Codex and confirmed by the adversarial pass during /review of #9.
Problem
doGetWithPaymentescapes the query value and concatenates the key raw:The caller-supplied path segment is also concatenated unescaped.
Impact
Every
doGetWithPaymentcaller passes user-controlled input:prediction_market.go:18—endpoint := "/v1/pm/" + pathdex.go:28—"/v1/zerox/" + pathdefi.go:26—"/v1/defillama/" + pathsurf.go:244—"/v1/surf/" + pathA map key of
a&injected=1&bproduces the request path:so a caller-supplied key forges extra query parameters. A path containing
?or#rewrites the request target entirely.Fix
Replace the hand-rolled escaper with
net/url:url.Valuesand use.Encode(), which escapes keys and valuesurl.PathEscapeeach caller-supplied path segmentbase_client.go:482justifies the hand-rolled version with "It avoids pulling in net/url just for this single use site" —net/urlis stdlib and already reachable, so the tradeoff no longer holds.Provenance
Surfaced by Codex and confirmed by the adversarial pass during
/reviewof #9.