Skip to content

fix: disable public Flask debug by default#4843

Closed
JuanERombado wants to merge 2 commits into
Scottcjn:mainfrom
JuanERombado:codex/flask-debug-env-default
Closed

fix: disable public Flask debug by default#4843
JuanERombado wants to merge 2 commits into
Scottcjn:mainfrom
JuanERombado:codex/flask-debug-env-default

Conversation

@JuanERombado
Copy link
Copy Markdown
Contributor

Closes #4810
/claim #4810

Summary

  • Default the affected public Flask entrypoints to debug=False by deriving debug mode from FLASK_DEBUG instead of hard-coding debug=True.
  • Keep local development opt-in available with values like FLASK_DEBUG=1.
  • Add an AST regression test that fails if the listed public entrypoints bind 0.0.0.0 while hard-coding debug=True.

Security impact

Flask/Werkzeug debug mode is no longer enabled by default on helper services that bind to a public interface, reducing stack trace disclosure and debugger exposure risk if these scripts are run on a reachable host.

Validation

  • python -m pytest tests\test_public_flask_debug.py -q
  • python -m py_compile bcos_directory.py bridge\bridge_api.py contributor_registry.py explorer\app.py keeper_explorer.py security_test_payment_widget.py tests\test_public_flask_debug.py
  • git diff --check

Payout

RTC wallet: RTCd84b6e2d917d0272ecaae49f2f0dfe2f5474d585

@github-actions
Copy link
Copy Markdown
Contributor

ghost commented May 12, 2026

Welcome to RustChain! Thanks for your first pull request.

Before we review, please make sure:

  • Your PR has a BCOS-L1 or BCOS-L2 label
  • New code files include an SPDX license header
  • You've tested your changes against the live node

Bounty tiers: Micro (1-10 RTC) | Standard (20-50) | Major (75-100) | Critical (100-150)

A maintainer will review your PR soon. Thanks for contributing!

@JuanERombado
Copy link
Copy Markdown
Contributor Author

Payout wallet for this fix: RTCd84b6e2d917d0272ecaae49f2f0dfe2f5474d585

@JuanERombado
Copy link
Copy Markdown
Contributor Author

I do not have permission to apply repository labels. This security hardening PR should be labeled BCOS-L1 unless maintainers prefer BCOS-L2.

Copy link
Copy Markdown
Contributor

@saim256 saim256 left a comment

Choose a reason for hiding this comment

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

The functional direction looks good, but this currently fails the repo SPDX gate because the new test file has no license header.

Blocking issue:

  • tests/test_public_flask_debug.py is a new file and needs the standard SPDX header before it can pass tools/bcos_spdx_check.py.

Validation I ran locally:

  • git diff --check origin/main...HEAD -- bcos_directory.py bridge/bridge_api.py contributor_registry.py explorer/app.py keeper_explorer.py security_test_payment_widget.py tests/test_public_flask_debug.py -> passed
  • python -m py_compile bcos_directory.py bridge\bridge_api.py contributor_registry.py explorer\app.py keeper_explorer.py security_test_payment_widget.py tests\test_public_flask_debug.py -> passed, with an existing keeper_explorer.py invalid-escape warning
  • python -m pytest tests\test_public_flask_debug.py -q -> 1 passed, with the same existing keeper_explorer.py warning
  • python -m ruff check bcos_directory.py bridge\bridge_api.py contributor_registry.py explorer\app.py keeper_explorer.py security_test_payment_widget.py tests\test_public_flask_debug.py --select E9,F821,F811 --output-format=concise -> passed
  • python tools\bcos_spdx_check.py --base-ref origin/main -> failed: tests/test_public_flask_debug.py is missing an SPDX header

Adding # SPDX-License-Identifier: MIT at the top of the new test file should clear the blocker.

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.

Code Review: Disable Public Flask Debug by Default

Summary

Changes all Flask app.run() calls from hardcoded debug=True to environment-controlled debug=FLASK_DEBUG. This prevents the Werkzeug debug console from being exposed on public interfaces (host='0.0.0.0').

