Skip to content

Commit f4609bf

Browse files
fix: opt-in --debug flag and README security warning
Replace hardcoded debug=True in app.run() with a --debug CLI flag (default False) so the server starts in production mode unless explicitly requested. Document the dangerous --host 0.0.0.0 plus --debug combination in the README Options section.
1 parent 2380427 commit f4609bf

3 files changed

Lines changed: 33 additions & 1 deletion

File tree

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,11 @@ python app.py --port 8080 --host 0.0.0.0
6262
python app.py --base-dir /path/to/claude/projects
6363
```
6464

65+
> **Security warning:** Do not use `--host 0.0.0.0` together with `--debug` on untrusted networks.
66+
> That combination exposes Werkzeug's interactive debugger, which allows arbitrary code execution
67+
> from any browser that can reach the server. For typical local browsing, keep the default
68+
> `--host 127.0.0.1` and omit `--debug`.
69+
6570
### CLI Export
6671

6772
```bash

app.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,12 @@ def index():
4141
parser = argparse.ArgumentParser(description="Claude Code Chat Browser")
4242
parser.add_argument("--port", type=int, default=5000)
4343
parser.add_argument("--host", default="127.0.0.1")
44+
parser.add_argument(
45+
"--debug",
46+
action="store_true",
47+
default=False,
48+
help="Enable Flask/Werkzeug debug mode (never use with --host 0.0.0.0 on untrusted networks).",
49+
)
4450
parser.add_argument("--base-dir", default=None, help="Override Claude projects dir")
4551
parser.add_argument(
4652
"--exclude-rules", "-e",
@@ -56,6 +62,6 @@ def index():
5662
app.run(
5763
host=args.host,
5864
port=args.port,
59-
debug=True,
65+
debug=args.debug,
6066
use_reloader=(sys.platform != "win32"),
6167
)

tests/test_cli_args.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ def _build_parser(self) -> argparse.ArgumentParser:
221221
parser = argparse.ArgumentParser(description="Claude Code Chat Browser")
222222
parser.add_argument("--port", type=int, default=5000)
223223
parser.add_argument("--host", default="127.0.0.1")
224+
parser.add_argument("--debug", action="store_true", default=False)
224225
parser.add_argument("--base-dir", default=None)
225226
parser.add_argument("--exclude-rules", "-e", default=None,
226227
metavar="PATH", dest="exclude_rules")
@@ -237,6 +238,26 @@ def test_host_override(self):
237238
args = parser.parse_args(["--host", "127.0.0.1"])
238239
assert args.host == "127.0.0.1"
239240

241+
def test_debug_default_is_false(self):
242+
parser = self._build_parser()
243+
args = parser.parse_args([])
244+
assert args.debug is False
245+
246+
def test_debug_explicit_true(self):
247+
parser = self._build_parser()
248+
args = parser.parse_args(["--debug"])
249+
assert args.debug is True
250+
251+
def test_app_py_debug_not_hardcoded_true(self):
252+
"""app.run() must not pass debug=True unconditionally."""
253+
app_path = os.path.join(REPO_ROOT, "app.py")
254+
with open(app_path, "r", encoding="utf-8") as f:
255+
src = f.read()
256+
run_block_start = src.find("app.run(")
257+
assert run_block_start != -1
258+
run_block = src[run_block_start : src.find(")", run_block_start) + 1]
259+
assert "debug=True" not in run_block
260+
240261
def test_port_default(self):
241262
parser = self._build_parser()
242263
args = parser.parse_args([])

0 commit comments

Comments
 (0)