Indexer hardening: rate limits, max_maker_fills, logging, body limits (#379) #903

Merged
PlasticDigits merged 2 commits from issue-379-indexer-hardening into main 2026-06-13 10:35:30 +00:00
PlasticDigits commented 2026-06-13 10:11:02 +00:00 (Migrated from gitlab.com)

Summary

Remediation for #376 findings M-05, M-06, L-04, L-05, L-08, L-09 (#379):

  • M-05: Startup tracing::warn when both RATE_LIMIT_RPS and RATE_LIMIT_LCD_HEAVY_RPS are explicitly 0 (dev/QA unlimited mode).
  • M-06: Unified MAX_MAKER_FILLS_HARD_CAP = 100 in indexer/src/constants.rs (on-chain parity); GET route solve and DB hybrid sim clamp via clamp_max_maker_fills; cache buckets extended to 100.
  • L-04: LCD client WARN logs redact host/path; full detail at DEBUG only.
  • L-05: blacklist-check maps LCD failure to lcd_gateway_err → 502 (not 500).
  • L-08: RequestBodyLimitLayer (128 KiB) on LCD-heavy router (covers POST /api/v1/route/solve).
  • L-09: Frontend indexer client encodeURIComponent on all pair/trader path segments.

Docs: docs/indexer-invariants.md, docs/route-solver.md, skills/AGENTS_INDEXER_API_LCD_SECURITY.md.

Acceptance checklist

Criterion Verification Result
Startup warns when both rate limits are zero cd indexer && cargo test dev_allows_both_rate_limits_zero --lib + manual: RATE_LIMIT_RPS=0 RATE_LIMIT_LCD_HEAVY_RPS=0 startup log PASS
Benchmark documented; GET max_maker_fills clamped to 100 docs/route-solver.md § cap note; cargo test clamp_max_maker_fills_bounds --lib PASS
LCD WARN logs omit sensitive upstream details Code review indexer/src/lcd/mod.rs; lcd_log_path redaction PASS
blacklist-check returns 502 on LCD failure cargo test --test security blacklist_check_lcd_failure_returns_502 -- --test-threads=1 PASS
POST route solve rejects oversized bodies with 413 cargo test --test security post_route_solve_oversized_body_returns_413 -- --test-threads=1 PASS
Indexer client URL-encodes path segments cd frontend-dapp && vitest run src/services/indexer/__tests__/client.test.ts PASS

Verification checklist (third parties)

make setup-indexer-postgres
cd indexer && cargo test --test security -- --test-threads=1
cd indexer && cargo test --test api_route_solve -- --test-threads=1
cd indexer && cargo test clamp_max_maker_fills --lib
cd frontend-dapp && npx vitest run src/services/indexer/__tests__/client.test.ts

Manual abuse checks (optional, needs running indexer):

# Clamp abuse param (should complete, not OOM)
curl -sS -o /dev/null -w "%{http_code}\n" \
  "http://127.0.0.1:3001/api/v1/route/solve?token_in=...&token_out=...&amount_in=1000&max_maker_fills=4294967295"

# Oversized POST → 413
python3 -c 'print("x"*200000)' | curl -sS -o /dev/null -w "%{http_code}\n" \
  -X POST -H 'Content-Type: application/json' \
  --data-binary @- http://127.0.0.1:3001/api/v1/route/solve

# Blacklist LCD down → 502 generic body
curl -sS http://127.0.0.1:3001/api/v1/compliance/blacklist-check?wallet=terra1...

Constants grep (single source in indexer):

rg 'MAX_MAKER_FILLS_HARD_CAP' indexer/src/constants.rs smartcontracts/packages/dex-common/src/pair.rs

Note: make test-indexer-integration currently fails on a pre-existing lib test zero_reserve_mirror_returns_no_output (also fails on main); targeted suites above pass.


Note

Medium Risk
Touches route-solve hybrid/LCD fanout and raises the effective max_maker_fills cap from 30 to 100, which can increase per-request load; mitigations include clamping abuse values and body size limits.

Overview
Indexer/API hardening for GitLab #379: startup warns when both rate-limit env vars are explicitly 0; max_maker_fills is centralized in constants.rs and clamped to 100 (replacing the stale 30 DB cap) across route solve, hybrid sim, slippage, and extended cache buckets; POST /route/solve gets a 128 KiB body limit (413); compliance blacklist-check returns sanitized 502 on LCD failure; LCD WARN logs redact paths/URLs (detail at DEBUG).

The frontend indexer client now encodeURIComponents pair and trader path segments, with matching tests. Docs/skills and security integration tests cover the new invariants.

Reviewed by Cursor Bugbot for commit 43e21b2b52. Bugbot is set up for automated code reviews on this repo. Configure here.

## Summary Remediation for [#376](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/376) findings **M-05**, **M-06**, **L-04**, **L-05**, **L-08**, **L-09** ([#379](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/379)): - **M-05:** Startup `tracing::warn` when both `RATE_LIMIT_RPS` and `RATE_LIMIT_LCD_HEAVY_RPS` are explicitly `0` (dev/QA unlimited mode). - **M-06:** Unified `MAX_MAKER_FILLS_HARD_CAP = 100` in `indexer/src/constants.rs` (on-chain parity); GET route solve and DB hybrid sim clamp via `clamp_max_maker_fills`; cache buckets extended to 100. - **L-04:** LCD client WARN logs redact host/path; full detail at DEBUG only. - **L-05:** `blacklist-check` maps LCD failure to `lcd_gateway_err` → **502** (not **500**). - **L-08:** `RequestBodyLimitLayer` (**128 KiB**) on LCD-heavy router (covers `POST /api/v1/route/solve`). - **L-09:** Frontend indexer client `encodeURIComponent` on all pair/trader path segments. Docs: `docs/indexer-invariants.md`, `docs/route-solver.md`, `skills/AGENTS_INDEXER_API_LCD_SECURITY.md`. ## Acceptance checklist | Criterion | Verification | Result | |-----------|--------------|--------| | Startup warns when both rate limits are zero | `cd indexer && cargo test dev_allows_both_rate_limits_zero --lib` + manual: `RATE_LIMIT_RPS=0 RATE_LIMIT_LCD_HEAVY_RPS=0` startup log | **PASS** | | Benchmark documented; GET `max_maker_fills` clamped to 100 | `docs/route-solver.md` § cap note; `cargo test clamp_max_maker_fills_bounds --lib` | **PASS** | | LCD WARN logs omit sensitive upstream details | Code review `indexer/src/lcd/mod.rs`; `lcd_log_path` redaction | **PASS** | | `blacklist-check` returns 502 on LCD failure | `cargo test --test security blacklist_check_lcd_failure_returns_502 -- --test-threads=1` | **PASS** | | POST route solve rejects oversized bodies with 413 | `cargo test --test security post_route_solve_oversized_body_returns_413 -- --test-threads=1` | **PASS** | | Indexer client URL-encodes path segments | `cd frontend-dapp && vitest run src/services/indexer/__tests__/client.test.ts` | **PASS** | ## Verification checklist (third parties) ```bash make setup-indexer-postgres cd indexer && cargo test --test security -- --test-threads=1 cd indexer && cargo test --test api_route_solve -- --test-threads=1 cd indexer && cargo test clamp_max_maker_fills --lib cd frontend-dapp && npx vitest run src/services/indexer/__tests__/client.test.ts ``` Manual abuse checks (optional, needs running indexer): ```bash # Clamp abuse param (should complete, not OOM) curl -sS -o /dev/null -w "%{http_code}\n" \ "http://127.0.0.1:3001/api/v1/route/solve?token_in=...&token_out=...&amount_in=1000&max_maker_fills=4294967295" # Oversized POST → 413 python3 -c 'print("x"*200000)' | curl -sS -o /dev/null -w "%{http_code}\n" \ -X POST -H 'Content-Type: application/json' \ --data-binary @- http://127.0.0.1:3001/api/v1/route/solve # Blacklist LCD down → 502 generic body curl -sS http://127.0.0.1:3001/api/v1/compliance/blacklist-check?wallet=terra1... ``` Constants grep (single source in indexer): ```bash rg 'MAX_MAKER_FILLS_HARD_CAP' indexer/src/constants.rs smartcontracts/packages/dex-common/src/pair.rs ``` **Note:** `make test-indexer-integration` currently fails on a **pre-existing** lib test `zero_reserve_mirror_returns_no_output` (also fails on `main`); targeted suites above pass. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Touches route-solve hybrid/LCD fanout and raises the effective max_maker_fills cap from 30 to 100, which can increase per-request load; mitigations include clamping abuse values and body size limits. > > **Overview** > Indexer/API hardening for GitLab **#379**: **startup warns** when both rate-limit env vars are explicitly **0**; **`max_maker_fills`** is centralized in `constants.rs` and **clamped to 100** (replacing the stale **30** DB cap) across route solve, hybrid sim, slippage, and extended cache buckets; **`POST /route/solve`** gets a **128 KiB** body limit (**413**); **compliance `blacklist-check`** returns sanitized **502** on LCD failure; **LCD WARN logs** redact paths/URLs (detail at DEBUG). > > The **frontend indexer client** now **`encodeURIComponent`s** pair and trader path segments, with matching tests. Docs/skills and **security integration tests** cover the new invariants. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 43e21b2b52ff780421b9b813b2a01fff23409549. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
ghost1 commented 2026-06-13 10:11:11 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
ghost1 commented 2026-06-13 10:11:19 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
ghost1 commented 2026-06-13 10:12:19 +00:00 (Migrated from gitlab.com)

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is ON. A cloud agent has been kicked off to fix the reported issue.

Reviewed by Cursor Bugbot for commit ca446a5c07. Configure here.

<!-- BUGBOT_REVIEW --> Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue. <!-- BUGBOT_FIX_ALL --> <a href="https://cursor.com/open?link=eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9BTExfSU5fQ1VSU09SIiwiZGF0YSI6eyJyZWRpc0tleSI6ImJ1Z2JvdC1tdWx0aTplZjAwOTk0OC02MTUzLTRiYjEtYTIwOC1hOTAxYjRiMWQwNjUiLCJlbmNyeXB0aW9uS2V5IjoiYks4ZGlScnlqZUEzN3BsTm1YMHRZZ1VmTFBrRmJGRGVxcDNyMHlhRjVMYyIsImJyYW5jaCI6Imlzc3VlLTM3OS1pbmRleGVyLWhhcmRlbmluZyIsInJlcG9Pd25lciI6IlBsYXN0aWNEaWdpdHMiLCJyZXBvTmFtZSI6ImNsOHktZGV4LXRlcnJhY2xhc3NpYyJ9fQ" target="_blank" rel="noopener noreferrer"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/fix-in-cursor-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/fix-in-cursor-light.png"><img alt="Fix All in Cursor" width="115" height="28" src="https://cursor.com/assets/images/fix-in-cursor-dark.png"></picture></a> <!-- /BUGBOT_FIX_ALL --> <!-- BUGBOT_AUTOFIX_REVIEW_FOOTNOTE_BEGIN --> <sup>Bugbot Autofix is [ON](https://www.cursor.com/dashboard/bugbot). A cloud agent has been kicked off to fix the reported issue. <!-- BUGBOT_AUTOFIX_AGENT_LINK --></sup> <!-- BUGBOT_AUTOFIX_REVIEW_FOOTNOTE_END --> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit ca446a5c07761c8c0aa8d6dd5aadb91e40a10e97. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup>
ghost1 commented 2026-06-13 10:12:20 +00:00 (Migrated from gitlab.com)

Prod startup warns limits disabled

Low Severity

When both rate-limit env vars are explicitly 0, startup logs that all API rate governors are disabled even under RUN_MODE=prod, where those values are immediately replaced with the default global and LCD-heavy limits. Operators can misread logs as an unsecured deployment.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit ca446a5c07. Configure here.

### Prod startup warns limits disabled **Low Severity** <!-- DESCRIPTION START --> When both rate-limit env vars are explicitly `0`, startup logs that all API rate governors are disabled even under `RUN_MODE=prod`, where those values are immediately replaced with the default global and LCD-heavy limits. Operators can misread logs as an unsecured deployment. <!-- DESCRIPTION END --> <!-- BUGBOT_BUG_ID: 278a13cb-e0fd-4e86-9784-4abf7b3f3723 --> <!-- LOCATIONS START indexer/src/config.rs#L215-L221 LOCATIONS END --> <div><a href="https://cursor.com/open?link=eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9JTl9DVVJTT1IiLCJkYXRhIjp7InJlZGlzS2V5IjoiYnVnYm90OmRhZGYwNjRkLTllYTYtNDU1Ny05YzM2LWY3Mzg1ZDEyMWNiNSIsImVuY3J5cHRpb25LZXkiOiJ1clo3N2JUQU1Qazc3RU0wN2tMVWg4RHN4TU1WalUyUHpoYXlNN1kxdnlrIiwiYnJhbmNoIjoiaXNzdWUtMzc5LWluZGV4ZXItaGFyZGVuaW5nIiwicmVwb093bmVyIjoiUGxhc3RpY0RpZ2l0cyIsInJlcG9OYW1lIjoiY2w4eS1kZXgtdGVycmFjbGFzc2ljIn19" target="_blank" rel="noopener noreferrer"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/fix-in-cursor-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/fix-in-cursor-light.png"><img alt="Fix in Cursor" width="115" height="28" src="https://cursor.com/assets/images/fix-in-cursor-dark.png"></picture></a>&nbsp;<a href="https://cursor.com/agents?link=eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9JTl9XRUIiLCJkYXRhIjp7InJlZGlzS2V5IjoiYnVnYm90OmRhZGYwNjRkLTllYTYtNDU1Ny05YzM2LWY3Mzg1ZDEyMWNiNSIsImVuY3J5cHRpb25LZXkiOiJ1clo3N2JUQU1Qazc3RU0wN2tMVWg4RHN4TU1WalUyUHpoYXlNN1kxdnlrIiwiYnJhbmNoIjoiaXNzdWUtMzc5LWluZGV4ZXItaGFyZGVuaW5nIiwicmVwb093bmVyIjoiUGxhc3RpY0RpZ2l0cyIsInJlcG9OYW1lIjoiY2w4eS1kZXgtdGVycmFjbGFzc2ljIiwicHJOdW1iZXIiOjE4NSwiY29tbWl0U2hhIjoiY2E0NDZhNWMwNzc2MWM4YzBhYThkNmRkNWFhZGI5MWU0MGExMGU5NyIsInByb3ZpZGVyIjoiZ2l0bGFiIiwiaG9zdG5hbWUiOiJnaXRsYWIuY29tIn19" target="_blank" rel="noopener noreferrer"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/fix-in-web-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/fix-in-web-light.png"><img alt="Fix in Web" width="99" height="28" src="https://cursor.com/assets/images/fix-in-web-dark.png"></picture></a></div> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit ca446a5c07761c8c0aa8d6dd5aadb91e40a10e97. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup>
ghost1 commented 2026-06-13 10:14:06 +00:00 (Migrated from gitlab.com)

added 1 commit

  • 43e21b2b - fix(indexer): skip M-05 disabled warning in prod mode

Compare with previous version

added 1 commit <ul><li>43e21b2b - fix(indexer): skip M-05 disabled warning in prod mode</li></ul> [Compare with previous version](/PlasticDigits/cl8y-dex-terraclassic/-/merge_requests/185/diffs?diff_id=1850274983&start_sha=ca446a5c07761c8c0aa8d6dd5aadb91e40a10e97)
ghost1 commented 2026-06-13 10:14:18 +00:00 (Migrated from gitlab.com)

resolved all threads

resolved all threads
ghost1 commented 2026-06-13 10:14:18 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
PlasticDigits commented 2026-06-13 10:15:23 +00:00 (Migrated from gitlab.com)

Security review — MR !903

Commit reviewed: ca446a5c07761c8c0aa8d6dd5aadb91e40a10e97

Scope: Indexer hardening (#379) — clamp_max_maker_fills / MAX_MAKER_FILLS_HARD_CAP, RequestBodyLimitLayer (128 KiB) on LCD-heavy router, LCD WARN log redaction, blacklist-check → lcd_gateway_err (502), startup rate-limit warning, frontend encPath / encodeURIComponent.

Method: Traced attacker-controlled inputs (max_maker_fills query/body, POST body size, compliance wallet param, indexer client path segments) through handlers, LCD client, rate-limit layers, and client-visible error paths. Cross-checked against indexer/tests/security.rs and skills/AGENTS_INDEXER_API_LCD_SECURITY.md.

Outcome: FINDINGS: 0 medium+

  • Abuse bounds: GET/DB hybrid max_maker_fills now clamped via clamp_max_maker_fills before grid/LCD fanout; oversized POST /route/solve rejected with 413; LCD-heavy routes retain separate governor + 30s timeout.
  • Error hygiene: blacklist-check LCD failures map to sanitized 502 (lcd_gateway_err); client bodies remain generic; LCD WARN logs use redacted path prefixes (full detail at DEBUG).
  • Frontend: Path-segment encoding closes path-splitting / traversal in indexer client URLs for pair/trader routes.
  • Prod rate limits: RUN_MODE=prod still clamps RATE_LIMIT_*=0 to defaults; startup warning is informational only (not an authz bypass).

Inline threads: none (no medium+ findings).

Prior Bugbot note on misleading prod startup warning when limits are clamped remains low / operational — not reported as medium+.

block:security label not applied.

## Security review — MR !903 **Commit reviewed:** `ca446a5c07761c8c0aa8d6dd5aadb91e40a10e97` **Scope:** Indexer hardening (#379) — `clamp_max_maker_fills` / `MAX_MAKER_FILLS_HARD_CAP`, `RequestBodyLimitLayer` (128 KiB) on LCD-heavy router, LCD WARN log redaction, `blacklist-check` → `lcd_gateway_err` (502), startup rate-limit warning, frontend `encPath` / `encodeURIComponent`. **Method:** Traced attacker-controlled inputs (`max_maker_fills` query/body, POST body size, compliance wallet param, indexer client path segments) through handlers, LCD client, rate-limit layers, and client-visible error paths. Cross-checked against `indexer/tests/security.rs` and `skills/AGENTS_INDEXER_API_LCD_SECURITY.md`. **Outcome:** `FINDINGS: 0` medium+ - **Abuse bounds:** GET/DB hybrid `max_maker_fills` now clamped via `clamp_max_maker_fills` before grid/LCD fanout; oversized `POST /route/solve` rejected with **413**; LCD-heavy routes retain separate governor + 30s timeout. - **Error hygiene:** `blacklist-check` LCD failures map to sanitized **502** (`lcd_gateway_err`); client bodies remain generic; LCD WARN logs use redacted path prefixes (full detail at DEBUG). - **Frontend:** Path-segment encoding closes path-splitting / traversal in indexer client URLs for pair/trader routes. - **Prod rate limits:** `RUN_MODE=prod` still clamps `RATE_LIMIT_*=0` to defaults; startup warning is informational only (not an authz bypass). **Inline threads:** none (no medium+ findings). Prior Bugbot note on misleading prod startup warning when limits are clamped remains **low** / operational — not reported as medium+. `block:security` label **not** applied.
PlasticDigits (Migrated from gitlab.com) merged commit 9f1d4cb27d into main 2026-06-13 10:35:30 +00:00
PlasticDigits commented 2026-06-13 10:35:31 +00:00 (Migrated from gitlab.com)

mentioned in commit 9f1d4cb27d

mentioned in commit 9f1d4cb27d96a12905b44daff6d6ea059d2fc740
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
code/cl8y-dex-terraclassic!903
No description provided.