What Works Well

  1. Critical security fix: Flask debug mode exposes an interactive Python console at /debugger, allowing remote code execution
  2. Consistent pattern: Same env var check across all files
  3. Multiple files fixed: bcos_directory.py, bridge_api.py, contributor_registry.py, explorer/app.py, faucet.py, profile_badge_generator.py, and more
  4. Default is safe: Without FLASK_DEBUG set, debug=False

Issues Found

1. High — host='0.0.0.0' still exposes the service publicly
Even with debug=False, binding to 0.0.0.0 makes the service accessible from any network interface. Combined with any future auth bypass or vulnerability, this is risky. Consider:

host = os.environ.get("FLASK_HOST", "127.0.0.1")  # Default to loopback only
app.run(debug=debug, host=host, port=5000)

2. Medium — No rate limiting on public endpoints
With host='0.0.0.0', any of these services are exposed without rate limiting. An attacker could brute-force the faucet, spam the contributor registry, or DDoS the explorer.

3. Low — FLASK_DEBUG env var is the standard Flask convention
Using the standard FLASK_DEBUG env var is correct and follows Flask conventions. Good.

Verdict: Approve — Critical security fix

This is an important fix. The host='0.0.0.0' concern is a separate issue but worth addressing.

Copy link
Copy Markdown
Contributor

@godd-ctrl godd-ctrl left a comment

Choose a reason for hiding this comment

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

Requesting changes on current head be3398c.

The Flask debug behavior itself looks covered by the focused AST regression, but the PR currently fails the repository BCOS/SPDX gate because the new test file tests/test_public_flask_debug.py has no SPDX header.

Validation performed:

  • python -m pytest tests\test_public_flask_debug.py -q -> 1 passed, 1 warning
  • python -m py_compile bcos_directory.py bridge\bridge_api.py contributor_registry.py explorer\app.py keeper_explorer.py security_test_payment_widget.py tests\test_public_flask_debug.py -> passed with the pre-existing keeper_explorer.py invalid escape SyntaxWarning
  • git diff --check origin/main...HEAD -> passed
  • python tools\bcos_spdx_check.py --base-ref origin/main -> failed: missing SPDX header in tests/test_public_flask_debug.py
  • rg over the changed entrypoints found no remaining public app.run(... debug=True) literal after the patch

@JuanERombado
Copy link
Copy Markdown
Contributor Author

Addressed the SPDX blocker in commit c2532b8 by adding the required MIT SPDX header to tests/test_public_flask_debug.py. Re-ran: python -m pytest tests\test_public_flask_debug.py -q, python tools\bcos_spdx_check.py --base-ref origin/main, and git diff --check.

Copy link
Copy Markdown
Contributor

@saim256 saim256 left a comment

Choose a reason for hiding this comment

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

Approved current head c2532b85a5a864141500b8cadfd889771405cb37 after the SPDX fix.

The public Flask debug hardening is now merge-ready in this focused scope: the affected app.run(host=0.0.0.0, ...) entrypoints no longer hard-code debug=True; debug mode is opt-in via FLASK_DEBUG, and the AST regression covers the public bind + hard-coded debug pattern.

Validation I ran locally:

  • git diff --check origin/main...HEAD -- bcos_directory.py bridge/bridge_api.py contributor_registry.py explorer/app.py keeper_explorer.py security_test_payment_widget.py tests/test_public_flask_debug.py -> passed
  • python -m py_compile bcos_directory.py bridge\bridge_api.py contributor_registry.py explorer\app.py keeper_explorer.py security_test_payment_widget.py tests\test_public_flask_debug.py -> passed, with the existing keeper_explorer.py invalid-escape warning
  • python tools\bcos_spdx_check.py --base-ref origin/main -> BCOS SPDX check: OK
  • python -m ruff check bcos_directory.py bridge\bridge_api.py contributor_registry.py explorer\app.py keeper_explorer.py security_test_payment_widget.py tests\test_public_flask_debug.py --select E9,F821,F811 --output-format=concise -> passed
  • python -m pytest tests\test_public_flask_debug.py -q -> 1 passed, same existing warning

I do not see a remaining blocker in this patch.

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 — #4843

1. Critical security fix — debug mode disabled by default

Flask debug=True exposes the Werkzeug debugger, which allows arbitrary code execution via the interactive console. This is a well-known RCE vector. The fix correctly defaults to False.

2. Environment variable approach is good

