fix(api): enforce CORS, trusted rate limits, safe errors and production network boundaries #41
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Scope and source
Priority: P1. Gap coverage: GAP-006, GAP-018, GAP-020, GAP-021. Derived from GAP_1791945837.md, reviewed code commit
f8dbe93df953a78b17cb3304b717dcf84c4cd517. Currente476a68da09645c2308cbf47b90211fcaffcb7afadds only the report, so implementation findings remain applicable. Report evidence is local reproduction/source inspection unless explicitly proposed; no production exploit or current live-readiness claim.Coverage and sequencing: gap backlog tracker. Workstream 06. Dependencies: 05.
Current codebase
PUT amendments are absent from allowed CORS methods and IP limits. Invalid configured origins are discarded. First X-Forwarded-For values are trusted by default without peer CIDRs; buckets have no cleanup and are per replica. RPC/LCD errors include credential-bearing URLs and API errors expose raw SQL text. API/ledger run-mode spellings differ; dev chain IDs and some simulated-wallet/build flags remain accepted in production.
Why this implementation is needed
Cross-origin drafting fails, spoofed headers may evade limits, errors may leak secrets, and ambiguous build/runtime modes weaken deployment separation.
Relevant files
operator-voting/src/main.rsoperator-voting/src/config.rsoperator-voting/src/rate_limit.rsoperator-voting/src/error.rsoperator-voting/src/payload.rsledger/src/config.rsledger/src/lcd.rsledger/src/bsc.rsledger/src/register.rsfrontend/src/utils/prodEnvGuards.tsfrontend/vite.config.tsoperator-voting/tests/api_flow.rsRecommended solution
Create a testable production application factory including middleware. Allow PUT with exact validated origins; fail startup for malformed configuration. Trust forwarded chains only from explicit proxy peers with documented edge header replacement/private ingress. Cover every mutation with bounded IP plus action/wallet controls and eviction; define multi-replica aggregate enforcement. Remove URLs from transport errors, use safe provider labels and request-correlated stable public error codes. Validate run-mode/network enums consistently and reject localterra/31337, simulated wallets, forbidden browser RPC flags and missing/insecure production API URLs across Docker, direct and custom-mode builds.
Constraints and guardrails
Preserve standalone offchain advisory voting, no new smart contracts or archive-node dependency, BSC as a core electorate, raw 18-decimal integer balances and separate Terra/BSC address identities. Keep Legal fail-closed transactional UI and the proven DEX Terra/Bridge EVM connectors; no browser BSC balance RPC, seed/key prompt or embedded admin/model credential. API must retain a restricted role separate from the ledger writer. Freeze at actual opening, never at draft creation or a client-supplied height. Agents own design, implementation, review and evidence under repository guidance; do not shift approvals/tests to the human or invent PASS evidence.
Acceptance criteria
Allowed-origin PUT preflight and actual browser amend succeed; disallowed origins/headers/methods remain rejected. Spoofing untrusted forwarded headers cannot change buckets. All mutations are limited with recoverable Retry-After behavior. Fake sentinel credentials never appear in logs/responses. Every production-equivalent mode applies the same network and build rules.
Test plan: supported paths, failure paths and concurrency
Real middleware GET/POST/PUT/OPTIONS, allowed/disallowed/null origins, malformed origin configuration and body limits. Trusted/untrusted proxy hop chains, direct access, IPv4/IPv6, bursts, expiry/cleanup and replicas. Provider timeout/HTTP/JSON and DB errors with sentinel credentials. Mode spellings, missing configuration, custom build modes, local/dev versus mainnet, HTTPS/API URL rules. Browser test against a second-origin local API.
Test plan: attack, hack and abuse vectors
XFF spoofing, huge/malformed proxy headers, per-route PUT floods, unique-IP bucket exhaustion, CORS reflection and development-chain signature replay in production; error-induced URL/query/basic-auth leakage. Inspect trusted edge behavior rather than assuming live topology; abuse tests must stay isolated.
Verification and completion criteria
Attach real preflight/browser results, spoofing/quota tests, log/response sentinel scan and production build rejection matrix. Verify deployed proxy topology with dated evidence when releasing; router-only tests are insufficient.
Record commit and pinned toolchain, commands/results and sanitized artifacts. Relevant Rust changes require
cargo test --workspace --libplus isolated Postgres integration (explicit guarded LEDGER_TEST_DATABASE_URL); frontend changes requirenpm testand production build plus relevant browser cases. Run secret scanning for new fixtures/config. Exercise fresh/upgrade migrations when schema/grants change; report skipped/live-only checks explicitly.Implementation status after main merge PR #53, commit
cd07f00f32f04ad02f8b760ed34588fd9645919e:Services are paused while existing storage is audited and the corrected pinned release is prepared. No production wallet transaction or hardware-wallet/Legal QA is claimed. This is an interim report; the issue remains open and the final comment will map the original criteria to actual live results and any unverified cases.
Implemented the API boundary fixes through PRs #53/#54 and subsequent followups. Accepted release:
5cd9363307dc1607de952ac3243193c1a16304c7at 2026-10-14T14:07:21Z, after PR #59 merged with CI passing. Implementation and verification evidence and documented invariants/agent guidance.10.0.17.2was observed and only10.0.17.2/32was trusted. An isolated 2-token maintenance quota with changing spoofed XFF values produced 200, 200, 429. The rejection had a stable code, matching response/header request ID and Retry-After:29; health stayed 200 and the same action succeeded after the advertised wait. Topology and evidence.prod/productionenforce mainnet network domains; genuine signed localterra/31337 and v1/unsupported-version mutation attempts fail through the real factory. Direct production/custom-release Vite builds reject 18 invalid cases. The actual Dockerfile builds valid configuration and rejects nine invalid configurations with recognizable guard reasons; pull/network/install failures do not count as rejection proof. Docker evidence./32proxy peer and one API instance. Three private readiness windows (240+240+600 =1080 observations) all passed, with maximum Terra lag 2 and BSC lag 17. The two final public windows passed 45/45 each. Loki and direct Coolify logs show no ledger warnings after activation at 13:58:22Z; the old 13:56:21Zrpc_missing_resultwarning preceded activation.Verification: Rust 1.88.0, locked dependencies and fresh guarded PostgreSQL16/SCRAM infrastructure; command
CARGO_BUILD_JOBS=2 scripts/verify-release.sh. Release13 passed 74 unit/supervisor tests, 121 integration tests (66 ledger hardening), 245 schema-validated API responses and 146 frontend tests, plus production build, both nginx checks and Gitleaks. Separate Chromium evidence: 11 UI regressions, nine hostile-rendering tests and one real second-origin protocol test, using Node24.21.0, Playwright1.62.1 and Chromium151.0.7922.34.Release12 was a failed historical run; the expected late-supervisor-exit fixture race was corrected without weakening financial assertions, then passed four fresh-database repetitions and the full release13 rerun. Earlier public sampling recorded one unexplained 503 at 14:00:58Z (44/45); the next check returned 200. It is retained in final live evidence rather than counted as a pass. The subsequent two extended public windows were fully green (90/90), alongside all 1080 private observations; acceptance is based on those final windows and does not claim transient failures are impossible.
The API retains its separate restricted database role; fresh/upgrade migrations, real restricted-login and inherited/function/column privilege regressions are included in the integration evidence. No arbitrary debug/wire-log safety, exhaustive route×status Cartesian matrix, funded-holder or hardware/mobile-wallet/real-Legal QA is claimed. The isolated browser Legal hatch does not weaken production Legal gating. All required issue criteria are checked against the evidence above; no mandatory verification item remains open.
Final evidence is published through PR #60. All mandatory body/comment criteria are satisfied by the checklist above; closing this issue.