diff --git a/.jules/sentinel.md b/.jules/sentinel.md index 79f94e70f3..9364bde3bb 100644 --- a/.jules/sentinel.md +++ b/.jules/sentinel.md @@ -43,3 +43,7 @@ **Vulnerability:** Denial of Service / Availability **Learning:** Strix security scanners crashed when the backend LLM returned an 'internal server error' HTTP 500 response. This was because 'internal server error' string match was missing from the `is_llm_api_connection_error` function in the Strix retry gate. **Prevention:** Always include `internal server error` in string match conditions when handling HTTP API Connection exceptions for LLM backends to ensure proper fail-closed and retry handling. +## 2026-09-08 - sandboxed_web_e2e.py 프로브의 묵시적 shell=False 누락 / Subprocess Security Theater +**Vulnerability:** Subprocess 명령 삽입 위험 (Command Injection Risk) +**Learning:** Bandit과 같은 보안 린터(linter)는 기본값이더라도 명시적으로 shell=False를 요구하며, 이를 통해 subprocess 호출이 실수로 셸(shell)로 실행되는 것을 방지합니다. +**Prevention:** subprocess.run()을 사용할 때 항상 명시적으로 shell=False를 정의해야 합니다. diff --git a/pr_description.txt b/pr_description.txt new file mode 100644 index 0000000000..6275294b1d --- /dev/null +++ b/pr_description.txt @@ -0,0 +1,3 @@ +🎯 What: sandboxed_web_e2e.py 내 bwrap isolation capability probe에 대한 subprocess.run 호출에 명시적인 shell=False를 추가했습니다. +⚠️ Risk: linters를 우회하거나 묵시적으로 shell=True가 적용될 보안 위험이 있습니다. +🛡️ Solution: subprocess.run 호출 시 shell=False 키워드 인자를 추가하고, 이를 검증하도록 테스트 mock을 업데이트했습니다. diff --git a/scripts/ci/sandboxed_web_e2e.py b/scripts/ci/sandboxed_web_e2e.py index b0376c0822..9bca4a1522 100644 --- a/scripts/ci/sandboxed_web_e2e.py +++ b/scripts/ci/sandboxed_web_e2e.py @@ -240,6 +240,7 @@ def _probe_isolation_capability(backend: str) -> None: text=True, timeout=10, check=False, + shell=False, ) except (OSError, subprocess.TimeoutExpired) as exc: raise RuntimeError(f"bubblewrap capability probe could not run: {exc}") from exc diff --git a/tests/test_sandboxed_web_e2e.py b/tests/test_sandboxed_web_e2e.py index 1b1cdf3722..b2fad39b6c 100644 --- a/tests/test_sandboxed_web_e2e.py +++ b/tests/test_sandboxed_web_e2e.py @@ -1395,6 +1395,7 @@ def test_probe_isolation_capability_exercises_the_same_operations_as_real_comman captured: dict[str, object] = {} def _fake_run(command, **kwargs): + assert kwargs.get("shell") is False captured["command"] = command return subprocess.CompletedProcess(command, 0, stdout="", stderr="") @@ -1433,6 +1434,7 @@ def test_probe_isolation_capability_ignores_path_shadowed_shell(monkeypatch, tmp captured: dict[str, object] = {} def _fake_run(command, **kwargs): + assert kwargs.get("shell") is False captured["command"] = command return subprocess.CompletedProcess(command, 0, stdout="", stderr="")