Using FLASK_DEBUG env var follows Flask best practices and 12-factor app principles. The value check ({1, true, yes, on}) is comprehensive.

3. host='0.0.0.0' still exposes all interfaces

Even with debug=False, binding to 0.0.0.0 exposes the service on all network interfaces. In production, this should be 127.0.0.1 or behind a reverse proxy. Consider also making the host configurable via env var.

4. Multiple files fixed consistently

The PR applies the same fix to bcos_directory.py, bridge_api.py, and contributor_registry.py — consistent approach.

5. Positive

  • Debug-off-by-default is the correct production posture
  • Env var approach allows developers to enable debug in dev
  • No behavior change for developers who set FLASK_DEBUG=true

— Xeophon (security review)

Copy link
Copy Markdown
Contributor

@dazer1234 dazer1234 left a comment

Choose a reason for hiding this comment

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

Code review for RustChain bounty #73.

Summary: This disables public Flask debug mode by default and uses an explicit truthy env parser. The AST test checks that 0.0.0.0 entrypoints do not hardcode debug=True.

Findings: No blocking issues found. The truthy set {1,true,yes,on} is clearer than a single-value check, and the regression test is less brittle than a string grep.

Verdict: Looks good. This overlaps with PR #4859, so only one of the duplicate fixes should be merged.

Reviewed with OpenAI Codex assistance.

Copy link
Copy Markdown
Contributor

@godd-ctrl godd-ctrl left a comment

Choose a reason for hiding this comment

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

Approved current head c2532b8.

The previous missing-SPDX blocker is fixed, and the public Flask entrypoints now derive debug from FLASK_DEBUG instead of hardcoding debug=True on 0.0.0.0 binds. Each touched file has os imported where needed and the focused AST regression covers the public entrypoints in this patch.

Validation performed:

  • git diff --name-status origin/main...HEAD -> six Flask entrypoints modified, tests/test_public_flask_debug.py added
  • git diff --check origin/main...HEAD -> passed
  • python tools\bcos_spdx_check.py --base-ref origin/main -> passed
  • python -m py_compile bcos_directory.py bridge\bridge_api.py contributor_registry.py explorer\app.py keeper_explorer.py security_test_payment_widget.py tests\test_public_flask_debug.py -> passed with pre-existing keeper_explorer invalid escape SyntaxWarning
  • python -m pytest tests\test_public_flask_debug.py -q -> 1 passed, same keeper_explorer warning
  • rg confirmed each touched entrypoint imports os and uses FLASK_DEBUG for app.run debug

No blocking issues found in the reviewed diff.

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.

Great contribution! 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.

Great contribution! 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.

Great contribution! 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.

Great contribution! 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.

Great contribution! 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.

Great contribution! 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.

Great contribution! LGTM.

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 affected public Flask entrypoints no longer hard-code debug=True while binding 0.0.0.0, and the replacement FLASK_DEBUG opt-in is consistent across the changed scripts. The AST regression test covers the listed public entrypoints without requiring the services to be started.

Validation performed: git diff --check origin/main...HEAD, PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 /tmp/rustchain-flask-venv/bin/python -m pytest -q tests/test_public_flask_debug.py, python3 -m py_compile bcos_directory.py bridge/bridge_api.py contributor_registry.py explorer/app.py keeper_explorer.py security_test_payment_widget.py tests/test_public_flask_debug.py, and python3 tools/bcos_spdx_check.py --base-ref origin/main all pass. The only warning observed is the pre-existing keeper_explorer.py invalid escape warning.

Copy link
Copy Markdown

@shuibui shuibui left a comment

Choose a reason for hiding this comment

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

Code Review: Good Fix

Approve.

**Verdict: Approve.

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.

Reviewed the Flask entrypoint changes and tests/test_public_flask_debug.py. The affected public bind entrypoints now default debug mode off and only enable it via explicit FLASK_DEBUG truthy values. The AST test directly checks app.run() calls that bind 0.0.0.0 and hardcode debug=True, which covers the security regression this PR targets.

I do not see a blocking issue in this patch. Approved.

@guangningsun
Copy link
Copy Markdown
Contributor

PR Review — Standard Quality ✓

PR: #4843 — Fix: disable public Flask debug by default

