Skip to content

fix: hide server proxy upstream errors#5545

Merged
Scottcjn merged 2 commits into
Scottcjn:mainfrom
ZHOUEU-star:fix/server-proxy-redact-upstream-errors
May 18, 2026
Merged

fix: hide server proxy upstream errors#5545
Scottcjn merged 2 commits into
Scottcjn:mainfrom
ZHOUEU-star:fix/server-proxy-redact-upstream-errors

Conversation

@ZHOUEU-star
Copy link
Copy Markdown
Contributor

Summary

  • Return a stable generic 502 response when the vintage-hardware server proxy hits an unexpected upstream request exception.
  • Log the original exception server-side with app.logger.exception(...) for operators.
  • Add regression coverage proving internal details are not reflected to proxy clients.

Fixes #5544
Bounty: #305
Wallet: RTC4e9b755109fc7b898eaebbd20ad665d9855449eb
BCOS tier: BCOS-L1

Validation

  • /tmp/rustchain-bug-venv/bin/python -m pytest tests/test_server_proxy_path.py -q
    • 5 passed, 1 warning in 0.05s
  • /tmp/rustchain-bug-venv/bin/python -m py_compile node/server_proxy.py tests/test_server_proxy_path.py
    • passed
  • git diff --check -- node/server_proxy.py tests/test_server_proxy_path.py
    • passed

@github-actions github-actions Bot added BCOS-L1 Beacon Certified Open Source tier BCOS-L1 (required for non-doc PRs) node Node server related tests Test suite changes size/S PR: 11-50 lines labels May 17, 2026
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.

Hide server proxy upstream errors. SECURITY: Good hardening — proxy upstream details can reveal internal infrastructure. Verify: all proxy error paths are covered, not just this one. — 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.

Approved. I focused on the changed server-proxy exception path and its regression coverage.

Validation performed on head c5025b0319da91f05e0c52cec48e2bc022c22b57:

  • git diff --check origin/main...HEAD -- node/server_proxy.py tests/test_server_proxy_path.py passed.
  • python3 -B -m py_compile node/server_proxy.py tests/test_server_proxy_path.py passed.
  • PYTHONPATH=. uv run --no-project --with pytest --with flask --with requests python -B -m pytest -q -o addopts='' tests/test_server_proxy_path.py passed with 5 passed in 0.04s.
  • A focused Flask runtime probe monkeypatched requests.get() to raise a fake upstream exception containing host/token/path sentinels; GET /api/miners returned HTTP 502 with exactly { "error": "Local server unavailable" }, and the sentinel host/token/path strings were not reflected in the response body.

The previous catch-all returned str(e) to the client, which could expose local hostnames, tokens, or filesystem paths from upstream request failures. This patch keeps the timeout behavior separate, logs the unexpected exception server-side, and returns a generic 502 for the public proxy response. The existing path-normalization tests plus the new redaction regression test cover the behavior I would expect for this narrow security fix.

@508704820
Copy link
Copy Markdown
Contributor

Security Review ✅ CRITICAL FIX

