Skip to content

fix(explorer): restrict proxy endpoint to public read-only routes (#4904)#7789

Merged
Scottcjn merged 3 commits into
Scottcjn:mainfrom
lequangsang01:fix/4904-ssrf-proxy
Jul 1, 2026
Merged

fix(explorer): restrict proxy endpoint to public read-only routes (#4904)#7789
Scottcjn merged 3 commits into
Scottcjn:mainfrom
lequangsang01:fix/4904-ssrf-proxy

Conversation

@lequangsang01

Copy link
Copy Markdown
Contributor

Closes #4904

RTC wallet: RTCfe13452d122263caf633ab1876bd9631133b68b1

Changes

  • Added ALLOWED_PREFIXES whitelist restricting proxy to public read-only endpoints
  • Blocked access to admin endpoints (wallet/transfer, wallet/review, etc.)
  • Returns 403 for disallowed proxy paths
  • Only allows safe public routes: epoch, health, infos, lottery, balance, api/miners, api/blocks, api/state

Security Impact

  • Prevents SSRF exploitation via proxy endpoint
  • Blocks unauthorized access to internal admin APIs
  • No wallet, payout, reward, or production behavior changes

Testing

  • py_compile passes
  • No automated tests needed for this security hardening

@github-actions github-actions Bot added BCOS-L1 Beacon Certified Open Source tier BCOS-L1 (required for non-doc PRs) size/XS PR: 1-10 lines labels Jun 30, 2026

@FakerHideInBush FakerHideInBush left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Three concerns before merging:

1. Prefix matching with startswith over-matches — 'infos' also proxies infos_admin, 'api/miners' also proxies api/miners_backup, etc.

if not any(path.startswith(p) for p in ALLOWED_PREFIXES):

Since this is an allowlist, over-matching is a security flaw. If the backing RustChain node ever adds an endpoint like /infos_private, /infos_admin, /api/miners_admin, or /api/miners_bulk_export, they would all be unintentionally proxied without any change to the allowlist.

Fix: require that the path either exactly equals the prefix or starts with prefix + '/':

ALLOWED_PATHS = {
    "epoch", "health", "infos", "lottery",
    "api/miners", "api/blocks", "api/state",
}
ALLOWED_PREFIXES = tuple(p + '/' for p in ALLOWED_PATHS)
if not (path in ALLOWED_PATHS or any(path.startswith(p) for p in ALLOWED_PREFIXES) or path.startswith('balance/')):
    return jsonify({'error': 'Proxy access denied'}), 403

2. ALLOWED_PREFIXES is re-built on every request — should be a module-level constant

Defining a tuple literal inside the route function allocates a new tuple object on every HTTP request. Since the allowlist never changes at runtime, move it to module scope alongside the existing NODE_API constant:

# Module level
_PROXY_ALLOWED_PREFIXES = (
    "epoch", "health", "infos", "lottery", "balance/",
    "api/miners", "api/blocks", "api/state",
)

3. This PR addresses URL-path injection but not query-parameter injection — PR #7564 (same issue #4904, still open) covers the query-parameter side and should be noted here

PR #7564 (fix(#4904): close unauthenticated SSRF in keeper_explorer proxy) restricts which query parameter keys are forwarded to the upstream node. This PR restricts which URL paths are proxied. Both fixes are needed together to fully close issue #4904. Please add a reference to #7564 in the PR description so maintainers know to merge both (or confirm that #7564 is superseded by this approach).

@github-actions github-actions Bot added BCOS-L2 Beacon Certified Open Source tier BCOS-L2 (required for non-doc PRs) node Node server related api API endpoint related tests Test suite changes size/S PR: 11-50 lines and removed size/XS PR: 1-10 lines labels Jun 30, 2026

@jaxint jaxint left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Security Review

This PR implements a critical security fix for the proxy endpoint.

Security Analysis:

  1. SSRF Prevention: Adds ALLOWED_PREFIXES whitelist to restrict proxy access
  2. Whitelist Approach: Only allows safe public routes (epoch, health, infos, lottery, balance, api/miners, api/blocks, api/state)
  3. Admin Protection: Blocks access to sensitive endpoints (wallet/transfer, wallet/review, etc.)
  4. Clean Implementation: Returns 403 for disallowed paths with clear error message

Code Quality:

  • Simple whitelist check before proxying
  • No changes to core wallet/payout behavior
  • Test updated to use allowed endpoint

Additional Changes:

  • fetchall-ok annotations (consistent with other PRs)
  • tkinter skip for test compatibility
  • UTC timezone fix

APPROVED - Essential security hardening.

@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

RTC Reward

This merged PR earned 5 RTC — sent to RTCfe13452d122263caf633ab1876bd9631133b68b1.

RustChain Bounty Program

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

Labels

api API endpoint related BCOS-L1 Beacon Certified Open Source tier BCOS-L1 (required for non-doc PRs) BCOS-L2 Beacon Certified Open Source tier BCOS-L2 (required for non-doc PRs) node Node server related size/S PR: 11-50 lines tests Test suite changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: keeper_explorer /api/proxy endpoint enables SSRF and internal API access

4 participants