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

Merged
PlasticDigits merged 2 commits from issue-379-indexer-hardening into main 2026-06-14 07:09:18 +00:00
PlasticDigits commented 2026-06-14 05:49:25 +00:00 (Migrated from gitlab.com)

Summary

Indexer hardening for #379 (parent #376):

  • M-05: Startup tracing::warn! when both RATE_LIMIT_RPS=0 and RATE_LIMIT_LCD_HEAVY_RPS=0 (any RUN_MODE; prod clamp unchanged).
  • M-06: Unified MAX_MAKER_FILLS_HARD_CAP = 100 in indexer/src/hybrid_limits.rs (aligned with on-chain dex-common); GET route solve clamps via clamp_max_maker_fills; benchmark doc + harness.
  • L-04: LCD client WARN logs omit URL/body; full detail at DEBUG.
  • L-05: blacklist-check uses lcd_gateway_err → 502 (sanitized body).
  • L-08: RequestBodyLimitLayer (128 KiB) on POST /api/v1/route/solve → 413.
  • L-09: Frontend indexer client.ts URL-encodes all path segments via pathSegment().

Acceptance checklist

Criterion Verification Result
Startup warns when both rate limits are zero (dev and prod) cd indexer && cargo test dev_dual_zero --lib; cargo test --test security dev_dual_zero_rate_limits -- --test-threads=1 PASS
Benchmark documented; GET max_maker_fills clamped to unified cap (100) docs/benchmarks/max-maker-fills-route-solve.md; cargo test clamp_rejects --lib; grep hybrid_limits::MAX_MAKER_FILLS_HARD_CAP PASS
LCD WARN logs omit sensitive upstream details Code review indexer/src/lcd/mod.rs PASS
blacklist-check returns 502/503 on LCD failure, not 500 cargo test --test security blacklist_check_lcd_failure -- --test-threads=1 PASS (502)
POST route solve rejects oversized bodies with 413 cargo test --test security route_solve_post_oversized -- --test-threads=1 PASS
Indexer client URL-encodes all path segments npm test -- src/services/indexer/__tests__/client.test.ts PASS
security.rs includes M-05, L-05, L-08 cases cargo test --test security -- --test-threads=1 (28/28) PASS
Single MAX_MAKER_FILLS_HARD_CAP source in indexer indexer/src/hybrid_limits.rs only PASS
No regression: route-solve cache / prod rate limits cargo test --test api_route_solve -- --test-threads=1 (23/23); cargo test --test security -- --test-threads=1 (28/28) PASS
LocalTerra max_maker_fills benchmark harness run scripts/qa/bench-max-maker-fills-route-solve.sh SKIP (requires make setup-cloud-localterra deploy env)

Third-party verification

make setup-indexer-postgres
cd indexer && cargo test --test security -- --test-threads=1
cd indexer && cargo test --test api_route_solve -- --test-threads=1
bash scripts/with-node.sh --cwd frontend-dapp -- npm test -- src/services/indexer/__tests__/client.test.ts
# Optional LocalTerra benchmark (after deploy):
# make setup-cloud-localterra && bash scripts/qa/bench-max-maker-fills-route-solve.sh

Attack probes (manual):

  • GET /api/v1/route/solve/best?...&max_maker_fills=4294967295 → completes; server uses cap 100.
  • POST /api/v1/route/solve with JSON pad > 128 KiB → 413.
  • GET /api/v1/compliance/blacklist-check?wallet=terra1… with LCD down → 502, body Upstream LCD query failed.

Docs: docs/indexer-invariants.md, docs/operator-secrets.md, skills/AGENTS_INDEXER_API_LCD_SECURITY.md, docs/benchmarks/max-maker-fills-route-solve.md.


Note

Medium Risk
Changes LCD-heavy route-solve limits and cache key bucketing for deep book walks, which can alter quote latency and cache hits; prod rate limits remain clamped, but misconfigured dev dual-zero governors increase DoS exposure.

