Skip to content

network-driver: tcc queryStates/queryTokens/areTokensSpent have no request-size limit (resource exhaustion) #2050

Description

@adecaro

Summary

The token chaincode's invoke entry point enforces a request-size ceiling before doing any per-element work, but the read-only query functions — queryStates, queryTokens, areTokensSpent — have no analogous guard: each JSON array element the (unauthenticated) caller supplies translates 1:1 into a stub.GetState (or equivalent) call, with no cap on array length or payload size.

Where

token/services/network/fabric/tcc/tcc.go:281-375

The invoke path checks request size via CheckRawRequestSize/CheckRequestLimits (driver.DefaultResourceLimits().MaxRequestBytes) before processing. queryStates/queryTokens/areTokensSpent skip this check entirely.

Impact

Any client able to reach the chaincode's query path (which, unlike invoke, does not go through the size-limited transaction-submission flow) can submit a single request with an arbitrarily large key/id array, driving an unbounded number of ledger reads inside one chaincode invocation — a straightforward resource-exhaustion / peer-slowdown vector requiring no elevated privileges.

Reproduction

Reproduced locally with a unit test (not yet committed) that builds a 10,000-key payload already larger than MaxRequestBytes (the limit that would reject an equivalently-sized invoke request) and shows queryStates processes it in full:

payload, _ := json.Marshal(keys)  // 10,000 keys
require.Greater(t, len(payload), driver.DefaultResourceLimits().MaxRequestBytes)

resp := cc.Invoke(fakestub)
require.Equal(t, int32(200), resp.Status)
require.Equal(t, n, fakestub.GetStateCallCount())  // one GetState call per key, no cap

Happy to include this regression test in the fix PR.

Suggested fix

Apply the same size/count limits enforced on invoke (CheckRawRequestSize/CheckRequestLimits or an equivalent per-element cap) to queryStates, queryTokens, and areTokensSpent before processing their input arrays.

Severity

HIGH — unauthenticated resource-exhaustion vector against the chaincode/peer.

Metadata

Metadata

Assignees

Type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions