Surface fee-discount registry query failures to traders and ops (#365) #874

Merged
PlasticDigits merged 6 commits from issue-365-fee-discount-registry-observability into main 2026-06-12 11:12:57 +00:00
PlasticDigits commented 2026-06-12 05:19:44 +00:00 (Migrated from gitlab.com)

Summary

Implements GitLab #365 observability for fee-discount registry LCD outages without changing on-chain fail-closed semantics (pair still charges full fee_bps when GetDiscount errors).

  • Indexer: background LCD config probe every 60s; exposes GET /api/v1/health/fee-discount with fee_discount_registry_ok and consecutive_lcd_failures (no per-trader data, no raw LCD text). Repeated failures log at error.
  • Frontend: Swap page non-blocking amber warning when LCD registration/discount queries fail or indexer health reports registry down; utility distinguishes unregistered vs registry_unreachable.
  • Docs: P5 / I10 fail-closed semantics, indexer invariants row, agent skill cross-links.

Acceptance checklist

Criterion Verification Result
Documented on-chain fail-closed full fee on registry Err docs/contracts-security-audit.md P5, docs/reference/fee-discount-tiers.md I10 PASS
Off-chain signal when registry LCD queries fail repeatedly indexer/src/indexer/fee_discount_registry_health.rs probe + logs; GET /api/v1/health/fee-discount PASS
Frontend/API can distinguish no registration vs registry unreachable feeDiscountRegistryWarning.ts; health endpoint + LCD query error paths PASS
swap_uses_full_fee_when_discount_registry_query_fails still passes make test-contracts PASS

Verification checklist (third parties)

  1. make test-contracts — contract invariant unchanged.
  2. make test-frontend — includes feeDiscountRegistryWarning.test.ts.
  3. make setup-indexer-postgres && cd indexer && cargo test --test api_fee_discount_health -- --test-threads=1 — health API tests.
  4. With LocalTerra + indexer running: curl -s http://127.0.0.1:3001/api/v1/health/fee-discount | jq → configured: true, fee_discount_registry_ok: true.
  5. Swap UI: connect wallet on /swap; if registry LCD is blocked, amber fee-discount-registry-warning banner appears (swap still allowed).

Test plan

Path Command Result
Contracts make test-contracts PASS
Frontend unit make test-frontend PASS
Indexer integration make setup-indexer-postgres && cd indexer && cargo test --test api_fee_discount_health -- --test-threads=1 PASS
Manual registry outage Pause/misconfigure registry LCD → health false + Swap warning SKIP (not run on agent VM)

Note

Medium Risk
Swap UX and ops signals depend on indexer probe accuracy; Terra broadcast changes affect whether signed txs enter recovery polling vs failing fast on CheckTx errors—user-facing swap submission behavior.

Overview
GitLab #365 — fee-discount registry observability (on-chain fail-closed behavior unchanged): the indexer runs a 60s LCD config probe when FEE_DISCOUNT_ADDRESS is set and exposes GET /api/v1/health/fee-discount with fee_discount_registry_ok and consecutive_lcd_failures (no per-trader or raw LCD leakage). Repeated probe failures log at error.

The Swap page polls that health endpoint and shows a non-blocking amber banner when the registry is unreachable (LCD registration/discount errors or indexer health down), separate from the existing “Hold CL8Y” CTA for unregistered wallets. New feeDiscountRegistryWarning utility and indexer client getFeeDiscountHealth.

Docs/skills expand P5/I10 and indexer observability rows for fail-closed full fee on registry GetDiscount errors.

Terra broadcast (split sign/broadcast path): post-sign recovery now triggers on ambiguous RPC/broadcast failures (e.g. 502, “tx already in cache”), not only timeouts; definite CheckTx rejections (sequence mismatch, bad sig, etc.) skip recovery and surface the error immediately. Poll timeouts after a successful broadcast still enter recovery.

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

## Summary Implements GitLab #365 observability for fee-discount registry LCD outages without changing on-chain fail-closed semantics (pair still charges full `fee_bps` when `GetDiscount` errors). - **Indexer:** background LCD `config` probe every 60s; exposes `GET /api/v1/health/fee-discount` with `fee_discount_registry_ok` and `consecutive_lcd_failures` (no per-trader data, no raw LCD text). Repeated failures log at `error`. - **Frontend:** Swap page non-blocking amber warning when LCD registration/discount queries fail or indexer health reports registry down; utility distinguishes `unregistered` vs `registry_unreachable`. - **Docs:** P5 / I10 fail-closed semantics, indexer invariants row, agent skill cross-links. ## Acceptance checklist | Criterion | Verification | Result | |-----------|--------------|--------| | Documented on-chain fail-closed full fee on registry `Err` | `docs/contracts-security-audit.md` P5, `docs/reference/fee-discount-tiers.md` I10 | PASS | | Off-chain signal when registry LCD queries fail repeatedly | `indexer/src/indexer/fee_discount_registry_health.rs` probe + logs; `GET /api/v1/health/fee-discount` | PASS | | Frontend/API can distinguish no registration vs registry unreachable | `feeDiscountRegistryWarning.ts`; health endpoint + LCD query error paths | PASS | | `swap_uses_full_fee_when_discount_registry_query_fails` still passes | `make test-contracts` | PASS | ## Verification checklist (third parties) 1. `make test-contracts` — contract invariant unchanged. 2. `make test-frontend` — includes `feeDiscountRegistryWarning.test.ts`. 3. `make setup-indexer-postgres && cd indexer && cargo test --test api_fee_discount_health -- --test-threads=1` — health API tests. 4. With LocalTerra + indexer running: `curl -s http://127.0.0.1:3001/api/v1/health/fee-discount | jq` → `configured: true`, `fee_discount_registry_ok: true`. 5. Swap UI: connect wallet on `/swap`; if registry LCD is blocked, amber `fee-discount-registry-warning` banner appears (swap still allowed). ## Test plan | Path | Command | Result | |------|---------|--------| | Contracts | `make test-contracts` | PASS | | Frontend unit | `make test-frontend` | PASS | | Indexer integration | `make setup-indexer-postgres && cd indexer && cargo test --test api_fee_discount_health -- --test-threads=1` | PASS | | Manual registry outage | Pause/misconfigure registry LCD → health `false` + Swap warning | SKIP (not run on agent VM) | <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Swap UX and ops signals depend on indexer probe accuracy; Terra broadcast changes affect whether signed txs enter recovery polling vs failing fast on CheckTx errors—user-facing swap submission behavior. > > **Overview** > **GitLab #365 — fee-discount registry observability** (on-chain fail-closed behavior unchanged): the indexer runs a **60s LCD `config` probe** when `FEE_DISCOUNT_ADDRESS` is set and exposes **`GET /api/v1/health/fee-discount`** with `fee_discount_registry_ok` and `consecutive_lcd_failures` (no per-trader or raw LCD leakage). Repeated probe failures log at `error`. > > The **Swap page** polls that health endpoint and shows a **non-blocking amber banner** when the registry is unreachable (LCD registration/discount errors or indexer health down), separate from the existing “Hold CL8Y” CTA for unregistered wallets. New **`feeDiscountRegistryWarning`** utility and indexer client **`getFeeDiscountHealth`**. > > **Docs/skills** expand P5/I10 and indexer observability rows for fail-closed full fee on registry `GetDiscount` errors. > > **Terra broadcast (split sign/broadcast path):** post-sign recovery now triggers on **ambiguous** RPC/broadcast failures (e.g. 502, “tx already in cache”), not only timeouts; **definite CheckTx rejections** (sequence mismatch, bad sig, etc.) skip recovery and surface the error immediately. Poll timeouts after a successful broadcast still enter recovery. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 4d1570b7e7c16d708eb172e8da905f433d1c944e. 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-12 05:19:54 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
ghost1 commented 2026-06-12 05:20:05 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
PlasticDigits commented 2026-06-12 05:21:31 +00:00 (Migrated from gitlab.com)

Security review — MR !874

Commit reviewed: 8cc60b4acc08a5b30b6a5874b9b18b2ff62a32e3
Scope: Off-chain observability for fee-discount registry LCD outages (#365) — indexer background config probe + GET /api/v1/health/fee-discount, frontend Swap warning banner, docs/skills. No smart-contract changes.

Outcome: FINDINGS: 0 medium+

Method

  • Diff and sink tracing on all added/modified code paths.
  • Prior MR security threads: none to re-validate.

Areas examined

Vector Result
Injection / SSRF Probe uses server-config FEE_DISCOUNT_ADDRESS and fixed {"config":{}} query; health handler has no request parameters. No attacker-controlled input reaches LCD or SQL.
Authn / authz New route is read-only aggregate health (same class as /health); global tower_governor rate limit applies via apply_rate_limit_layer.
Information disclosure API returns only configured, fee_discount_registry_ok, consecutive_lcd_failures. Integration test asserts no LCD URLs, cosmwasm paths, or raw LCD error text in HTTP body. Probe failure logs use existing LcdError formatting (server-side only; not a new client leak vector).
XSS / CSRF Warning copy is a static constant rendered as React text; no user/LCD-derived strings in the banner. GET endpoint is side-effect free.
Abuse / DoS Health handler is in-memory RwLock snapshot (no per-request LCD). Background probe is capped at one query per 60s from indexer config address.
On-chain impact Documented fail-closed P5/I10 behavior unchanged; MR adds off-chain signals only.
Supply chain No new dependencies.

Inline threads

None — no medium, high, or critical findings on this diff.


Security review: no medium+ findings on this diff.

## Security review — MR !874 **Commit reviewed:** `8cc60b4acc08a5b30b6a5874b9b18b2ff62a32e3` **Scope:** Off-chain observability for fee-discount registry LCD outages (#365) — indexer background `config` probe + `GET /api/v1/health/fee-discount`, frontend Swap warning banner, docs/skills. No smart-contract changes. **Outcome:** `FINDINGS: 0` medium+ ### Method - Diff and sink tracing on all added/modified code paths. - Prior MR security threads: none to re-validate. ### Areas examined | Vector | Result | |--------|--------| | **Injection / SSRF** | Probe uses server-config `FEE_DISCOUNT_ADDRESS` and fixed `{"config":{}}` query; health handler has no request parameters. No attacker-controlled input reaches LCD or SQL. | | **Authn / authz** | New route is read-only aggregate health (same class as `/health`); global `tower_governor` rate limit applies via `apply_rate_limit_layer`. | | **Information disclosure** | API returns only `configured`, `fee_discount_registry_ok`, `consecutive_lcd_failures`. Integration test asserts no LCD URLs, `cosmwasm` paths, or raw LCD error text in HTTP body. Probe failure logs use existing `LcdError` formatting (server-side only; not a new client leak vector). | | **XSS / CSRF** | Warning copy is a static constant rendered as React text; no user/LCD-derived strings in the banner. GET endpoint is side-effect free. | | **Abuse / DoS** | Health handler is in-memory `RwLock` snapshot (no per-request LCD). Background probe is capped at one query per 60s from indexer config address. | | **On-chain impact** | Documented fail-closed P5/I10 behavior unchanged; MR adds off-chain signals only. | | **Supply chain** | No new dependencies. | ### Inline threads None — no medium, high, or critical findings on this diff. --- Security review: no medium+ findings on this diff.
PlasticDigits commented 2026-06-12 08:34:20 +00:00 (Migrated from gitlab.com)

added 32 commits

  • 8cc60b4a...62050542 - 31 commits from branch main
  • 4d33747d - Merge branch 'main' into issue-365-fee-discount-registry-observability

Compare with previous version

added 32 commits <ul><li>8cc60b4a...62050542 - 31 commits from branch <code>main</code></li><li>4d33747d - Merge branch &#39;main&#39; into issue-365-fee-discount-registry-observability</li></ul> [Compare with previous version](/PlasticDigits/cl8y-dex-terraclassic/-/merge_requests/156/diffs?diff_id=1848545991&start_sha=8cc60b4acc08a5b30b6a5874b9b18b2ff62a32e3)
PlasticDigits commented 2026-06-12 08:34:25 +00:00 (Migrated from gitlab.com)

Resolved merge conflicts with main:

  • docs/indexer-invariants.md — kept main's #363 rate-limit row (Retry-After, x-ratelimit-*, startup warning) and this branch's #365 fee-discount health observability row.
  • indexer/src/indexer/poller.rs — combined imports for both reorg_alert (main) and fee_discount_registry_health (this MR).

Sanity: cargo check (indexer), feeDiscountRegistryWarning unit tests.

Resolved merge conflicts with `main`: - **`docs/indexer-invariants.md`** — kept main's #363 rate-limit row (`Retry-After`, `x-ratelimit-*`, startup warning) and this branch's #365 fee-discount health observability row. - **`indexer/src/indexer/poller.rs`** — combined imports for both `reorg_alert` (main) and `fee_discount_registry_health` (this MR). Sanity: `cargo check` (indexer), `feeDiscountRegistryWarning` unit tests.
ghost1 commented 2026-06-12 08:34:34 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
PlasticDigits commented 2026-06-12 08:36:37 +00:00 (Migrated from gitlab.com)

Security review — MR !874 (re-review)

Commit reviewed: 4d33747d7f1ccf24239f6e349b2ff394da096ca1
Scope: Off-chain observability for fee-discount registry LCD outages (#365) — indexer background config probe + GET /api/v1/health/fee-discount, frontend Swap warning banner, docs/skills. Merge-conflict resolution with main (poller.rs import combine, indexer-invariants.md row merge). No smart-contract changes.

Outcome: FINDINGS: 0 medium+

Method

  • Full diff re-reviewed at current HEAD (post-merge with main).
  • Prior security thread on 8cc60b4 re-validated; no inline findings to carry forward.
  • Attacker-controlled input traced to sinks on all new/modified code paths.

Areas examined

Vector Result
Injection / SSRF Probe uses operator-config FEE_DISCOUNT_ADDRESS and fixed {"config":{}} query via LcdClient::query_contract; health handler has no request parameters. No attacker-controlled input reaches LCD paths or SQL.
Authn / authz New route is read-only aggregate health (same class as /health); protected by global tower_governor via apply_rate_limit_layer on api_router (not LCD-heavy subset).
Information disclosure HTTP body limited to configured, fee_discount_registry_ok, consecutive_lcd_failures. Integration test asserts no LCD URLs, cosmwasm paths, or raw LCD error text in responses. Probe failure logs use existing LcdError formatting (server-side only).
XSS / CSRF Warning copy is a static React text node; no user/LCD-derived strings in the banner. GET endpoint is side-effect free.
Abuse / DoS Health handler is in-memory RwLock snapshot (no per-request LCD). Background probe capped at one query per 60s from configured address.
On-chain impact Documented fail-closed P5/I10 behavior unchanged; MR adds off-chain signals only.
Supply chain No new dependencies.

Inline threads

None — no medium, high, or critical findings on this diff.


Security review: no medium+ findings on this diff.

## Security review — MR !874 (re-review) **Commit reviewed:** `4d33747d7f1ccf24239f6e349b2ff394da096ca1` **Scope:** Off-chain observability for fee-discount registry LCD outages (#365) — indexer background `config` probe + `GET /api/v1/health/fee-discount`, frontend Swap warning banner, docs/skills. Merge-conflict resolution with `main` (`poller.rs` import combine, `indexer-invariants.md` row merge). No smart-contract changes. **Outcome:** `FINDINGS: 0` medium+ ### Method - Full diff re-reviewed at current HEAD (post-merge with `main`). - Prior security thread on `8cc60b4` re-validated; no inline findings to carry forward. - Attacker-controlled input traced to sinks on all new/modified code paths. ### Areas examined | Vector | Result | |--------|--------| | **Injection / SSRF** | Probe uses operator-config `FEE_DISCOUNT_ADDRESS` and fixed `{"config":{}}` query via `LcdClient::query_contract`; health handler has no request parameters. No attacker-controlled input reaches LCD paths or SQL. | | **Authn / authz** | New route is read-only aggregate health (same class as `/health`); protected by global `tower_governor` via `apply_rate_limit_layer` on `api_router` (not LCD-heavy subset). | | **Information disclosure** | HTTP body limited to `configured`, `fee_discount_registry_ok`, `consecutive_lcd_failures`. Integration test asserts no LCD URLs, `cosmwasm` paths, or raw LCD error text in responses. Probe failure logs use existing `LcdError` formatting (server-side only). | | **XSS / CSRF** | Warning copy is a static React text node; no user/LCD-derived strings in the banner. GET endpoint is side-effect free. | | **Abuse / DoS** | Health handler is in-memory `RwLock` snapshot (no per-request LCD). Background probe capped at one query per 60s from configured address. | | **On-chain impact** | Documented fail-closed P5/I10 behavior unchanged; MR adds off-chain signals only. | | **Supply chain** | No new dependencies. | ### Inline threads None — no medium, high, or critical findings on this diff. --- Security review: no medium+ findings on this diff.
ghost1 commented 2026-06-12 08:37:38 +00:00 (Migrated from gitlab.com)
Stale Security Review comment
Stale Security Review comment

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
Bugbot Autofix is ON. A cloud agent has been kicked off to fix the reported issue.

Reviewed by Cursor Bugbot for commit 4d33747d7f. Configure here.

<details> <summary>Stale Security Review comment</summary> <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 [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 4d33747d7f1ccf24239f6e349b2ff394da096ca1. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> </details> </details>
ghost1 commented 2026-06-12 08:37:39 +00:00 (Migrated from gitlab.com)

Post-sign recovery only on timeout

High Severity

In the split sign-then-broadcast path, recovery polling runs only when RpcClient.broadcastTx or pollTx fails with the fixed timeout messages. Any other post-sign RPC error is thrown immediately even though a signed tx hash already exists, so the UI can clear isPending and invite another submit while the first broadcast may still land.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 4d33747d7f. Configure here.

### Post-sign recovery only on timeout **High Severity** <!-- DESCRIPTION START --> In the split sign-then-broadcast path, recovery polling runs only when `RpcClient.broadcastTx` or `pollTx` fails with the fixed timeout messages. Any other post-sign RPC error is thrown immediately even though a signed tx hash already exists, so the UI can clear `isPending` and invite another submit while the first broadcast may still land. <!-- DESCRIPTION END --> <!-- BUGBOT_BUG_ID: 31511079-1bd6-4d81-9c1a-505e965b4750 --> <!-- LOCATIONS START frontend-dapp/src/services/terraclassic/terraBroadcast.ts#L148-L171 LOCATIONS END --> <div><a href="https://cursor.com/open?link=eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9JTl9DVVJTT1IiLCJkYXRhIjp7InJlZGlzS2V5IjoiYnVnYm90OjQzNGRmZjdmLTA5ODctNDRmNy04MmM3LTUzYWQ1ZWRlMzFjYiIsImVuY3J5cHRpb25LZXkiOiIxa3lXMjlHS244Ny1ISGszYnlxTV9IandUVUZFdUFmQ0txVUh4WVRRM2k4IiwiYnJhbmNoIjoiaXNzdWUtMzY1LWZlZS1kaXNjb3VudC1yZWdpc3RyeS1vYnNlcnZhYmlsaXR5IiwicmVwb093bmVyIjoiUGxhc3RpY0RpZ2l0cyIsInJlcG9OYW1lIjoiY2w4eS1kZXgtdGVycmFjbGFzc2ljIn19" 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=eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9JTl9XRUIiLCJkYXRhIjp7InJlZGlzS2V5IjoiYnVnYm90OjQzNGRmZjdmLTA5ODctNDRmNy04MmM3LTUzYWQ1ZWRlMzFjYiIsImVuY3J5cHRpb25LZXkiOiIxa3lXMjlHS244Ny1ISGszYnlxTV9IandUVUZFdUFmQ0txVUh4WVRRM2k4IiwiYnJhbmNoIjoiaXNzdWUtMzY1LWZlZS1kaXNjb3VudC1yZWdpc3RyeS1vYnNlcnZhYmlsaXR5IiwicmVwb093bmVyIjoiUGxhc3RpY0RpZ2l0cyIsInJlcG9OYW1lIjoiY2w4eS1kZXgtdGVycmFjbGFzc2ljIiwicHJOdW1iZXIiOjE1NiwiY29tbWl0U2hhIjoiNGQzMzc0N2Q3ZjFjY2YyNDIzOWY2ZTM0OWIyZmYzOTRkYTA5NmNhMSIsInByb3ZpZGVyIjoiZ2l0bGFiIiwiaG9zdG5hbWUiOiJnaXRsYWIuY29tIn19" 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 4d33747d7f1ccf24239f6e349b2ff394da096ca1. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup>
ghost1 commented 2026-06-12 08:40:59 +00:00 (Migrated from gitlab.com)

added 1 commit

  • 1154cb6f - fix(frontend): recover after any post-sign broadcast or poll RPC failure

Compare with previous version

added 1 commit <ul><li>1154cb6f - fix(frontend): recover after any post-sign broadcast or poll RPC failure</li></ul> [Compare with previous version](/PlasticDigits/cl8y-dex-terraclassic/-/merge_requests/156/diffs?diff_id=1848559344&start_sha=4d33747d7f1ccf24239f6e349b2ff394da096ca1)
ghost1 commented 2026-06-12 08:41:14 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
ghost1 commented 2026-06-12 08:42:34 +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 ON. A cloud agent has been kicked off to fix the reported issue.

Reviewed by Cursor Bugbot for commit 1154cb6ff3. 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 [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 1154cb6ff3d5b22443f66524a3b7680ca6c31542. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> </details>
ghost1 commented 2026-06-12 08:42:35 +00:00 (Migrated from gitlab.com)

Broadcast errors always enter recovery

Medium Severity

In the split sign/broadcast path, any RpcClient.broadcastTx failure is caught and handled like an ambiguous timeout: the UI moves to confirming and runs post-sign recovery. Synchronous RPC rejections that mean the tx was never accepted no longer propagate immediately, so users wait through the recovery window and lose the original error detail.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 1154cb6ff3. Configure here.

### Broadcast errors always enter recovery **Medium Severity** <!-- DESCRIPTION START --> In the split sign/broadcast path, any `RpcClient.broadcastTx` failure is caught and handled like an ambiguous timeout: the UI moves to `confirming` and runs post-sign recovery. Synchronous RPC rejections that mean the tx was never accepted no longer propagate immediately, so users wait through the recovery window and lose the original error detail. <!-- DESCRIPTION END --> <!-- BUGBOT_BUG_ID: cf6907cd-f025-4fbe-af44-e22cefa0baa9 --> <!-- LOCATIONS START frontend-dapp/src/services/terraclassic/terraBroadcast.ts#L139-L142 LOCATIONS END --> <div><a href="https://cursor.com/open?link=eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9JTl9DVVJTT1IiLCJkYXRhIjp7InJlZGlzS2V5IjoiYnVnYm90OjA4ZTQ4ZmEyLWRjNDYtNDY3My04ODY3LTkzYTM3MzI4NWRlNSIsImVuY3J5cHRpb25LZXkiOiJVdllqLV81bWxRZmN5N2NzNExYZFRHLVFMQ0g2c1lsY1pmQ1NPbURKVVdnIiwiYnJhbmNoIjoiaXNzdWUtMzY1LWZlZS1kaXNjb3VudC1yZWdpc3RyeS1vYnNlcnZhYmlsaXR5IiwicmVwb093bmVyIjoiUGxhc3RpY0RpZ2l0cyIsInJlcG9OYW1lIjoiY2w4eS1kZXgtdGVycmFjbGFzc2ljIn19" 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=eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9JTl9XRUIiLCJkYXRhIjp7InJlZGlzS2V5IjoiYnVnYm90OjA4ZTQ4ZmEyLWRjNDYtNDY3My04ODY3LTkzYTM3MzI4NWRlNSIsImVuY3J5cHRpb25LZXkiOiJVdllqLV81bWxRZmN5N2NzNExYZFRHLVFMQ0g2c1lsY1pmQ1NPbURKVVdnIiwiYnJhbmNoIjoiaXNzdWUtMzY1LWZlZS1kaXNjb3VudC1yZWdpc3RyeS1vYnNlcnZhYmlsaXR5IiwicmVwb093bmVyIjoiUGxhc3RpY0RpZ2l0cyIsInJlcG9OYW1lIjoiY2w4eS1kZXgtdGVycmFjbGFzc2ljIiwicHJOdW1iZXIiOjE1NiwiY29tbWl0U2hhIjoiMTE1NGNiNmZmM2Q1YjIyNDQzZjY2NTI0YTNiNzY4MGNhNmMzMTU0MiIsInByb3ZpZGVyIjoiZ2l0bGFiIiwiaG9zdG5hbWUiOiJnaXRsYWIuY29tIn19" 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 1154cb6ff3d5b22443f66524a3b7680ca6c31542. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup>
ghost1 commented 2026-06-12 08:45:03 +00:00 (Migrated from gitlab.com)

added 1 commit

  • 5604ea9a - fix(frontend): re-throw non-timeout split-path broadcast errors

Compare with previous version

added 1 commit <ul><li>5604ea9a - fix(frontend): re-throw non-timeout split-path broadcast errors</li></ul> [Compare with previous version](/PlasticDigits/cl8y-dex-terraclassic/-/merge_requests/156/diffs?diff_id=1848567824&start_sha=1154cb6ff3d5b22443f66524a3b7680ca6c31542)
ghost1 commented 2026-06-12 08:45:20 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
ghost1 commented 2026-06-12 08:46:35 +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 5604ea9a1a. 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=eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9BTExfSU5fQ1VSU09SIiwiZGF0YSI6eyJyZWRpc0tleSI6ImJ1Z2JvdC1tdWx0aTo0MzZjNmNjNi0zYzMyLTQwYzItOTdjYS1iMDgxM2YzZjA0ZmEiLCJlbmNyeXB0aW9uS2V5IjoiRnJFWlVtbFVrNXE5S3JyS3p3bXdSNHg3RFQwNE9YSnBtNFBwTVBuS0c5VSIsImJyYW5jaCI6Imlzc3VlLTM2NS1mZWUtZGlzY291bnQtcmVnaXN0cnktb2JzZXJ2YWJpbGl0eSIsInJlcG9Pd25lciI6IlBsYXN0aWNEaWdpdHMiLCJyZXBvTmFtZSI6ImNsOHktZGV4LXRlcnJhY2xhc3NpYyJ9fQ" 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 5604ea9a1aee2594a4921611714eaea804976580. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup>
ghost1 commented 2026-06-12 08:46:36 +00:00 (Migrated from gitlab.com)

Post-sign broadcast skips recovery

Medium Severity

After a successful sign on the split broadcast path, only errors whose message exactly matches the broadcast/poll timeout strings enter recoverPostSignBroadcast. Other RpcClient.broadcastTx rejections (typical RPC or network failures) propagate immediately, so the UI can invite retry while a signed transaction may still be in flight—unlike the poll step, which still recovers on any error per GitLab #359.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 5604ea9a1a. Configure here.

### Post-sign broadcast skips recovery **Medium Severity** <!-- DESCRIPTION START --> After a successful sign on the split broadcast path, only errors whose message exactly matches the broadcast/poll timeout strings enter `recoverPostSignBroadcast`. Other `RpcClient.broadcastTx` rejections (typical RPC or network failures) propagate immediately, so the UI can invite retry while a signed transaction may still be in flight—unlike the poll step, which still recovers on any error per GitLab #359. <!-- DESCRIPTION END --> <!-- BUGBOT_BUG_ID: 05095d46-3d76-4fd1-85fe-7bd41c725475 --> <!-- LOCATIONS START frontend-dapp/src/services/terraclassic/terraBroadcast.ts#L146-L152 LOCATIONS END --> <div><a href="https://cursor.com/open?link=eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9JTl9DVVJTT1IiLCJkYXRhIjp7InJlZGlzS2V5IjoiYnVnYm90OjQ4ZTU1NWZkLTE1NzgtNGY2Ni05YTIwLWZjNjliMDg0N2U3NCIsImVuY3J5cHRpb25LZXkiOiI2bS05bjZWU2tJd01RczVqd0FDMFpBdnhWRlJXRDVMSDRRcGpma3o1ak1zIiwiYnJhbmNoIjoiaXNzdWUtMzY1LWZlZS1kaXNjb3VudC1yZWdpc3RyeS1vYnNlcnZhYmlsaXR5IiwicmVwb093bmVyIjoiUGxhc3RpY0RpZ2l0cyIsInJlcG9OYW1lIjoiY2w4eS1kZXgtdGVycmFjbGFzc2ljIn19" 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=eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9JTl9XRUIiLCJkYXRhIjp7InJlZGlzS2V5IjoiYnVnYm90OjQ4ZTU1NWZkLTE1NzgtNGY2Ni05YTIwLWZjNjliMDg0N2U3NCIsImVuY3J5cHRpb25LZXkiOiI2bS05bjZWU2tJd01RczVqd0FDMFpBdnhWRlJXRDVMSDRRcGpma3o1ak1zIiwiYnJhbmNoIjoiaXNzdWUtMzY1LWZlZS1kaXNjb3VudC1yZWdpc3RyeS1vYnNlcnZhYmlsaXR5IiwicmVwb093bmVyIjoiUGxhc3RpY0RpZ2l0cyIsInJlcG9OYW1lIjoiY2w4eS1kZXgtdGVycmFjbGFzc2ljIiwicHJOdW1iZXIiOjE1NiwiY29tbWl0U2hhIjoiNTYwNGVhOWExYWVlMjU5NGE0OTIxNjExNzE0ZWFlYTgwNDk3NjU4MCIsInByb3ZpZGVyIjoiZ2l0bGFiIiwiaG9zdG5hbWUiOiJnaXRsYWIuY29tIn19" 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 5604ea9a1aee2594a4921611714eaea804976580. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup>
ghost1 commented 2026-06-12 08:46:37 +00:00 (Migrated from gitlab.com)

Post-sign broadcast skips recovery

Medium Severity

After a successful sign on the split broadcast path, only errors whose message exactly matches the broadcast/poll timeout strings enter recoverPostSignBroadcast. Other RpcClient.broadcastTx rejections (typical RPC or network failures) propagate immediately, so the UI can invite retry while a signed transaction may still be in flight—unlike the poll step, which still recovers on any error per GitLab #359.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 5604ea9a1a. Configure here.

### Post-sign broadcast skips recovery **Medium Severity** <!-- DESCRIPTION START --> After a successful sign on the split broadcast path, only errors whose message exactly matches the broadcast/poll timeout strings enter `recoverPostSignBroadcast`. Other `RpcClient.broadcastTx` rejections (typical RPC or network failures) propagate immediately, so the UI can invite retry while a signed transaction may still be in flight—unlike the poll step, which still recovers on any error per GitLab #359. <!-- DESCRIPTION END --> <!-- BUGBOT_BUG_ID: 05095d46-3d76-4fd1-85fe-7bd41c725475 --> <!-- LOCATIONS START frontend-dapp/src/services/terraclassic/terraBroadcast.ts#L146-L152 LOCATIONS END --> <div><a href="https://cursor.com/open?link=eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9JTl9DVVJTT1IiLCJkYXRhIjp7InJlZGlzS2V5IjoiYnVnYm90OjQ4ZTU1NWZkLTE1NzgtNGY2Ni05YTIwLWZjNjliMDg0N2U3NCIsImVuY3J5cHRpb25LZXkiOiI2bS05bjZWU2tJd01RczVqd0FDMFpBdnhWRlJXRDVMSDRRcGpma3o1ak1zIiwiYnJhbmNoIjoiaXNzdWUtMzY1LWZlZS1kaXNjb3VudC1yZWdpc3RyeS1vYnNlcnZhYmlsaXR5IiwicmVwb093bmVyIjoiUGxhc3RpY0RpZ2l0cyIsInJlcG9OYW1lIjoiY2w4eS1kZXgtdGVycmFjbGFzc2ljIn19" 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=eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9JTl9XRUIiLCJkYXRhIjp7InJlZGlzS2V5IjoiYnVnYm90OjQ4ZTU1NWZkLTE1NzgtNGY2Ni05YTIwLWZjNjliMDg0N2U3NCIsImVuY3J5cHRpb25LZXkiOiI2bS05bjZWU2tJd01RczVqd0FDMFpBdnhWRlJXRDVMSDRRcGpma3o1ak1zIiwiYnJhbmNoIjoiaXNzdWUtMzY1LWZlZS1kaXNjb3VudC1yZWdpc3RyeS1vYnNlcnZhYmlsaXR5IiwicmVwb093bmVyIjoiUGxhc3RpY0RpZ2l0cyIsInJlcG9OYW1lIjoiY2w4eS1kZXgtdGVycmFjbGFzc2ljIiwicHJOdW1iZXIiOjE1NiwiY29tbWl0U2hhIjoiNTYwNGVhOWExYWVlMjU5NGE0OTIxNjExNzE0ZWFlYTgwNDk3NjU4MCIsInByb3ZpZGVyIjoiZ2l0bGFiIiwiaG9zdG5hbWUiOiJnaXRsYWIuY29tIn19" 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 5604ea9a1aee2594a4921611714eaea804976580. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup>
ghost1 commented 2026-06-12 08:49:20 +00:00 (Migrated from gitlab.com)

changed this line in version 5 of the diff

changed this line in [version 5 of the diff](/PlasticDigits/cl8y-dex-terraclassic/-/merge_requests/156/diffs?diff_id=1848577279&start_sha=5604ea9a1aee2594a4921611714eaea804976580#88a78c528e591acd067c08a37205eb540c7324f2_150_140)
ghost1 commented 2026-06-12 08:49:20 +00:00 (Migrated from gitlab.com)

added 1 commit

  • 77881360 - fix(frontend): recover after any post-sign broadcast RPC failure (#359)

Compare with previous version

added 1 commit <ul><li>77881360 - fix(frontend): recover after any post-sign broadcast RPC failure (#359)</li></ul> [Compare with previous version](/PlasticDigits/cl8y-dex-terraclassic/-/merge_requests/156/diffs?diff_id=1848577279&start_sha=5604ea9a1aee2594a4921611714eaea804976580)
ghost1 commented 2026-06-12 08:49:34 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
PlasticDigits commented 2026-06-12 11:06:57 +00:00 (Migrated from gitlab.com)

added 1 commit

  • 4d1570b7 - fix(frontend): narrow post-sign broadcast recovery to ambiguous RPC errors

Compare with previous version

added 1 commit <ul><li>4d1570b7 - fix(frontend): narrow post-sign broadcast recovery to ambiguous RPC errors</li></ul> [Compare with previous version](/PlasticDigits/cl8y-dex-terraclassic/-/merge_requests/156/diffs?diff_id=1848871248&start_sha=778813600a9320a65a8ad4a5bce501e347685d2b)
PlasticDigits commented 2026-06-12 11:07:03 +00:00 (Migrated from gitlab.com)

Security fix summary (4d1570b)

Finding Severity Resolution
Post-sign recovery only on timeout High Already addressed in 1154cb6 / 7788136; split-path broadcast now enters recovery for ambiguous post-sign RPC failures (not only timeout strings).
Post-sign broadcast skips recovery Medium Same — ambiguous RPC/network errors after sign route through recoverPostSignBroadcast so submit stays disabled until deadline poll completes (#359).
Broadcast errors always enter recovery Medium Fixed in 4d1570b: added isDefiniteBroadcastRejection / shouldRecoverPostSignBroadcast so CheckTx rejections (sequence mismatch, invalid tx, fee/auth validation, etc.) re-throw immediately; ambiguous failures (timeout, 502, tx already exists in cache) still recover. Poll step unchanged — any poll error still recovers per #359.
#365 fee-discount observability (indexer health, Swap banner) — No open low+ findings from prior security reviews (8cc60b4, 4d33747).

Tests: make test-frontend (includes new terraBroadcastRecovery cases for ambiguous vs definite broadcast errors).

## Security fix summary (`4d1570b`) | Finding | Severity | Resolution | |---------|----------|------------| | **Post-sign recovery only on timeout** | High | Already addressed in `1154cb6` / `7788136`; split-path broadcast now enters recovery for ambiguous post-sign RPC failures (not only timeout strings). | | **Post-sign broadcast skips recovery** | Medium | Same — ambiguous RPC/network errors after sign route through `recoverPostSignBroadcast` so submit stays disabled until deadline poll completes (#359). | | **Broadcast errors always enter recovery** | Medium | Fixed in `4d1570b`: added `isDefiniteBroadcastRejection` / `shouldRecoverPostSignBroadcast` so CheckTx rejections (sequence mismatch, invalid tx, fee/auth validation, etc.) re-throw immediately; ambiguous failures (timeout, 502, `tx already exists in cache`) still recover. Poll step unchanged — any poll error still recovers per #359. | | **#365 fee-discount observability** (indexer health, Swap banner) | — | No open low+ findings from prior security reviews (`8cc60b4`, `4d33747`). | **Tests:** `make test-frontend` (includes new `terraBroadcastRecovery` cases for ambiguous vs definite broadcast errors).
ghost1 commented 2026-06-12 11:07:12 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
PlasticDigits commented 2026-06-12 11:09:14 +00:00 (Migrated from gitlab.com)

Security review — MR !874 (re-review)

Commit reviewed: 4d1570b7e7c16d708eb172e8da905f433d1c944e
Scope: Off-chain observability for fee-discount registry LCD outages (#365) — indexer background config probe + GET /api/v1/health/fee-discount, frontend Swap warning banner, docs/skills. Also includes post-merge terraBroadcast.ts post-sign recovery narrowing (isDefiniteBroadcastRejection / shouldRecoverPostSignBroadcast, #359). No smart-contract changes.

Outcome: FINDINGS: 0 medium+

Method

  • Full diff re-reviewed at current HEAD (includes 4d1570b broadcast-recovery fix atop prior #365 work).
  • Prior security threads on 8cc60b4 and 4d33747 re-validated; Bugbot broadcast-recovery threads assessed against current code — over-broad recovery from intermediate commits is resolved; remaining behavior is duplicate-submit mitigation, not an exploitable regression.
  • Attacker-controlled input traced to sinks on all new/modified code paths.

Areas examined

Vector Result
Injection / SSRF Probe uses operator-config FEE_DISCOUNT_ADDRESS and fixed {"config":{}} query via LcdClient::query_contract; health handler has no request parameters. No attacker-controlled input reaches LCD paths or SQL.
Authn / authz New route is read-only aggregate health (same class as /health); protected by global tower_governor via apply_rate_limit_layer on api_router (not LCD-heavy subset).
Information disclosure HTTP body limited to configured, fee_discount_registry_ok, consecutive_lcd_failures. Integration test asserts no LCD URLs, cosmwasm paths, or raw LCD error text in responses. Probe failure logs use existing LcdError formatting (server-side only).
XSS / CSRF Warning copy is a static React text node; no user/LCD-derived strings in the banner. GET endpoint is side-effect free.
Abuse / DoS Health handler is in-memory RwLock snapshot (no per-request LCD). Background probe capped at one query per 60s from configured address.
Client tx safety Post-sign recovery triggers only on ambiguous RPC/broadcast failures; definite CheckTx rejections (sequence mismatch, bad sig, insufficient fee, etc.) fail fast without recovery polling — reduces duplicate-submit window vs timeout-only recovery without opening a remote exploit path.
On-chain impact Documented fail-closed P5/I10 behavior unchanged; MR adds off-chain signals only.
Supply chain No new dependencies.

Inline threads

None — no medium, high, or critical findings on this diff.


Security review: no medium+ findings on this diff.

## Security review — MR !874 (re-review) **Commit reviewed:** `4d1570b7e7c16d708eb172e8da905f433d1c944e` **Scope:** Off-chain observability for fee-discount registry LCD outages (#365) — indexer background `config` probe + `GET /api/v1/health/fee-discount`, frontend Swap warning banner, docs/skills. Also includes post-merge `terraBroadcast.ts` post-sign recovery narrowing (`isDefiniteBroadcastRejection` / `shouldRecoverPostSignBroadcast`, #359). No smart-contract changes. **Outcome:** `FINDINGS: 0` medium+ ### Method - Full diff re-reviewed at current HEAD (includes `4d1570b` broadcast-recovery fix atop prior #365 work). - Prior security threads on `8cc60b4` and `4d33747` re-validated; Bugbot broadcast-recovery threads assessed against current code — over-broad recovery from intermediate commits is resolved; remaining behavior is duplicate-submit mitigation, not an exploitable regression. - Attacker-controlled input traced to sinks on all new/modified code paths. ### Areas examined | Vector | Result | |--------|--------| | **Injection / SSRF** | Probe uses operator-config `FEE_DISCOUNT_ADDRESS` and fixed `{"config":{}}` query via `LcdClient::query_contract`; health handler has no request parameters. No attacker-controlled input reaches LCD paths or SQL. | | **Authn / authz** | New route is read-only aggregate health (same class as `/health`); protected by global `tower_governor` via `apply_rate_limit_layer` on `api_router` (not LCD-heavy subset). | | **Information disclosure** | HTTP body limited to `configured`, `fee_discount_registry_ok`, `consecutive_lcd_failures`. Integration test asserts no LCD URLs, `cosmwasm` paths, or raw LCD error text in responses. Probe failure logs use existing `LcdError` formatting (server-side only). | | **XSS / CSRF** | Warning copy is a static React text node; no user/LCD-derived strings in the banner. GET endpoint is side-effect free. | | **Abuse / DoS** | Health handler is in-memory `RwLock` snapshot (no per-request LCD). Background probe capped at one query per 60s from configured address. | | **Client tx safety** | Post-sign recovery triggers only on ambiguous RPC/broadcast failures; definite CheckTx rejections (sequence mismatch, bad sig, insufficient fee, etc.) fail fast without recovery polling — reduces duplicate-submit window vs timeout-only recovery without opening a remote exploit path. | | **On-chain impact** | Documented fail-closed P5/I10 behavior unchanged; MR adds off-chain signals only. | | **Supply chain** | No new dependencies. | ### Inline threads None — no medium, high, or critical findings on this diff. --- Security review: no medium+ findings on this diff.
PlasticDigits commented 2026-06-12 11:12:57 +00:00 (Migrated from gitlab.com)

mentioned in commit d0a75849a1

mentioned in commit d0a75849a1f13b55cbd26eedb51093c498212491
PlasticDigits (Migrated from gitlab.com) merged commit d0a75849a1 into main 2026-06-12 11:12:58 +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!874
No description provided.