Pre-launch: dev-mode zero rate limit with no non-loopback bind guard [SEC-I04] (F01) #458
Labels
No labels
agent:fix_bugfix
agent:fix_conflicts
agent:fix_security
agent:gap_analysis
agent:implement
agent:implement
agent:implement
agent:open_issues
agent:ready
agent:research
agent:security_audit
agent:verify
architecture
backend
blocker:hybrid
blocker:launch
blocker:limit-orders
blocker:v2
block:log_only
block:security
bug
ci
contracts
correctness
deploy
dev
devops
docs
documentation
duplicate
e2e
enhancement
epic
feature
frontend
functional-completion
gas
good first issue
governance
help wanted
high-risk
hooks
hybrid
indexer
infra
infrastructure
integrators
invalid
launch-blocker
limit-orders
localnet
localterra
low priority
missing-implementation
needs-design
ops
performance
priority
high
priority
medium
product
qa
QA
question
ready
ready
research
scripts
security
security-hardening
smartcontracts
tech-debt
testing
ux
UX
v2
verification
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
code/cl8y-dex-terraclassic#458
Loading…
Add table
Add a link
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?
Summary
When
RUN_MODEis unset (defaults to Dev) and bothRATE_LIMIT_RPSandRATE_LIMIT_LCD_HEAVY_RPSare set to 0, all rate governors are disabled with only atracing::warn!log entry. The indexer.envtemplate ships withRATE_LIMIT_RPS=0. If an operator deploys the indexer on a non-loopback bind address without settingRUN_MODE=prod, the entire API is unprotected with no hard refusal and no startup check.RUN_MODE=prodcorrectly clamps both values to 60 and 10 RPS respectively, but there is nothing in the Dev path to catch a misconfigured public deployment.What Was Checked
indexer/src/config.rslines 208-234: rate limit clamping logic.RUN_MODE=prodenforces minimums. Dev path emits only atracing::warn!when both are 0.indexer/.env: ships withRATE_LIMIT_RPS=0,RATE_LIMIT_LCD_HEAVY_RPS=10. The global layer is disabled in the template default.docs/operator-secrets.md: documents the dual-zero DoS-risk warning but does not require non-loopback check.Expected (per checklist)
If both rate limits are 0 and the API binds to a non-loopback address, the indexer emits an ERROR-level log and refuses to start (or requires an explicit
ALLOW_ZERO_RATE_LIMITS=1override to proceed). This prevents silent public deployments with no rate protection.Actual
Zero rate limit on a non-loopback bind address produces only a
tracing::warn!log and continues serving traffic unprotected.Suggested Fix
In
Config::from_env(), add a startup check: if bothRATE_LIMIT_RPSandRATE_LIMIT_LCD_HEAVY_RPSare 0 andapi_bindresolves to a non-loopback IP, emit anERROR-level log and refuse to start unlessALLOW_ZERO_RATE_LIMITS=1is explicitly set in env. Updatedocs/operator-secrets.mdto document the new opt-out.Verification Checklist
docs/operator-secrets.mdupdated to documentALLOW_ZERO_RATE_LIMITS=1opt-out if addedCc: @PlasticDigits
mentioned in issue #453
mentioned in issue #381
mentioned in merge request !983
mentioned in issue #451
Done.
RATE_LIMIT_RPS=0+RATE_LIMIT_LCD_HEAVY_RPS=0only logged awarn!— on a non-loopback bind that's an unthrottled public API.Added a startup guard in
Config::from_env(): in non-prod, if both limits are 0 ANDAPI_BINDis non-loopback, it refuses to start (ConfigError::ZeroRateLimitNonLoopbackBind) unlessALLOW_ZERO_RATE_LIMITS=1is set (the explicit opt-out for offline/benchmark runs). Prod already clamps both to 60/10 so the guard never fires there, and loopback binds (Playwright / local-dev / the QA indexer) keep working.bind_is_loopback()treats 127/8, ::1, and "localhost" as loopback and errs toward safety on anything else.Tests (new): non-loopback dual-zero rejected; opt-out allows it; loopback dual-zero loads; prod-clamp loads on a public bind. indexer lib 167/0.
Shipped with #451 in MR !983, branch
qa/451-458-indexer-config-guards, commit6ae40413. Needs review/merge @PlasticDigits — leaving open for verification.mentioned in commit
d326a2e188mentioned in commit
1c7f9b1c82mentioned in merge request !992
mentioned in commit
b1407f63d0mentioned in commit
b5752c20c5mentioned in merge request !996
Verification — #458 [SEC-I04] (F01) — PASS
Verified on
main(implementation from MR !983 /6ae40413).Checklist
0refuses start (or explicit opt-out)indexer/src/config.rs—Config::from_env()returnsConfigError::ZeroRateLimitNonLoopbackBindwhenRUN_MODE≠prod,RATE_LIMIT_RPS=0,RATE_LIMIT_LCD_HEAVY_RPS=0, non-loopbackAPI_BIND, andALLOW_ZERO_RATE_LIMITSunset. Runtime:cargo runwithAPI_BIND=0.0.0.0exits withConfiguration error: … set ALLOW_ZERO_RATE_LIMITS=1 to override.cargo test --lib config::tests::dev_dual_zero_rate_limits_nonloopback_bind_rejected— ok. Also: opt-out (ALLOW_ZERO_RATE_LIMITS=1), loopback dual-zero, and prod clamp tests — all ok.docs/operator-secrets.mddocumentsALLOW_ZERO_RATE_LIMITS=1ALLOW_ZERO_RATE_LIMITS,API_BIND, andRATE_LIMIT_RPSreference #458; cross-linked indocs/indexer-invariants.mdandskills/AGENTS_INDEXER_API_LCD_SECURITY.md(H7e).scripts/deploy-dex-local.shwritesAPI_BIND=127.0.0.1,RATE_LIMIT_RPS=0,RATE_LIMIT_LCD_HEAVY_RPS=10(not dual-zero).dev_dual_zero_rate_limits_loopback_bind_loadspasses. Runtime loopback dual-zero reachesStarting CL8Y DEX indexer(fails later on DB timeout — expected without Postgres).Automated suite
Closing as verified — no additional repo changes required.
mentioned in issue #337