Indexer hardening: rate limits, max_maker_fills, logging, body limits (#376) #379
Labels
No labels
agent:fix_bugfix
agent:fix_conflicts
agent:fix_security
agent:gap_analysis
agent:implement
agent:implement
agent:implement
agent:open_issues
agent:ready
agent:research
agent:security_audit
agent:verify
architecture
backend
blocker:hybrid
blocker:launch
blocker:limit-orders
blocker:v2
block:log_only
block:security
bug
ci
contracts
correctness
deploy
dev
devops
docs
documentation
duplicate
e2e
enhancement
epic
feature
frontend
functional-completion
gas
good first issue
governance
help wanted
high-risk
hooks
hybrid
indexer
infra
infrastructure
integrators
invalid
launch-blocker
limit-orders
localnet
localterra
low priority
missing-implementation
needs-design
ops
performance
priority
high
priority
medium
product
qa
QA
question
ready
ready
research
scripts
security
security-hardening
smartcontracts
tech-debt
testing
ux
UX
v2
verification
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
code/cl8y-dex-terraclassic#379
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Parent
Remediation bundle for #376 — Full security report.
Covers approved findings: M-05, M-06, L-04, L-05, L-08, L-09.
Current codebase
indexer/src/config.rsclamps zero limits to 60/10 in prod withtracing::warn.indexer/src/api/mod.rsapply_rate_limit_layerskips governors whenrps == 0. Dev/QA with both limits at 0 has no startup warning.MAX_MAKER_FILLS_HARD_CAP = 100insmartcontracts/packages/dex-common/src/pair.rsL26. Indexer DB sim uses stale cap of 30 inindexer/src/api/db_orderbook_sim.rsL15. GET route solve LCD path inindexer/src/api/route_solver.rsL719 usesmax_maker_fills.max(1)with no upper bound. Frontend uses 100 inhybridBookWalkLimits.ts.indexer/src/lcd/mod.rsL89–127 logs full upstream URL and body snippets atWARN.indexer/src/api/compliance.rsL82–86 maps LCD failures tointernal_err→ HTTP 500 instead of 502/503.indexer/src/api/mod.rsbuild_routerhas noRequestBodyLimitLayeronPOST /api/v1/route/solve.frontend-dapp/src/services/indexer/client.ts—getPair/getTraderinterpolate path segments raw;getTokenDetailalready usesencodeURIComponent.Why needed
Unbounded
max_maker_fillsand disabled rate limits enable DoS against the indexer and upstream LCD. Logging and status-code hygiene reduce ops leakage. Body limits and URL encoding close minor abuse vectors.Constraints / guardrails
MAX_MAKER_FILLS_HARD_CAP(100) or benchmarked value — "ideally much higher than 30."Relevant files
indexer/src/config.rs,indexer/src/api/mod.rs,indexer/src/main.rsindexer/src/api/route_solver.rs,indexer/src/api/db_orderbook_sim.rsindexer/src/lcd/mod.rsindexer/src/api/compliance.rsfrontend-dapp/src/services/indexer/client.tssmartcontracts/packages/dex-common/src/pair.rsindexer/tests/security.rs,indexer/tests/api_route_solve.rsdocs/indexer-invariants.md,docs/operator-secrets.mdRecommended direction
config.rsormain.rs, emittracing::warn!whenRATE_LIMIT_RPS == 0 && RATE_LIMIT_LCD_HEAVY_RPS == 0regardless ofRUN_MODE.max_maker_fills(1, 8, 30, 100) under LocalTerra; document p99 latency and LCD fanout. UnifyMAX_MAKER_FILLS_HARD_CAPacrossdb_orderbook_sim.rs,route_solver.rsGET path, and chain constant. Clamp GET query param to benchmarked cap.api/pairs.rs) → 502/503 with generic client body.tower_http::limit::RequestBodyLimitLayer(64–256 KiB) on POST route solve.encodeURIComponenton all path params inclient.ts(getPair,getTrader, etc.).Acceptance criteria
max_maker_fillsclamped to unified cap (aligned with chain, not stale 30).blacklist-checkreturns 502/503 on LCD failure, not 500.Test plan
make setup-indexer-postgresthenmake test-indexer-integrationcd indexer && cargo test --test securitycd indexer && cargo test --test api_route_solve -- --test-threads=1frontend-dapp:src/services/indexer/__tests__/client.test.tsmake setup-cloud-localterraor existing bench harness)Attack / abuse test plan
GET /api/v1/route/solve?...&max_maker_fills=4294967295— must clamp to cap, complete within timeout.RATE_LIMIT_RPS=0in dev — warning logged at startup.hybrid_by_hopJSON (> limit) — 413, no OOM.blacklist-checkwith LCD down — 502/503, generic body, no internal host in response.Verification criteria
indexer/tests/security.rsincludes new cases for M-05, L-05, L-08.MAX_MAKER_FILLS_HARD_CAPsource of truth across indexer + chain.mentioned in issue #376
mentioned in commit
ca446a5c07mentioned in merge request !903
mentioned in commit
43e21b2b52mentioned in commit
9f1d4cb27dVerification — #379 (Indexer hardening: rate limits, max_maker_fills, logging, body limits)
Branch:
main@origin/main(no local changes)Verifier: Cloud Agent QA
Result: FAIL — acceptance criteria not implemented on
main. Issue left open.Acceptance criteria
indexer/src/config.rsonly warns per-knob whenRUN_MODE=prodand that knob is0(clamps to 60/10). Notracing::warn!when bothRATE_LIMIT_RPS=0andRATE_LIMIT_LCD_HEAVY_RPS=0in dev/QA.apply_rate_limit_layerskips governors whenrps == 0(indexer/src/api/mod.rsL133–135).max_maker_fillsclamped to unified cap (≠ stale 30)MAX_MAKER_FILLS_HARD_CAP: u32 = 30(indexer/src/api/db_orderbook_sim.rsL15). Chain/frontend use 100 (smartcontracts/packages/dex-common/src/pair.rsL26,hybridBookWalkLimits.tsL10). GET path usesmax_maker_fills.max(1)with no upper bound (indexer/src/api/route_solver.rsL719). No benchmark doc/script for #379max_maker_fillssweep.indexer/src/lcd/mod.rsL89–127 still logs fullfull_url, HTTP status, and body snippets attracing::warn!.blacklist-checkreturns 502/503 on LCD failure, not 500indexer/src/api/compliance.rsL82–86 maps LCD errors viainternal_err→ HTTP 500. Sharedlcd_gateway_errexists (indexer/src/api/errors.rs) but is not used here.RequestBodyLimitLayerinbuild_router(indexer/src/api/mod.rs). Grep: no 413 /PAYLOAD_TOO_LARGEhandling for route solve.getTokenDetail/getTokenPairsencode (client.tsL400–407).getPair(L102),getTrader(L281),getTraderPositions(L390), and other pair/trader subresources interpolate addresses raw. NoencodeURIComponenttests inclient.test.ts.Verification criteria (issue body)
indexer/tests/security.rsincludes M-05, L-05, L-08 casesblacklist-checkLCD failure status, or POST body 413. Existinglcd_failure_returns_sanitized_502_bodycovers order-book-head only.MAX_MAKER_FILLS_HARD_CAPsource of truthcargo test --test api_route_solve -- --test-threads=1— 23/23 ok.cargo test --test security -- --test-threads=1— 25/25 ok (includes #363 prod LCD-heavy clamp).Test plan (issue)
make setup-indexer-postgresindexer/.envready.make test-indexer-integrationapi::db_orderbook_sim::tests::zero_reserve_mirror_returns_no_outputfailed (pre-existing; not #379 scope).cd indexer && cargo test --test security--test-threads=1. 8/25 fail under default parallelism (DB seed races — pre-existing).cd indexer && cargo test --test api_route_solve -- --test-threads=1frontend-dappclient.test.tsgetPair/getTrader.max_maker_fillsbenchmark harnessscripts/qa/verify-issue-309.shis expired-park gas only.Attack / abuse plan
GET …/route/solve?max_maker_fills=4294967295clamped0→ startup warninghybrid_by_hopJSON → 413blacklist-checkLCD down → 502/503internal_err.getPair/getTrader.Recommended next steps
security.rscases for M-05, L-05, L-08; extendclient.test.tsfor path encoding.MAX_MAKER_FILLS_HARD_CAP(import from shared constant or re-export chain value 100).make test-indexer-integrationserially or fix thezero_reserve_mirrorlib test flake before release sign-off.No repo changes from this verification pass — no MR opened.
Verification — #379 (Indexer hardening: rate limits, max_maker_fills, logging, body limits)
Branch:
main@origin/main(clean working tree)Verifier: Cloud Agent QA
Result: FAIL — acceptance criteria not implemented on
main. Issue remains open.Acceptance criteria
indexer/src/config.rsL197–221 warns and clamps each knob only whenRUN_MODE=prodand that knob is0. Notracing::warn!when bothRATE_LIMIT_RPS=0andRATE_LIMIT_LCD_HEAVY_RPS=0in dev/QA.apply_rate_limit_layerskips governors whenrps == 0(indexer/src/api/mod.rsL129–135).max_maker_fillsclamped to unified cap (≠ stale 30)MAX_MAKER_FILLS_HARD_CAP: u32 = 30(indexer/src/api/db_orderbook_sim.rsL15). Chain/frontend use 100 (smartcontracts/packages/dex-common/src/pair.rsL26,hybridBookWalkLimits.tsL10). GET path usesmax_maker_fills.max(1)with no upper bound (indexer/src/api/route_solver.rsL719). No #379 benchmark doc/script formax_maker_fillssweep.indexer/src/lcd/mod.rsL89–127 logs fullfull_url, HTTP status, and body snippets attracing::warn!.blacklist-checkreturns 502/503 on LCD failure, not 500indexer/src/api/compliance.rsL82–86 maps LCD errors viainternal_err→ HTTP 500. Sharedlcd_gateway_errexists (indexer/src/api/errors.rsL9) but is not used here.RequestBodyLimitLayerinbuild_router(indexer/src/api/mod.rsL368+). Grep: no 413 / payload-too-large handling for route solve.getTokenDetail/getTokenPairsencode (client.tsL400–407).getPair(L102),getTrader(L281),getTraderPositions(L390), and 12+ other pair/trader subresources interpolate addresses raw. NoencodeURIComponenttests inclient.test.ts.Verification criteria (issue body)
indexer/tests/security.rsincludes M-05, L-05, L-08 casesblacklist-checkLCD failure status, or POST body 413. Existinglcd_failure_returns_sanitized_502_bodycovers order-book-head only.MAX_MAKER_FILLS_HARD_CAPsource of truthcargo test --test api_route_solve -- --test-threads=1— 23/23 ok.cargo test --test security -- --test-threads=1— 25/25 ok (includes #363 prod LCD-heavy clamp).Test plan (issue)
make setup-indexer-postgresindexer/.envready.make test-indexer-integrationapi::db_orderbook_sim::tests::zero_reserve_mirror_returns_no_outputfailed (pre-existing; not #379 scope). 148/149 lib tests passed.cd indexer && cargo test --test security -- --test-threads=1--test-threads=1(DB seed races — pre-existing).cd indexer && cargo test --test api_route_solve -- --test-threads=1frontend-dappclient.test.tsgetPair/getTrader.max_maker_fillsbenchmark harnessscripts/qa/verify-issue-309.shis expired-park gas only.Attack / abuse plan
GET …/route/solve?max_maker_fills=4294967295clampedroute_solver.rsL719).0→ startup warninghybrid_by_hopJSON → 413blacklist-checkLCD down → 502/503internal_err.getPair/getTraderand related helpers.Follow-ups
security.rscases for M-05, L-05, L-08; extendclient.test.tsfor path encoding.MAX_MAKER_FILLS_HARD_CAPat 100 (align indexer with chain constant).zero_reserve_mirror_returns_no_outputlib test flake before release sign-off.No repo changes from this verification pass — no MR opened.
mentioned in commit
1d12feb3c2mentioned in merge request !910
mentioned in commit
30cfd4be2eVerification — #379 (Indexer hardening: rate limits, max_maker_fills, logging, body limits)
Branch:
main@f5a0dc79(clean working tree)Verifier: Cloud Agent QA
Result: PASS — all acceptance criteria implemented and verified on
main.Acceptance criteria
indexer/src/config.rsL208–211:tracing::warn!whenRATE_LIMIT_RPS=0 && RATE_LIMIT_LCD_HEAVY_RPS=0regardless ofRUN_MODE.dev_dual_zero_rate_limits_load_without_clampinsecurity.rsconfirms dev dual-zero loads without clamp.max_maker_fillsclamped to unified cap (≠ stale 30)indexer/src/hybrid_limits.rsdefinesMAX_MAKER_FILLS_HARD_CAP = 100;clamp_max_maker_fillsused inroute_solver.rsanddb_orderbook_sim.rs. Benchmark doc:docs/benchmarks/max-maker-fills-route-solve.md; harness:scripts/qa/bench-max-maker-fills-route-solve.sh. Unit test clamps4294967295→ 100.indexer/src/lcd/mod.rsL110–120: WARN logspath(redacted vialcd_log_path), status, endpoint idx only; full URL/body at DEBUG.blacklist-checkreturns 502/503 on LCD failure, not 500indexer/src/api/compliance.rsL86 useslcd_gateway_err.blacklist_check_lcd_failure_returns_sanitized_502— HTTP 502, generic body, no LCD host in response.RequestBodyLimitLayeron POST/api/v1/route/solve(api/mod.rsL415–417, 128 KiB).route_solve_post_oversized_body_returns_413insecurity.rs.pathSegment()→encodeURIComponentinclient.ts; all pair/trader subresources use it.client.test.ts— 19/19 including slash/special-char encoding tests.Verification criteria (issue body)
indexer/tests/security.rsincludes M-05, L-05, L-08 casesdev_dual_zero_rate_limits_load_without_clamp,blacklist_check_lcd_failure_returns_sanitized_502,route_solve_post_oversized_body_returns_413.MAX_MAKER_FILLS_HARD_CAPsource of truthhybrid_limits.rs(100); chain:dex-common/pair.rs(100); frontend:hybridBookWalkLimits.ts(100). Stale indexer value 30 removed.cargo test --test api_route_solve -- --test-threads=1— 23/23.cargo test --test security -- --test-threads=1— 28/28 (includes #363 prod LCD-heavy clamp).Test plan (issue)
make setup-indexer-postgresindexer/.envready.make test-indexer-integrationapi::db_orderbook_sim::tests::zero_reserve_mirror_returns_no_output— 151/152 lib tests pass; pre-existing flake, not #379 scope.cd indexer && cargo test --test security -- --test-threads=1cd indexer && cargo test --test api_route_solve -- --test-threads=1frontend-dappclient.test.tsmax_maker_fillsbenchmark harnessmake has-localterra→ not provisioned). Benchmark doc + script present; reference table indocs/benchmarks/max-maker-fills-route-solve.md.Attack / abuse plan
GET …/route/solve?max_maker_fills=4294967295clampedhybrid_limits::tests::clamp_rejects_zero_and_overflow;route_solvercache-key tests.0→ startup warningconfig.rsdual-zerotracing::warn!.hybrid_by_hopJSON → 413route_solve_post_oversized_body_returns_413.blacklist-checkLCD down → 502/503blacklist_check_lcd_failure_returns_sanitized_502.client.test.tsencodes/and+in pair/trader paths.No repo changes from this verification pass — closing issue.
mentioned in issue #337
mentioned in issue #485
mentioned in issue #594
mentioned in issue #595
mentioned in issue #694