Security: validate explorer URL segments before interpolation (#430) #958

Merged
PlasticDigits merged 1 commit from fix/430-explorer-url-sanitization into main 2026-06-29 15:18:04 +00:00
PlasticDigits commented 2026-06-29 15:17:07 +00:00 (Migrated from gitlab.com)

Summary

Fixes #430 (SEC-E10): getExplorerTxUrl and getExplorerAddressUrl now reject unsafe inputs before interpolating them into URL templates.

  • Tx hash: must be a 64-character hex digest (RPC/LCD format); otherwise returns null.
  • Address: must pass Terra bech32 validation; otherwise returns null.
  • Components already hide explorer links when the helper returns null, so spoofed indexer data cannot produce javascript: or HTML-injected href values.
  • Added adversarial unit tests, link-rendering tests, and documented invariants in docs/frontend.md and skills/AGENTS_FRONTEND_TERRA_EXPLORER.md.

Acceptance checklist

Criterion Verification Result
terraExplorer.test.ts rejects javascript: prefix (output is not a javascript: URL) bash scripts/with-node.sh --cwd frontend-dapp -- npm test -- src/utils/__tests__/terraExplorer.test.ts -t "javascript" PASS
terraExplorer.test.ts rejects HTML-special characters in tx hash or address bash scripts/with-node.sh --cwd frontend-dapp -- npm test -- src/utils/__tests__/terraExplorer.test.ts -t "HTML-special" PASS
Link rendering tests assert safe href under adversarial input (or document React defense) bash scripts/with-node.sh --cwd frontend-dapp -- npm test -- src/components/ui/__tests__/AddressRow.explorerSafety.test.tsx src/components/ui/__tests__/TerraBroadcastPendingLink.test.tsx -t "explorer link safety" PASS
Builder rejection behavior explicitly tested bash scripts/with-node.sh --cwd frontend-dapp -- npm test -- src/utils/__tests__/terraExplorer.test.ts -t "adversarial" PASS

Third-party verification

# Unit + link-rendering tests for #430
bash scripts/with-node.sh --cwd frontend-dapp -- npm test -- \
  src/utils/__tests__/terraExplorer.test.ts \
  src/components/ui/__tests__/AddressRow.explorerSafety.test.tsx \
  src/components/ui/__tests__/TerraBroadcastPendingLink.test.tsx

# Full frontend suite (includes WalletButton fix for valid bech32 test address)
bash scripts/with-node.sh --cwd frontend-dapp -- npm test -- --run

Inspect frontend-dapp/src/utils/terraExplorer.ts — both public helpers return null when isSafeExplorerTxHash / isSafeExplorerAddress fail.

Docs: docs/frontend.md § Terra Classic block explorer URLs · skills/AGENTS_FRONTEND_TERRA_EXPLORER.md rule 6.

## Summary Fixes [#430](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/430) (SEC-E10): `getExplorerTxUrl` and `getExplorerAddressUrl` now reject unsafe inputs before interpolating them into URL templates. - **Tx hash:** must be a 64-character hex digest (RPC/LCD format); otherwise returns `null`. - **Address:** must pass Terra bech32 validation; otherwise returns `null`. - Components already hide explorer links when the helper returns `null`, so spoofed indexer data cannot produce `javascript:` or HTML-injected `href` values. - Added adversarial unit tests, link-rendering tests, and documented invariants in `docs/frontend.md` and `skills/AGENTS_FRONTEND_TERRA_EXPLORER.md`. ## Acceptance checklist | Criterion | Verification | Result | |-----------|--------------|--------| | `terraExplorer.test.ts` rejects `javascript:` prefix (output is not a `javascript:` URL) | `bash scripts/with-node.sh --cwd frontend-dapp -- npm test -- src/utils/__tests__/terraExplorer.test.ts -t "javascript"` | PASS | | `terraExplorer.test.ts` rejects HTML-special characters in tx hash or address | `bash scripts/with-node.sh --cwd frontend-dapp -- npm test -- src/utils/__tests__/terraExplorer.test.ts -t "HTML-special"` | PASS | | Link rendering tests assert safe `href` under adversarial input (or document React defense) | `bash scripts/with-node.sh --cwd frontend-dapp -- npm test -- src/components/ui/__tests__/AddressRow.explorerSafety.test.tsx src/components/ui/__tests__/TerraBroadcastPendingLink.test.tsx -t "explorer link safety"` | PASS | | Builder rejection behavior explicitly tested | `bash scripts/with-node.sh --cwd frontend-dapp -- npm test -- src/utils/__tests__/terraExplorer.test.ts -t "adversarial"` | PASS | ## Third-party verification ```bash # Unit + link-rendering tests for #430 bash scripts/with-node.sh --cwd frontend-dapp -- npm test -- \ src/utils/__tests__/terraExplorer.test.ts \ src/components/ui/__tests__/AddressRow.explorerSafety.test.tsx \ src/components/ui/__tests__/TerraBroadcastPendingLink.test.tsx # Full frontend suite (includes WalletButton fix for valid bech32 test address) bash scripts/with-node.sh --cwd frontend-dapp -- npm test -- --run ``` Inspect `frontend-dapp/src/utils/terraExplorer.ts` — both public helpers return `null` when `isSafeExplorerTxHash` / `isSafeExplorerAddress` fail. Docs: `docs/frontend.md` § Terra Classic block explorer URLs · `skills/AGENTS_FRONTEND_TERRA_EXPLORER.md` rule 6.
PlasticDigits commented 2026-06-29 15:18:04 +00:00 (Migrated from gitlab.com)

mentioned in commit 8a7e7adda1

mentioned in commit 8a7e7adda1fefecb2792daa7e5ed1370d0178381
PlasticDigits (Migrated from gitlab.com) merged commit 8a7e7adda1 into main 2026-06-29 15:18:04 +00:00
PlasticDigits commented 2026-06-29 15:19:21 +00:00 (Migrated from gitlab.com)

Security review — MR !958

Commit reviewed: 7e28b26b96a88bc4b2496a3fe960758126f7d3f5
Scope: terraExplorer.ts segment validation (isSafeExplorerTxHash / isSafeExplorerAddress), consumer components (AddressRow, TerraBroadcastPendingLink, TxResultAlert, TradesTable, WalletIndexerHistoryPanel, WalletDropdownMenuItems), adversarial unit/link tests, docs/skills updates.

Outcome: FINDINGS: 0 medium+

Security review: no medium+ findings on this diff.

Analysis summary

This MR closes SEC-E10 (#430) by validating attacker-influenced segments before URL interpolation:

Sink Control Effect on spoofed indexer / API data
getExplorerTxUrl /^[0-9a-fA-F]{64}$/ Rejects javascript:, HTML specials, path traversal, empty — returns null
getExplorerAddressUrl Terra bech32 (isValidTerraBech32Address) Charset excludes :, /, <, >; rejects non-terra prefixes — returns null

Attack-path tracing: Indexer-returned tx_hash / address fields are the primary untrusted input. All explorer href sinks route through the two helpers above; components render anchors only when the helper returns non-null, otherwise plain <span> (verified in AddressRow.explorerSafety.test.tsx, TerraBroadcastPendingLink.test.tsx). No alternate explorer-URL builders were introduced.

Residual notes (informational, below medium): React href sanitization remains a secondary layer. isSafeExplorerAddress validates trim() but interpolates the raw address argument — whitespace padding could produce a malformed explorer URL but not scheme injection or XSS.

Tests run: adversarial + link-safety vitest targets — PASS.

No inline threads (no medium+ findings).

## Security review — MR !958 **Commit reviewed:** `7e28b26b96a88bc4b2496a3fe960758126f7d3f5` **Scope:** `terraExplorer.ts` segment validation (`isSafeExplorerTxHash` / `isSafeExplorerAddress`), consumer components (`AddressRow`, `TerraBroadcastPendingLink`, `TxResultAlert`, `TradesTable`, `WalletIndexerHistoryPanel`, `WalletDropdownMenuItems`), adversarial unit/link tests, docs/skills updates. **Outcome:** `FINDINGS: 0` medium+ Security review: no medium+ findings on this diff. ### Analysis summary This MR closes SEC-E10 ([#430](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/430)) by validating attacker-influenced segments **before** URL interpolation: | Sink | Control | Effect on spoofed indexer / API data | |------|---------|--------------------------------------| | `getExplorerTxUrl` | `/^[0-9a-fA-F]{64}$/` | Rejects `javascript:`, HTML specials, path traversal, empty — returns `null` | | `getExplorerAddressUrl` | Terra bech32 (`isValidTerraBech32Address`) | Charset excludes `:`, `/`, `<`, `>`; rejects non-`terra` prefixes — returns `null` | **Attack-path tracing:** Indexer-returned `tx_hash` / address fields are the primary untrusted input. All explorer `href` sinks route through the two helpers above; components render anchors only when the helper returns non-`null`, otherwise plain `<span>` (verified in `AddressRow.explorerSafety.test.tsx`, `TerraBroadcastPendingLink.test.tsx`). No alternate explorer-URL builders were introduced. **Residual notes (informational, below medium):** React `href` sanitization remains a secondary layer. `isSafeExplorerAddress` validates `trim()` but interpolates the raw `address` argument — whitespace padding could produce a malformed explorer URL but not scheme injection or XSS. **Tests run:** adversarial + link-safety vitest targets — PASS. No inline threads (no medium+ findings).
Brouie commented 2026-06-29 15:20:23 +00:00 (Migrated from gitlab.com)

mentioned in issue #430

mentioned in issue #430
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!958
No description provided.