This fixes an information disclosure vulnerability. The previous code returned str(e) in the 500 response, which could leak:

  • Internal URLs (http://127.0.0.1:8088)
  • Auth tokens (token=secret)
  • File system paths (/srv/rustchain/private.db)

The test case demonstrates this perfectly - a RuntimeError containing token and db path would have been sent directly to the client.

Fix is correct:

  1. Generic error message to client (502 Bad Gateway)
  2. Full exception logged server-side via app.logger.exception()
  3. Test verifies no sensitive data in response body

Reviewed by Xeophon - Solana: Lt9nERv6VHsojw15LpFeiaabuphAggzfLF9sM9UXRrZ

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!

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.

Hide server proxy upstream errors. Good - server proxy errors can reveal internal routing, service URLs, and backend topology. Verify: (1) All proxy error paths are covered. (2) Error messages are generic for external consumers. (3) Internal logging still captures full error details for debugging. - Xeophon (security review)

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!

Copy link
Copy Markdown
Contributor

@LubuSeb LubuSeb left a comment

Choose a reason for hiding this comment

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

I found a remaining information-disclosure path in this proxy hardening change. The new handler hides Python exceptions raised by requests.get() / requests.post(), but once the local upstream returns a response object the proxy still reflects upstream error bodies verbatim.

Two cases still leak sensitive upstream detail to the public proxy client:

  • non-JSON upstream errors go through return response.text, response.status_code
  • Content-Type: application/json responses that fail JSON parsing also fall back to return response.text, response.status_code

That means a local server 500 text/html stack page, or a broken JSON error payload containing an internal token/path, is still exposed even though this PR is meant to hide server proxy upstream errors.

Validation on head c5025b0319da91f05e0c52cec48e2bc022c22b57:

  • git diff --check origin/main...HEAD -- node/server_proxy.py tests/test_server_proxy_path.py passed.
  • python -B -m py_compile node/server_proxy.py tests/test_server_proxy_path.py passed in a Flask/requests review venv.
  • PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 python -B -m pytest -q --noconftest -o addopts='' tests/test_server_proxy_path.py passed with 5 passed.
  • Focused probe monkeypatching requests.get() to return status_code = 500, Content-Type: text/html, and body trace token=super-secret path=/srv/rustchain/private.db host=127.0.0.1 returned HTTP 500 to /api/miners with all three sentinels still present in the client-visible body.
  • A second probe with Content-Type: application/json, invalid JSON parsing, and text = '{"error":"token=super-secret path=/srv/rustchain/private.db"}' returned the raw error body with the token/path still present.

For this security fix to hold, upstream 5xx responses and parse-failure paths should return a generic client error while logging the upstream detail server-side. If legitimate 2xx text endpoints must remain proxied, the sanitization can be limited to error statuses and invalid JSON/error content.

@ZHOUEU-star
Copy link
Copy Markdown
Contributor Author

Thanks for catching the remaining upstream-body leak. I pushed 66128cc to redact upstream 5xx bodies and invalid JSON response bodies behind the same generic proxy error, while logging the upstream detail server-side.

Validation run:

  • PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 /tmp/rustchain-bug-venv/bin/python -m pytest -q --noconftest -o addopts="" tests/test_server_proxy_path.py -> 7 passed, 1 urllib3 LibreSSL warning
  • /tmp/rustchain-bug-venv/bin/python -m py_compile node/server_proxy.py tests/test_server_proxy_path.py
  • git diff --check -- node/server_proxy.py tests/test_server_proxy_path.py

@github-actions github-actions Bot added size/M PR: 51-200 lines and removed size/S PR: 11-50 lines labels May 17, 2026
@BossChaos
Copy link
Copy Markdown
Contributor

Code Review

PR: fix: hide server proxy upstream errors by @ZHOUEU-star

  • ✅ Bug fix / error handling

Wallet: 0xdaE5d307339074A24F579dB48e7c639359D94904

Reviewing under Bounty #73

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!

Copy link
Copy Markdown
Contributor

@kekehanshujun kekehanshujun left a comment

Choose a reason for hiding this comment

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

Reviewing this as part of the RustChain code review bounty.

This fixes the exact exception-reflection case from #5544: unexpected upstream request failures now log server-side and return a generic JSON 502, with regression coverage for 127.0.0.1, token-like text, and private DB paths.

The second commit also improves the higher-risk case where the local node returns a 5xx body or malformed JSON; those bodies are now replaced with Local server unavailable, which is the right public-proxy behavior for upstream failures.

Potential non-blocking follow-up: non-JSON upstream responses with 4xx status are still proxied verbatim. That is probably acceptable for the narrow bug report, but if the local node ever returns diagnostic HTML for 400/404 responses, the proxy could still reflect internal text. I would consider redacting all non-JSON non-2xx responses in a separate hardening PR.

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!

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!

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!

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! Great work on this PR. 🚀

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!

Copy link
Copy Markdown
Contributor

@iamdinhthuan iamdinhthuan left a comment

Choose a reason for hiding this comment

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

Reviewed head 66128cc1859d486557b397c380c5e888202b7df8.

I approve this current revision. The first commit fixed the requests.get() / requests.post() exception-reflection path, and the current head also covers the follow-up upstream response cases: local 5xx bodies and invalid JSON bodies are replaced with a generic public 502 while the detail remains server-side logging.

Validation I ran:

git diff --check origin/main...HEAD -- node/server_proxy.py tests/test_server_proxy_path.py
python3 -B -m py_compile node/server_proxy.py tests/test_server_proxy_path.py
PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 python3 -B -m pytest -q --noconftest -o addopts='' tests/test_server_proxy_path.py
# 7 passed
python3 tools/bcos_spdx_check.py --base-ref origin/main
# BCOS SPDX check: OK

I also ran a direct Flask test-client probe with mocked upstream calls and a sentinel string token=super-secret path=/srv/rustchain/private.db host=127.0.0.1:

exception -> status=502 body='{"error":"Local server unavailable"}' leaked=False
html_500 -> status=502 body='{"error":"Local server unavailable"}' leaked=False
invalid_json_200 -> status=502 body='{"error":"Local server unavailable"}' leaked=False
text_200 -> status=200 body='plain ok' leaked=False
json_200 -> status=200 body='{"ok":true,"source":"upstream"}' leaked=False

That covers the previous blocker I would have had on the earlier head: server-side upstream diagnostics are still logged, but exception text, local 5xx bodies, and invalid JSON error bodies are no longer reflected to proxy clients. Normal 2xx text and JSON proxy behavior remains intact. No blocking issue found in this scoped fix.

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!

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!

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!

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!

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!

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!

@Scottcjn Scottcjn merged commit 5130a02 into Scottcjn:main May 18, 2026
10 of 11 checks passed
Copy link
Copy Markdown
Contributor

@BossChaos BossChaos left a comment

Choose a reason for hiding this comment

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

PR #5545 Review - Proxy upstream error hiding (502/504)

Security Analysis

This PR fixes information leakage in the RustChain proxy.

Key improvements:

  1. _generic_upstream_error(): Server-side logging, client gets generic error
  2. Status 500+ handling: Upstream server errors now hidden
  3. JSON parse failure: ValueError now returns 502 instead of leaking error
  4. Exception handling: Generic exception no longer exposes details

Recommendation: Merge - proxy security hardening.

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) node Node server related size/M PR: 51-200 lines tests Test suite changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] Server proxy leaks upstream exception details

10 participants