What I reviewed

  • bcos_directory.py, bridge/bridge_api.py, contributor_registry.py, explorer/app.py, keeper_explorer.py, security_test_payment_widget.py
  • tests/test_public_flask_debug.py (new 51-line test)

Observations

  1. Removing debug=True from 6 Flask entrypoints is a critical security fix. debug=True enables the Werkzeug debugger and interactive tracebacks — if these services are exposed publicly, attackers can execute arbitrary code.

  2. New 51-line test using ast module to parse Flask entrypoints — statically analyzing Python source code to find debug=True patterns is a smart approach that doesn't require running the code.

  3. 6 Flask apps fixed across different modules — comprehensive sweep of the codebase for this dangerous pattern.

LGTM.

Bounty: #2782
Disclosure: I received RTC compensation for this review.

@Scottcjn
Copy link
Copy Markdown
Owner

Wave-5 cluster pay sent (4 RTC/PR). Please rebase against current main to clear conflicts — multiple wave-5 PRs touch overlapping files.

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 Summary

LGTM ✅ — Solid contribution to the RustChain ecosystem.

Code Quality

  • Implementation follows project conventions
  • Security considerations adequately addressed
  • Error handling appears robust

Testing

  • Test coverage is appropriate for the changes
  • Edge cases covered

Approved. Ready to merge. 🚀

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 Summary

LGTM ✅ — Solid contribution to the RustChain ecosystem.

Code Quality

  • Implementation follows project conventions
  • Security considerations adequately addressed
  • Error handling appears robust

Testing

  • Test coverage is appropriate for the changes
  • Edge cases covered

Documentation

  • Code is readable and self-documenting
  • Comments where needed

Approved. Ready to merge. 🚀

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

@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.

@JuanERombado JuanERombado force-pushed the codex/flask-debug-env-default branch from c2532b8 to 7fbd0c3 Compare May 15, 2026 19:07
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.

Verified this one against the current origin/main checkout at head 7fbd0c3c1e70566927d0eaab1649fc1349430f7f.

Validation run:

git diff --check origin/main...HEAD -- bridge/bridge_api.py contributor_registry.py explorer/app.py keeper_explorer.py security_test_payment_widget.py tests/test_public_flask_debug.py
python3 -B -m py_compile bridge/bridge_api.py contributor_registry.py explorer/app.py keeper_explorer.py security_test_payment_widget.py tests/test_public_flask_debug.py
uv run --no-project --with pytest --with flask --with requests python -m pytest tests/test_public_flask_debug.py -q

Results: diff check clean, all changed Python files compiled, and the focused regression passed (1 passed, 1 warning; the warning is the existing invalid escape sequence warning emitted while parsing keeper_explorer.py).

I also ran a focused AST probe over the five changed public Flask entrypoints. Each app.run(host="0.0.0.0", ...) now uses the local debug variable instead of a hard-coded debug=True, and each file imports os for the FLASK_DEBUG env read. That preserves explicit local opt-in while removing default public debugger exposure.

Approved.

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.

Reviewed PR 4843. Standard 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! Thanks for contributing to RustChain!

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! Great contribution to the RustChain ecosystem. Thanks for keeping the codebase clean and well-tested. Approved ✅

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
Copy link
Copy Markdown
Owner

Closing as stale branch — would cause destructive deletions if merged.

Your branch is 237 commits behind current main. Filed during the May 11-13 contributor burst, the codebase has since moved substantially. GitHub's mergeable=clean indicator doesn't detect this; only an explicit git diff main..your-branch --shortstat does.

Bounty credit acknowledged where applicable

Most of the canonical fixes from your work-period have already shipped via other contributors' parallel PRs that landed earlier this week. Specific cases credited via the Codex audit batches:

If you want fresh review

Rebase against current main and verify your diff matches the size of your original changes:

git fetch upstream main
git rebase upstream/main
git diff main..HEAD --shortstat

If the deletion count is much higher than what you intended, the branch is still picking up stale assumptions — recreate from a fresh main.

Thanks for the contribution work.

@Scottcjn Scottcjn closed this May 18, 2026
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) BCOS-L2 Beacon Certified Open Source tier BCOS-L2 (required for non-doc PRs) security Security-related change size/M PR: 51-200 lines tests Test suite changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[SECURITY] Public Flask entrypoints enable debug mode by default