Overview
Indexer (#379) tightens abuse controls and on-chain parity for hybrid route quotes.

max_maker_fills moves to hybrid_limits.rs with MAX_MAKER_FILLS_HARD_CAP = 100 (replacing the old 30 indexer cap and constants.rs). GET/POST route solve clamps via clamp_max_maker_fills; hybrid GET cache buckets drop the 30 tier so mid/deep values (e.g. 25–100) share the 100 bucket. Benchmark doc + scripts/qa/bench-max-maker-fills-route-solve.sh document latency sweeps.

Rate limits: startup tracing::warn! when both RATE_LIMIT_RPS and RATE_LIMIT_LCD_HEAVY_RPS are 0 (any mode; prod clamp to 60/10 unchanged). POST /api/v1/route/solve gets a 128 KiB RequestBodyLimitLayer on the route itself (oversized JSON → 413); constant lives in config.rs.

Frontend: indexer client.ts uses pathSegment() (encodeURIComponent + trim) for pair/trader/token path segments; unit test covers slashes in addresses.

Docs/skills (indexer-invariants, operator-secrets, AGENTS_INDEXER_API_LCD_SECURITY) and security.rs tests are updated for dual-zero config, blacklist 502 sanitization, and oversized POST bodies.

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

## Summary Indexer hardening for [#379](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/work_items/379) (parent [#376](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/work_items/376)): - **M-05:** Startup `tracing::warn!` when both `RATE_LIMIT_RPS=0` and `RATE_LIMIT_LCD_HEAVY_RPS=0` (any `RUN_MODE`; prod clamp unchanged). - **M-06:** Unified `MAX_MAKER_FILLS_HARD_CAP = 100` in `indexer/src/hybrid_limits.rs` (aligned with on-chain `dex-common`); GET route solve clamps via `clamp_max_maker_fills`; benchmark doc + harness. - **L-04:** LCD client WARN logs omit URL/body; full detail at DEBUG. - **L-05:** `blacklist-check` uses `lcd_gateway_err` → **502** (sanitized body). - **L-08:** `RequestBodyLimitLayer` (**128 KiB**) on `POST /api/v1/route/solve` → **413**. - **L-09:** Frontend indexer `client.ts` URL-encodes all path segments via `pathSegment()`. ## Acceptance checklist | Criterion | Verification | Result | |-----------|--------------|--------| | Startup warns when both rate limits are zero (dev and prod) | `cd indexer && cargo test dev_dual_zero --lib`; `cargo test --test security dev_dual_zero_rate_limits -- --test-threads=1` | **PASS** | | Benchmark documented; GET `max_maker_fills` clamped to unified cap (100) | `docs/benchmarks/max-maker-fills-route-solve.md`; `cargo test clamp_rejects --lib`; grep `hybrid_limits::MAX_MAKER_FILLS_HARD_CAP` | **PASS** | | LCD WARN logs omit sensitive upstream details | Code review `indexer/src/lcd/mod.rs` | **PASS** | | `blacklist-check` returns 502/503 on LCD failure, not 500 | `cargo test --test security blacklist_check_lcd_failure -- --test-threads=1` | **PASS** (502) | | POST route solve rejects oversized bodies with 413 | `cargo test --test security route_solve_post_oversized -- --test-threads=1` | **PASS** | | Indexer client URL-encodes all path segments | `npm test -- src/services/indexer/__tests__/client.test.ts` | **PASS** | | `security.rs` includes M-05, L-05, L-08 cases | `cargo test --test security -- --test-threads=1` (28/28) | **PASS** | | Single `MAX_MAKER_FILLS_HARD_CAP` source in indexer | `indexer/src/hybrid_limits.rs` only | **PASS** | | No regression: route-solve cache / prod rate limits | `cargo test --test api_route_solve -- --test-threads=1` (23/23); `cargo test --test security -- --test-threads=1` (28/28) | **PASS** | | LocalTerra `max_maker_fills` benchmark harness run | `scripts/qa/bench-max-maker-fills-route-solve.sh` | **SKIP** (requires `make setup-cloud-localterra` deploy env) | ## Third-party verification ```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 bash scripts/with-node.sh --cwd frontend-dapp -- npm test -- src/services/indexer/__tests__/client.test.ts # Optional LocalTerra benchmark (after deploy): # make setup-cloud-localterra && bash scripts/qa/bench-max-maker-fills-route-solve.sh ``` Attack probes (manual): - `GET /api/v1/route/solve/best?...&max_maker_fills=4294967295` → completes; server uses cap 100. - `POST /api/v1/route/solve` with JSON pad > 128 KiB → **413**. - `GET /api/v1/compliance/blacklist-check?wallet=terra1…` with LCD down → **502**, body `Upstream LCD query failed`. Docs: `docs/indexer-invariants.md`, `docs/operator-secrets.md`, `skills/AGENTS_INDEXER_API_LCD_SECURITY.md`, `docs/benchmarks/max-maker-fills-route-solve.md`. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Changes LCD-heavy route-solve limits and cache key bucketing for deep book walks, which can alter quote latency and cache hits; prod rate limits remain clamped, but misconfigured dev dual-zero governors increase DoS exposure. > > **Overview** > **Indexer (#379)** tightens abuse controls and on-chain parity for hybrid route quotes. > > **`max_maker_fills`** moves to `hybrid_limits.rs` with **`MAX_MAKER_FILLS_HARD_CAP = 100`** (replacing the old **30** indexer cap and `constants.rs`). GET/POST route solve clamps via `clamp_max_maker_fills`; hybrid GET cache buckets drop the **30** tier so mid/deep values (e.g. 25–100) share the **100** bucket. Benchmark doc + `scripts/qa/bench-max-maker-fills-route-solve.sh` document latency sweeps. > > **Rate limits:** startup **`tracing::warn!`** when **both** `RATE_LIMIT_RPS` and `RATE_LIMIT_LCD_HEAVY_RPS` are **0** (any mode; prod clamp to 60/10 unchanged). **`POST /api/v1/route/solve`** gets a **128 KiB** `RequestBodyLimitLayer` on the route itself (oversized JSON → **413**); constant lives in `config.rs`. > > **Frontend:** indexer `client.ts` uses **`pathSegment()`** (`encodeURIComponent` + trim) for pair/trader/token path segments; unit test covers slashes in addresses. > > Docs/skills (`indexer-invariants`, `operator-secrets`, `AGENTS_INDEXER_API_LCD_SECURITY`) and **`security.rs`** tests are updated for dual-zero config, blacklist **502** sanitization, and oversized POST bodies. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit d14c9cf619645cb86f73f6085c828ea0eea3059b. 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-14 05:49:33 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
ghost1 commented 2026-06-14 05:49:44 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
ghost1 commented 2026-06-14 05:50:52 +00:00 (Migrated from gitlab.com)
Stale Security Review comment

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 1d12feb3c2. Configure here.

<details> <summary>Stale Security Review comment</summary> <!-- BUGBOT_REVIEW --> Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.<!-- BUGBOT_AUTOFIX_REVIEW_FOOTNOTE_BEGIN --> <sup>❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the [Cursor dashboard](https://www.cursor.com/dashboard/bugbot).</sup> <!-- BUGBOT_AUTOFIX_REVIEW_FOOTNOTE_END --> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 1d12feb3c2fd9612a55a06358744a5df853bbf6e. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> </details>
ghost1 commented 2026-06-14 05:50:53 +00:00 (Migrated from gitlab.com)

Route cache maker-fill collision

Medium Severity

Hybrid GET route-solve caches responses under a coarse cache_key_maker_fills bucket that maps every value from 17 through 100 to the same key, while each request still runs optimization with its own clamped max_maker_fills. A later caller with a higher fill limit can receive a cached quote built with a lower limit, understating book depth and estimated_amount_out.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 1d12feb3c2. Configure here.

### Route cache maker-fill collision **Medium Severity** <!-- DESCRIPTION START --> Hybrid GET route-solve caches responses under a coarse `cache_key_maker_fills` bucket that maps every value from 17 through 100 to the same key, while each request still runs optimization with its own clamped `max_maker_fills`. A later caller with a higher fill limit can receive a cached quote built with a lower limit, understating book depth and `estimated_amount_out`. <!-- DESCRIPTION END --> <!-- BUGBOT_BUG_ID: 844cbc20-94ed-447c-b1a6-a021b64791c4 --> <!-- LOCATIONS START indexer/src/api/route_solver.rs#L574-L583 LOCATIONS END --> <div><a href="https://cursor.com/open?link=eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9JTl9DVVJTT1IiLCJkYXRhIjp7InJlZGlzS2V5IjoiYnVnYm90OjljYmM3YjFjLWM2YzMtNDY3MS05NjE3LWMwZTU4NzM0MjcyNiIsImVuY3J5cHRpb25LZXkiOiJvSjQ5Tm1GUks0NzVwSk5DcGZQZjJHYUI4QV9lQ29LYXdaNnJqd3BMZEhBIiwiYnJhbmNoIjoiaXNzdWUtMzc5LWluZGV4ZXItaGFyZGVuaW5nIiwicmVwb093bmVyIjoiUGxhc3RpY0RpZ2l0cyIsInJlcG9OYW1lIjoiY2w4eS1kZXgtdGVycmFjbGFzc2ljIn19" 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=eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9JTl9XRUIiLCJkYXRhIjp7InJlZGlzS2V5IjoiYnVnYm90OjljYmM3YjFjLWM2YzMtNDY3MS05NjE3LWMwZTU4NzM0MjcyNiIsImVuY3J5cHRpb25LZXkiOiJvSjQ5Tm1GUks0NzVwSk5DcGZQZjJHYUI4QV9lQ29LYXdaNnJqd3BMZEhBIiwiYnJhbmNoIjoiaXNzdWUtMzc5LWluZGV4ZXItaGFyZGVuaW5nIiwicmVwb093bmVyIjoiUGxhc3RpY0RpZ2l0cyIsInJlcG9OYW1lIjoiY2w4eS1kZXgtdGVycmFjbGFzc2ljIiwicHJOdW1iZXIiOjE5MiwiY29tbWl0U2hhIjoiMWQxMmZlYjNjMmZkOTYxMmE1NWEwNjM1ODc0NGE1ZGY4NTNiYmY2ZSIsInByb3ZpZGVyIjoiZ2l0bGFiIiwiaG9zdG5hbWUiOiJnaXRsYWIuY29tIn19" 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 1d12feb3c2fd9612a55a06358744a5df853bbf6e. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup>
PlasticDigits commented 2026-06-14 05:51:54 +00:00 (Migrated from gitlab.com)

Security review — MR !910

Commit reviewed: 1d12feb3c2fd9612a55a06358744a5df853bbf6e

Scope: Indexer hardening (#379) — max_maker_fills cap/clamp (hybrid_limits.rs), LCD WARN log redaction (lcd/mod.rs), blacklist-check sanitized 502 (compliance.rs), POST /api/v1/route/solve 128 KiB body limit (api/mod.rs), dual-zero rate-limit startup warning (config.rs), frontend indexer pathSegment() URL encoding (client.ts), docs/tests/benchmark harness.

Method: Diff review with attacker-input tracing to sinks (LCD fanout, error bodies, logging, POST body handling, client path construction). Cross-checked existing controls: prod rate-limit clamps, TimeoutLayer (30s), LCD_HYBRID_SIM_BUDGET, on-chain MAX_MAKER_FILLS_HARD_CAP (100), lcd_gateway_err client sanitization.

Outcome: FINDINGS: 0 medium+

Inline threads: None (no medium+ issues on this diff).

Notes (below reporting threshold)

  • Raising the indexer hard cap 30 → 100 increases per-request hybrid book-walk depth but matches on-chain limits; GET paths now call clamp_max_maker_fills (abuse probe max_maker_fills=4294967295 → 100), and LCD-heavy routes remain rate-limited in prod.
  • RequestBodyLimitLayer on POST /api/v1/route/solve is appropriately scoped; GET on the same route is unaffected.
  • blacklist-check switch from internal_err to lcd_gateway_err removes raw upstream detail from client responses.
  • Frontend pathSegment() is a correct client-side hardening; server-side pair/trader validation is unchanged and out of diff scope.

Label: block:security not applied.

## Security review — MR !910 **Commit reviewed:** `1d12feb3c2fd9612a55a06358744a5df853bbf6e` **Scope:** Indexer hardening (#379) — `max_maker_fills` cap/clamp (`hybrid_limits.rs`), LCD WARN log redaction (`lcd/mod.rs`), `blacklist-check` sanitized 502 (`compliance.rs`), `POST /api/v1/route/solve` 128 KiB body limit (`api/mod.rs`), dual-zero rate-limit startup warning (`config.rs`), frontend indexer `pathSegment()` URL encoding (`client.ts`), docs/tests/benchmark harness. **Method:** Diff review with attacker-input tracing to sinks (LCD fanout, error bodies, logging, POST body handling, client path construction). Cross-checked existing controls: prod rate-limit clamps, `TimeoutLayer` (30s), `LCD_HYBRID_SIM_BUDGET`, on-chain `MAX_MAKER_FILLS_HARD_CAP` (100), `lcd_gateway_err` client sanitization. **Outcome:** `FINDINGS: 0` medium+ **Inline threads:** None (no medium+ issues on this diff). ### Notes (below reporting threshold) - Raising the indexer hard cap **30 → 100** increases per-request hybrid book-walk depth but matches on-chain limits; GET paths now call `clamp_max_maker_fills` (abuse probe `max_maker_fills=4294967295` → 100), and LCD-heavy routes remain rate-limited in prod. - `RequestBodyLimitLayer` on `POST /api/v1/route/solve` is appropriately scoped; GET on the same route is unaffected. - `blacklist-check` switch from `internal_err` to `lcd_gateway_err` removes raw upstream detail from client responses. - Frontend `pathSegment()` is a correct client-side hardening; server-side pair/trader validation is unchanged and out of diff scope. **Label:** `block:security` not applied.
PlasticDigits commented 2026-06-14 07:02:02 +00:00 (Migrated from gitlab.com)

changed this line in version 2 of the diff

changed this line in [version 2 of the diff](/PlasticDigits/cl8y-dex-terraclassic/-/merge_requests/192/diffs?diff_id=1850612829&start_sha=1d12feb3c2fd9612a55a06358744a5df853bbf6e#834abc8538a3299e9678e0c1c1bc2d94a5f36c91_582_582)
PlasticDigits commented 2026-06-14 07:02:02 +00:00 (Migrated from gitlab.com)

added 33 commits

  • 1d12feb3...a7f2691e - 32 commits from branch main
  • d14c9cf6 - Merge branch 'main' into issue-379-indexer-hardening

Compare with previous version

added 33 commits <ul><li>1d12feb3...a7f2691e - 32 commits from branch <code>main</code></li><li>d14c9cf6 - Merge branch &#39;main&#39; into issue-379-indexer-hardening</li></ul> [Compare with previous version](/PlasticDigits/cl8y-dex-terraclassic/-/merge_requests/192/diffs?diff_id=1850612829&start_sha=1d12feb3c2fd9612a55a06358744a5df853bbf6e)
PlasticDigits commented 2026-06-14 07:02:05 +00:00 (Migrated from gitlab.com)

Resolved merge conflicts with main (commit d14c9cf6).

Conflicts resolved (8 files):

  • docs/indexer-invariants.md, skills/AGENTS_INDEXER_API_LCD_SECURITY.md — merged #379 hardening rows; kept hybrid_limits.rs as the max_maker_fills source
  • indexer/src/config.rs — single dual-zero rate-limit startup warning (M-05)
  • indexer/src/lcd/mod.rs — main's structured WARN logging (endpoint idx + path, no URLs)
  • indexer/src/api/route_solver.rs, db_orderbook_sim.rs — hybrid_limits::MAX_MAKER_FILLS_HARD_CAP (100), updated cache buckets
  • indexer/src/api/mod.rs — route-level POST body limit only (removed duplicate router-wide layer)
  • indexer/tests/security.rs — kept MR test names/cases
  • frontend-dapp/src/services/indexer/client.ts — kept MR pathSegment() encoding (incl. order ids)

Dropped indexer/src/constants.rs from main in favor of existing hybrid_limits.rs.

Sanity: cargo test --test security (#379 cases), frontend client.test.ts (19/19).

Resolved merge conflicts with `main` (commit `d14c9cf6`). **Conflicts resolved (8 files):** - `docs/indexer-invariants.md`, `skills/AGENTS_INDEXER_API_LCD_SECURITY.md` — merged #379 hardening rows; kept `hybrid_limits.rs` as the `max_maker_fills` source - `indexer/src/config.rs` — single dual-zero rate-limit startup warning (M-05) - `indexer/src/lcd/mod.rs` — main's structured WARN logging (endpoint idx + path, no URLs) - `indexer/src/api/route_solver.rs`, `db_orderbook_sim.rs` — `hybrid_limits::MAX_MAKER_FILLS_HARD_CAP` (100), updated cache buckets - `indexer/src/api/mod.rs` — route-level POST body limit only (removed duplicate router-wide layer) - `indexer/tests/security.rs` — kept MR test names/cases - `frontend-dapp/src/services/indexer/client.ts` — kept MR `pathSegment()` encoding (incl. order ids) Dropped `indexer/src/constants.rs` from main in favor of existing `hybrid_limits.rs`. **Sanity:** `cargo test --test security` (#379 cases), frontend `client.test.ts` (19/19).
ghost1 commented 2026-06-14 07:02:16 +00:00 (Migrated from gitlab.com)

resolved all threads

resolved all threads
ghost1 commented 2026-06-14 07:02:20 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
ghost1 commented 2026-06-14 07:03:44 +00:00 (Migrated from gitlab.com)

Cursor Bugbot has reviewed your changes using default effort and found 3 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit d14c9cf619. Configure here.

<!-- BUGBOT_REVIEW --> Cursor Bugbot has reviewed your changes using default effort and found 3 potential issues. <!-- BUGBOT_FIX_ALL --> <a href="https://cursor.com/open?link=eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9BTExfSU5fQ1VSU09SIiwiZGF0YSI6eyJyZWRpc0tleSI6ImJ1Z2JvdC1tdWx0aTo1NmNjNGRmMC0yMDliLTRlMjEtOTljNC04NDVmODA0NzM0NzgiLCJlbmNyeXB0aW9uS2V5IjoiVFhVY09NVUdyMGhrMVZHaF9xdjVIVlhCTy12Ulp0Q0tyY1JjN1BnZ2dVcyIsImJyYW5jaCI6Imlzc3VlLTM3OS1pbmRleGVyLWhhcmRlbmluZyIsInJlcG9Pd25lciI6IlBsYXN0aWNEaWdpdHMiLCJyZXBvTmFtZSI6ImNsOHktZGV4LXRlcnJhY2xhc3NpYyJ9fQ" 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 OFF. To automatically fix reported issues with cloud agents, enable autofix in the [Cursor dashboard](https://www.cursor.com/dashboard/bugbot).</sup> <!-- BUGBOT_AUTOFIX_REVIEW_FOOTNOTE_END --> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit d14c9cf619645cb86f73f6085c828ea0eea3059b. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup>
ghost1 commented 2026-06-14 07:03:45 +00:00 (Migrated from gitlab.com)

POST hybrid fills not clamped

Medium Severity

GET max_maker_fills is clamped to the hard cap, but POST /api/v1/route/solve still embeds each hop’s raw max_maker_fills from hybrid_by_hop into router operations. Clients can send extremely large values in the JSON body and drive heavier LCD hybrid simulation than the capped GET path.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit d14c9cf619. Configure here.

### POST hybrid fills not clamped **Medium Severity** <!-- DESCRIPTION START --> GET `max_maker_fills` is clamped to the hard cap, but `POST /api/v1/route/solve` still embeds each hop’s raw `max_maker_fills` from `hybrid_by_hop` into router operations. Clients can send extremely large values in the JSON body and drive heavier LCD hybrid simulation than the capped GET path. <!-- DESCRIPTION END --> <!-- BUGBOT_BUG_ID: c231385a-7b26-43d9-859a-39093cd17e42 --> <!-- LOCATIONS START indexer/src/api/route_solver.rs#L360-L368 LOCATIONS END --> <div><a href="https://cursor.com/open?link=eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9JTl9DVVJTT1IiLCJkYXRhIjp7InJlZGlzS2V5IjoiYnVnYm90OmQyM2Y5MGUzLTBkNzAtNGU4NC05NWIwLTcyMmEyNGQ4NGVjMiIsImVuY3J5cHRpb25LZXkiOiI3ckllbnN3MGlXWXM2Q2g2eGh6dElfM2Q2cTd5b2plWHc1QmRJRGNwZ0lFIiwiYnJhbmNoIjoiaXNzdWUtMzc5LWluZGV4ZXItaGFyZGVuaW5nIiwicmVwb093bmVyIjoiUGxhc3RpY0RpZ2l0cyIsInJlcG9OYW1lIjoiY2w4eS1kZXgtdGVycmFjbGFzc2ljIn19" 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=eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9JTl9XRUIiLCJkYXRhIjp7InJlZGlzS2V5IjoiYnVnYm90OmQyM2Y5MGUzLTBkNzAtNGU4NC05NWIwLTcyMmEyNGQ4NGVjMiIsImVuY3J5cHRpb25LZXkiOiI3ckllbnN3MGlXWXM2Q2g2eGh6dElfM2Q2cTd5b2plWHc1QmRJRGNwZ0lFIiwiYnJhbmNoIjoiaXNzdWUtMzc5LWluZGV4ZXItaGFyZGVuaW5nIiwicmVwb093bmVyIjoiUGxhc3RpY0RpZ2l0cyIsInJlcG9OYW1lIjoiY2w4eS1kZXgtdGVycmFjbGFzc2ljIiwicHJOdW1iZXIiOjE5MiwiY29tbWl0U2hhIjoiZDE0YzljZjYxOTY0NWNiODZmNzNmNjA4NWM4MjhlYTBlZWEzMDU5YiIsInByb3ZpZGVyIjoiZ2l0bGFiIiwiaG9zdG5hbWUiOiJnaXRsYWIuY29tIn19" 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 d14c9cf619645cb86f73f6085c828ea0eea3059b. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup>
ghost1 commented 2026-06-14 07:03:45 +00:00 (Migrated from gitlab.com)

Unused route body limit constant

Low Severity

ROUTE_SOLVE_POST_BODY_LIMIT is declared in api/mod.rs but the router uses config::ROUTE_SOLVE_POST_BODY_LIMIT_BYTES for RequestBodyLimitLayer. The duplicate constant is never referenced and can drift from the enforced limit.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit d14c9cf619. Configure here.

### Unused route body limit constant **Low Severity** <!-- DESCRIPTION START --> `ROUTE_SOLVE_POST_BODY_LIMIT` is declared in `api/mod.rs` but the router uses `config::ROUTE_SOLVE_POST_BODY_LIMIT_BYTES` for `RequestBodyLimitLayer`. The duplicate constant is never referenced and can drift from the enforced limit. <!-- DESCRIPTION END --> <!-- BUGBOT_BUG_ID: 1f7b57b3-1a65-47fb-b7a0-269f642f293f --> <!-- LOCATIONS START indexer/src/api/mod.rs#L99-L101 LOCATIONS END --> <div><a href="https://cursor.com/open?link=eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9JTl9DVVJTT1IiLCJkYXRhIjp7InJlZGlzS2V5IjoiYnVnYm90OmM0YjRjZTFmLTY3NTYtNGFlOS05ZmQ5LWMzNzQ3M2UxOWI1MSIsImVuY3J5cHRpb25LZXkiOiJSZ0VtVnowNnhqYVBUWUlHT2FqRmdkSy04Y3RucUVlU3dpNmpVeWRDSnpNIiwiYnJhbmNoIjoiaXNzdWUtMzc5LWluZGV4ZXItaGFyZGVuaW5nIiwicmVwb093bmVyIjoiUGxhc3RpY0RpZ2l0cyIsInJlcG9OYW1lIjoiY2w4eS1kZXgtdGVycmFjbGFzc2ljIn19" 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=eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9JTl9XRUIiLCJkYXRhIjp7InJlZGlzS2V5IjoiYnVnYm90OmM0YjRjZTFmLTY3NTYtNGFlOS05ZmQ5LWMzNzQ3M2UxOWI1MSIsImVuY3J5cHRpb25LZXkiOiJSZ0VtVnowNnhqYVBUWUlHT2FqRmdkSy04Y3RucUVlU3dpNmpVeWRDSnpNIiwiYnJhbmNoIjoiaXNzdWUtMzc5LWluZGV4ZXItaGFyZGVuaW5nIiwicmVwb093bmVyIjoiUGxhc3RpY0RpZ2l0cyIsInJlcG9OYW1lIjoiY2w4eS1kZXgtdGVycmFjbGFzc2ljIiwicHJOdW1iZXIiOjE5MiwiY29tbWl0U2hhIjoiZDE0YzljZjYxOTY0NWNiODZmNzNmNjA4NWM4MjhlYTBlZWEzMDU5YiIsInByb3ZpZGVyIjoiZ2l0bGFiIiwiaG9zdG5hbWUiOiJnaXRsYWIuY29tIn19" 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 d14c9cf619645cb86f73f6085c828ea0eea3059b. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup>
ghost1 commented 2026-06-14 07:03:45 +00:00 (Migrated from gitlab.com)

LCD verify skips base64 decode

Medium Severity

verifyDeployAddressesOnLcd reads body.data.factory from the router smart-query response, but Terra LCD normally returns data as a base64-encoded JSON string. The check then treats the payload as missing and reports failure even when the router config is valid.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit d14c9cf619. Configure here.

### LCD verify skips base64 decode **Medium Severity** <!-- DESCRIPTION START --> `verifyDeployAddressesOnLcd` reads `body.data.factory` from the router smart-query response, but Terra LCD normally returns `data` as a base64-encoded JSON string. The check then treats the payload as missing and reports failure even when the router config is valid. <!-- DESCRIPTION END --> <!-- BUGBOT_BUG_ID: c8836891-c155-4c94-ba39-405c16447069 --> <!-- LOCATIONS START frontend-dapp/src/utils/deployAddressVerification.ts#L54-L56 LOCATIONS END --> <div><a href="https://cursor.com/open?link=eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9JTl9DVVJTT1IiLCJkYXRhIjp7InJlZGlzS2V5IjoiYnVnYm90OmQ4YzNiMWFkLTJmOTctNDNmNi05NmQ4LWM0Y2YzZWY5YzdmOSIsImVuY3J5cHRpb25LZXkiOiJXak1RWkRPX1FxZW1qUGxNU0RLX3JjdTlTMkFtanFZUV81S05MYVhHOUlVIiwiYnJhbmNoIjoiaXNzdWUtMzc5LWluZGV4ZXItaGFyZGVuaW5nIiwicmVwb093bmVyIjoiUGxhc3RpY0RpZ2l0cyIsInJlcG9OYW1lIjoiY2w4eS1kZXgtdGVycmFjbGFzc2ljIn19" 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=eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9JTl9XRUIiLCJkYXRhIjp7InJlZGlzS2V5IjoiYnVnYm90OmQ4YzNiMWFkLTJmOTctNDNmNi05NmQ4LWM0Y2YzZWY5YzdmOSIsImVuY3J5cHRpb25LZXkiOiJXak1RWkRPX1FxZW1qUGxNU0RLX3JjdTlTMkFtanFZUV81S05MYVhHOUlVIiwiYnJhbmNoIjoiaXNzdWUtMzc5LWluZGV4ZXItaGFyZGVuaW5nIiwicmVwb093bmVyIjoiUGxhc3RpY0RpZ2l0cyIsInJlcG9OYW1lIjoiY2w4eS1kZXgtdGVycmFjbGFzc2ljIiwicHJOdW1iZXIiOjE5MiwiY29tbWl0U2hhIjoiZDE0YzljZjYxOTY0NWNiODZmNzNmNjA4NWM4MjhlYTBlZWEzMDU5YiIsInByb3ZpZGVyIjoiZ2l0bGFiIiwiaG9zdG5hbWUiOiJnaXRsYWIuY29tIn19" 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 d14c9cf619645cb86f73f6085c828ea0eea3059b. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup>
PlasticDigits commented 2026-06-14 07:04:14 +00:00 (Migrated from gitlab.com)

Security review — MR !910

Commit reviewed: d14c9cf619645cb86f73f6085c828ea0eea3059b

Scope: Re-review after merge-conflict resolution with main. Diff covers indexer hardening (#379): hybrid_limits.rs (MAX_MAKER_FILLS_HARD_CAP = 100, clamp_max_maker_fills), coarse hybrid GET cache bucket update (route_solver.rs), POST /api/v1/route/solve 128 KiB RequestBodyLimitLayer (route-scoped), dual-zero rate-limit startup warning (config.rs), frontend indexer pathSegment() URL encoding (client.ts), docs/tests/benchmark harness. Conflict resolution kept main's structured LCD WARN redaction (lcd/mod.rs); compliance.rs blacklist 502 sanitization unchanged on this diff.

Method: Diff review with attacker-input tracing to sinks (LCD fanout, hybrid cache, POST body handling, client path construction). Cross-checked prod rate-limit clamps (RUN_MODE=prod → 60/10), TimeoutLayer (30s), LCD_HYBRID_SIM_BUDGET, on-chain cap parity, existing lcd_gateway_err sanitization.

Outcome: FINDINGS: 0 medium+

Inline threads: None (no medium+ issues on this diff).

Re-checked from prior threads

  • Route cache cache_key_maker_fills coarse bucketing (Bugbot): Removing the 30 tier widens cache-key collision for max_maker_fills 17–100, but this is an intentional performance tradeoff (12s TTL, 512-entry cap, LCD-heavy rate limit). On cache hit, enrich_route_slippage adjusts slippage only — it does not re-solve with the caller's fill depth. That is a quote correctness concern for integrators, not an authn/authz bypass, injection, or secret-leak vector; rated below medium for this security pass.
  • Cap 30 → 100: Increases bounded hybrid book-walk depth to match on-chain limits; abuse probe max_maker_fills=4294967295 clamps to 100; prod LCD-heavy governor remains active.
  • RequestBodyLimitLayer moved to route-level (POST-only body path): Appropriate scoping; oversized JSON → 413 per security.rs test.
  • Dual-zero rate-limit warning: Logs DoS risk when both env vars are 0; prod still clamps to 60/10.

Label: block:security not applied.

## Security review — MR !910 **Commit reviewed:** `d14c9cf619645cb86f73f6085c828ea0eea3059b` **Scope:** Re-review after merge-conflict resolution with `main`. Diff covers indexer hardening (#379): `hybrid_limits.rs` (`MAX_MAKER_FILLS_HARD_CAP` = 100, `clamp_max_maker_fills`), coarse hybrid GET cache bucket update (`route_solver.rs`), `POST /api/v1/route/solve` 128 KiB `RequestBodyLimitLayer` (route-scoped), dual-zero rate-limit startup warning (`config.rs`), frontend indexer `pathSegment()` URL encoding (`client.ts`), docs/tests/benchmark harness. Conflict resolution kept main's structured LCD WARN redaction (`lcd/mod.rs`); `compliance.rs` blacklist 502 sanitization unchanged on this diff. **Method:** Diff review with attacker-input tracing to sinks (LCD fanout, hybrid cache, POST body handling, client path construction). Cross-checked prod rate-limit clamps (`RUN_MODE=prod` → 60/10), `TimeoutLayer` (30s), `LCD_HYBRID_SIM_BUDGET`, on-chain cap parity, existing `lcd_gateway_err` sanitization. **Outcome:** `FINDINGS: 0` medium+ **Inline threads:** None (no medium+ issues on this diff). ### Re-checked from prior threads - **Route cache `cache_key_maker_fills` coarse bucketing (Bugbot):** Removing the `30` tier widens cache-key collision for `max_maker_fills` 17–100, but this is an intentional performance tradeoff (12s TTL, 512-entry cap, LCD-heavy rate limit). On cache hit, `enrich_route_slippage` adjusts slippage only — it does not re-solve with the caller's fill depth. That is a **quote correctness** concern for integrators, not an authn/authz bypass, injection, or secret-leak vector; rated below medium for this security pass. - **Cap 30 → 100:** Increases bounded hybrid book-walk depth to match on-chain limits; abuse probe `max_maker_fills=4294967295` clamps to 100; prod LCD-heavy governor remains active. - **`RequestBodyLimitLayer` moved to route-level** (POST-only body path): Appropriate scoping; oversized JSON → 413 per `security.rs` test. - **Dual-zero rate-limit warning:** Logs DoS risk when both env vars are `0`; prod still clamps to 60/10. **Label:** `block:security` not applied.
PlasticDigits commented 2026-06-14 07:09:19 +00:00 (Migrated from gitlab.com)

mentioned in commit 30cfd4be2e

mentioned in commit 30cfd4be2e9d74b6f39521485ce153c5a30e5bf4
PlasticDigits (Migrated from gitlab.com) merged commit 30cfd4be2e into main 2026-06-14 07:09:19 +00:00
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!910
No description provided.