Skip to content

fix: restrict OTC bridge CORS origins#5104

Merged
Scottcjn merged 1 commit into
Scottcjn:mainfrom
galpetame:codex-fix-otc-bridge-cors-5054
May 14, 2026
Merged

fix: restrict OTC bridge CORS origins#5104
Scottcjn merged 1 commit into
Scottcjn:mainfrom
galpetame:codex-fix-otc-bridge-cors-5054

Conversation

@galpetame
Copy link
Copy Markdown
Contributor

Summary

  • replace OTC bridge wildcard CORS(app) with an explicit trusted-origin allowlist
  • add OTC_CORS_ORIGINS parsing for deploy-specific origins
  • fail fast if the configured allowlist includes *
  • add regression coverage for the default allowlist and wildcard rejection

Fixes #5054.

Validation

  • python -m pytest tests/test_otc_bridge_query_validation.py -q -> 7 passed
  • python -m py_compile .\otc-bridge\otc_bridge.py .\tests\test_otc_bridge_query_validation.py -> passed
  • git diff --check -- .\otc-bridge\otc_bridge.py .\tests\test_otc_bridge_query_validation.py -> clean
  • python tools\bcos_spdx_check.py --base-ref origin/main -> BCOS SPDX check OK

Note: the legacy python .\otc-bridge\test_otc_bridge.py suite still hits the known Windows temp SQLite lock / shared DB state issue; the focused regression for this CORS change is isolated and green.

@508704820
Copy link
Copy Markdown
Contributor

Code Review: Restrict OTC bridge CORS origins

Summary

Third fix PR for #5054 (our bug report) -- restricts CORS from wildcard to configurable origins.

Three competing fixes: #5061, #5063, #5104. All approach the same issue.

Review quality: Comparative review

Copy link
Copy Markdown
Contributor

@loganoe loganoe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved. The wildcard CORS(app) is replaced with an explicit allowlist plus OTC_CORS_ORIGINS override, and wildcard configuration is rejected. I verified the submitted regression suite (7 passed), py_compile, git diff --check, and tools/bcos_spdx_check.py --base-ref origin/main. I also ran a live Flask-CORS header check: https://rustchain.org receives Access-Control-Allow-Origin, while https://evil.example receives none.

Copy link
Copy Markdown

@8npyvz5bd8-lang 8npyvz5bd8-lang left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the OTC bridge CORS hardening.

The old CORS(app) default exposed the bridge API to any origin; this patch moves the bridge to an explicit allowlist, keeps the trusted defaults narrow, trims custom OTC_CORS_ORIGINS, falls back to defaults for empty config, and fails startup if a wildcard origin is configured. The test stub was updated so existing query-validation tests still import with the new CORS call signature, and the new tests cover both default allowlist behavior and wildcard rejection.

Verification I ran locally:

  • git diff --check origin/main...HEAD
  • python -m pytest tests/test_otc_bridge_query_validation.py -q -> 7 passed

No blocking findings. Operational note: deployments that legitimately serve the OTC UI from another trusted domain should set OTC_CORS_ORIGINS explicitly; rejecting * is the right fail-closed behavior here.

Copy link
Copy Markdown
Contributor

@508704820 508704820 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Security Review — #5104

1. Critical CORS fix — restricts origins

The old code used CORS(app) with no origin restriction, meaning ANY website could make cross-origin requests to the OTC bridge. This enables:

  • CSRF attacks from any website
  • Data exfiltration via malicious JavaScript
  • Unauthorized bridge operations

2. Default allowlist is appropriate

DEFAULT_OTC_CORS_ORIGINS includes:

3. Environment variable override

OTC_CORS_ORIGINS allows operators to customize the allowlist without code changes. This is good for deployment flexibility.

4. Consider: validate origin format

The parse_cors_origins function should validate that each origin:

  • Starts with https:// (or http:// for localhost only)
  • Does not contain wildcards unless intentional
  • Is a valid URL format

5. Related to #4624 and #4626

This is the same CORS issue we reviewed in earlier PRs. This PR provides the most complete fix for the OTC bridge specifically.

— Xeophon (security review)

Copy link
Copy Markdown

@TJCurnutte TJCurnutte left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hermes Agent review — APPROVED

I reviewed the diff for PR #5104: fix: restrict OTC bridge CORS origins

Validation proof

  • git diff --check: PASS
  • BCOS SPDX check: PASS
  • added-line secret-pattern scan: PASS
  • python py_compile: PASS
  • focused changed-test pytest: PASS

Scope checked
otc-bridge/otc_bridge.py (+22/-1), tests/test_otc_bridge_query_validation.py (+21/-1)

Review note
The changed surface is bounded and the local gates above did not expose whitespace, SPDX, syntax, focused-test, or added-secret regressions. This approval is for the submitted diff at the reviewed head; payout/merge authority remains with the maintainers.

Copy link
Copy Markdown
Contributor

@jaxint jaxint left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Thanks for contributing. Approved.

Copy link
Copy Markdown
Contributor

@himanalot himanalot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved. The OTC bridge no longer enables unrestricted CORS. It now parses OTC_CORS_ORIGINS, defaults to a small trusted allowlist, ignores blank entries, and fails closed if * is configured.

I could not run the Flask-based tests locally because the project dependencies are not installed and I am avoiding installs. Static review of parse_cors_origins() and the CORS(app, origins=OTC_CORS_ORIGINS) wiring matches the added tests for default trusted origins and wildcard rejection.

Copy link
Copy Markdown
Contributor

@jaxint jaxint left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR Review - Standard Quality ✓

Reviewed: Review submitted via GitHub API
Bounty: #73 - PR Reviews Bounty
Wallet: AhqbFaPBPLMMiaLDzA9WhQcyvv4hMxiteLhPk3NhG1iG

This PR has been reviewed as part of the RustChain bounty program. All standard review criteria met.


🤖 Automated review via RustChain RTC bounty bot

@Scottcjn Scottcjn merged commit aae50a3 into Scottcjn:main May 14, 2026
3 checks passed
Copy link
Copy Markdown
Contributor

@HCIE2054 HCIE2054 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Thanks for contributing!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

BCOS-L1 Beacon Certified Open Source tier BCOS-L1 (required for non-doc PRs) size/S PR: 11-50 lines tests Test suite changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: OTC bridge uses wildcard CORS — any website can call trading API

9 participants