Security (EVM-14): No eth_chainId verification; wrong-chain RPC would be read silently #12
Labels
No labels
enhancement
governance
QA
testing
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
code/ust1-window#12
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?
@PlasticDigits finding from security review on #5.
Severity
Low-to-Medium. Deployment footgun; misconfig rarely caught automatically.
Description
oracle-service/src/bsc.rsconstructs an Alloy provider fromrpc_urland immediately queriesexchangeRateStored:There is no
eth_chainIdcheck before theexchangeRateStoredcall. IfBSC_RPC_URLScontains a URL pointing at:callwould fail or return garbage from an EOA...the service treats the response as authoritative BSC mainnet data.
Why this matters
Combined with EVM-03 (no Venus address allowlist), a single misconfiguration (wrong RPC URL AND/OR wrong token address) produces a silently-wrong on-chain oracle rate. With CL8Y bridge's recent Terra classic hexxagon.dev mislabel (handoff #109 — returns
rebel-2testnet), misconfigured fallback URLs are a real class of incident.Recommendation
On provider creation, fetch
eth_chainIdand assert== 56:Cache the chainId per provider so the check isn't re-run every poll tick; fail immediately at service startup if any configured RPC URL misreports.
Related
mentioned in issue #5
Resolution (EVM-14 / chain-id verification)
Implemented in `oracle-service` (see `
673ac74` on `main`, plus follow-up `12051ea` rustfmt-only):`eth_chainId` check — After each HTTP provider is built, we call `get_chain_id()` and require it to match an allowlist. Results are cached per RPC URL (in-process `HashMap`) so we do not re-query chain id every poll tick.
Startup — `verify_all_bsc_rpc_urls` runs once at process start and validates every configured URL in `BSC_RPC_URLS`, so a misconfigured endpoint fails immediately.
`BSC_ALLOWED_CHAIN_IDS` — Comma-separated list; default is `56` (BSC mainnet only). For BSC Chapel testnet use `97`, for Anvil use `31337` (Foundry default). Example for mixed local/dev testing: `BSC_ALLOWED_CHAIN_IDS=56,97,31337`.
Canonical Venus vToken (glab #9) — Still enforced when the allowlist is mainnet-only (`[56]` only). If you allow testnet/local chain ids, any well-formed contract address is accepted so mocks work.
This closes the “wrong RPC URL silently returns wrong chain” footgun while keeping production strict (56 by default) and test/local workflows explicit via env.
@PlasticDigits verified fix on
673ac74— this was quietly addressed alongside the Debug redact commit.New functions in
oracle-service/src/bsc.rs:verify_bsc_rpc_chain_id— callsget_chain_id(), checks againstallowed_chain_ids, caches result per-URLverify_all_bsc_rpc_urls— startup check across every configured BSC_RPC_URLread_exchange_rate_storednow takesallowed_chain_idsand re-verifies before each call (defense in depth with cache)Config:
BSC_ALLOWED_CHAIN_IDSenv var (default "56" = BSC mainnet only)validate_venus_vtoken_addressonly requires canonical vFDUSD when allowed_chain_ids is exactly[56]— dev environments can bypass, production mainnet enforces strictlyWrong-chain RPC now fails fast at startup with clear error message. Closing.