From 908bca3687ed0c2fcc5eb40de018f5f4fc8f96ef Mon Sep 17 00:00:00 2001 From: mwiegand Date: Fri, 8 May 2026 16:18:00 +0200 Subject: [PATCH] =?UTF-8?q?fix(l4d2-web):=20ScriptBuilder=20=E2=80=94=20ch?= =?UTF-8?q?mod=20script=20tmpfile=20to=200644=20for=20sandbox=20read?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit NamedTemporaryFile creates the script file at mode 0600 owned by the left4me web user. The sandbox runs as l4d2-sandbox and bwrap bind-mounts the file read-only at /script.sh, but the kernel still enforces the underlying file's permissions — l4d2-sandbox can't read 0600 left4me files, so /bin/bash /script.sh fails with "Permission denied". Script content is not a secret (it's stored in the DB and editable by the user), so 0644 is appropriate. Co-Authored-By: Claude Opus 4.7 (1M context) --- l4d2web/services/overlay_builders.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/l4d2web/services/overlay_builders.py b/l4d2web/services/overlay_builders.py index 223aaca..da1d95c 100644 --- a/l4d2web/services/overlay_builders.py +++ b/l4d2web/services/overlay_builders.py @@ -192,6 +192,11 @@ def run_sandboxed_script( with tempfile.NamedTemporaryFile("w", suffix=".sh", delete=False) as f: f.write(script_text or "") script_path = f.name + # NamedTemporaryFile creates 0600 owned by the web user; the sandbox runs + # as l4d2-sandbox and needs to read it (bind-mounted at /script.sh inside + # the sandbox). Script content is not a secret — it's plain bash stored + # in the DB and editable by the user — so 0644 is appropriate. + os.chmod(script_path, 0o644) try: cmd = [ "sudo",