From c41fa68ed316590983cb2e8848e32a0cb00b8ec6 Mon Sep 17 00:00:00 2001 From: Janna Hopp <201101176+jannahopp@users.noreply.github.com> Date: Mon, 23 Mar 2026 11:56:22 +0100 Subject: [PATCH] fix: disable /config/dump endpoint by default MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The /config/dump endpoint uses eval() with an incomplete sandbox — all public crawl4ai names are exposed in the eval namespace. This is a code execution risk when the server is network-accessible. Guard behind CRAWL4AI_CONFIG_DUMP_ENABLED env var (default: false). Returns 403 when disabled. Operators who need it for development can opt in explicitly. Co-Authored-By: Claude Opus 4.6 (1M context) --- deploy/docker/server.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/deploy/docker/server.py b/deploy/docker/server.py index 7ae1adb8b..ed5bbfe3f 100644 --- a/deploy/docker/server.py +++ b/deploy/docker/server.py @@ -83,6 +83,10 @@ # Hooks are disabled by default for security (RCE risk). Set to "true" to enable. HOOKS_ENABLED = os.environ.get("CRAWL4AI_HOOKS_ENABLED", "false").lower() == "true" +# /config/dump endpoint uses eval() and is disabled by default for security. +# Set to "true" to enable (e.g. for local development). +CONFIG_DUMP_ENABLED = os.environ.get("CRAWL4AI_CONFIG_DUMP_ENABLED", "false").lower() == "true" + # ── default browser config helper ───────────────────────────── def get_default_browser_config() -> BrowserConfig: """Get default BrowserConfig from config.yml.""" @@ -311,6 +315,8 @@ async def get_token(req: TokenRequest): @app.post("/config/dump") async def config_dump(raw: RawCode): + if not CONFIG_DUMP_ENABLED: + raise HTTPException(403, "/config/dump is disabled. Set CRAWL4AI_CONFIG_DUMP_ENABLED=true to enable.") try: return JSONResponse(_safe_eval_config(raw.code.strip())) except Exception as e: