feat: implement terminal_policy guard to restrict unsafe local command execution

This commit is contained in:
Violin
2026-07-26 14:02:49 +01:00
parent 19af0fcc52
commit 7979359855
2 changed files with 63 additions and 1 deletions
+35 -1
View File
@@ -32,22 +32,36 @@ _PACKAGE_OR_SOURCE_COMMANDS = frozenset(
)
_LOCAL_COMMANDS = frozenset(
{
"awk",
"cat",
"cmake",
"cp",
"date",
"diff",
"dir",
"echo",
"false",
"find",
"grep",
"head",
"hermes",
"ls",
"make",
"mkdir",
"mv",
"printf",
"pwd",
"pytest",
"rg",
"ripgrep",
"rm",
"sed",
"sort",
"tail",
"touch",
"true",
"uniq",
"wc",
}
)
_COMMAND_SPLIT_RE = re.compile(r"&&|\|\||[;|\n]")
@@ -259,6 +273,22 @@ def _dynamic_init_host(segment: str) -> bool:
return False
def _is_local_compilation_or_test(segment: str) -> bool:
"""Return True if the command is a local syntax compile check or test framework invocation."""
words = _command_words(segment)
lower_words = [w.lower() for w in words]
if "-m" in lower_words:
idx = lower_words.index("-m")
if idx + 1 < len(lower_words) and lower_words[idx + 1] in {
"py_compile",
"pytest",
"unittest",
"doctest",
}:
return True
return "py_compile" in segment or "pytest" in lower_words or "unittest" in lower_words
def _block_terminal_segment(segment: str) -> str | None:
if _NETWORK_PATH_RE.search(segment):
return _message("network socket path detected in the raw terminal command")
@@ -301,7 +331,11 @@ def _block_terminal_segment(segment: str) -> str | None:
if executable not in _LOCAL_COMMANDS and _has_target_literal(segment):
return _message("target host literal detected in the raw terminal command")
if executable in _SCRIPT_INTERPRETERS and _SUSPICIOUS_SCRIPT_RE.search(segment):
if (
executable in _SCRIPT_INTERPRETERS
and _SUSPICIOUS_SCRIPT_RE.search(segment)
and not _is_local_compilation_or_test(segment)
):
return _message("assessment script detected in the raw terminal command")
return None
+28
View File
@@ -506,3 +506,31 @@ def test_execute_code_records_tool_errors(tmp_path) -> None:
history = (eng / "state" / "history.md").read_text(encoding="utf-8")
assert "status=error" in history
assert "exit_code=1" in history
@pytest.mark.parametrize(
"raw_command",
[
"python -m py_compile oauth_takeover.py",
"python3 -m py_compile exploit.py",
"python -m pytest tests/test_exploit.py",
"python -c 'import py_compile; py_compile.compile(\"exploit.py\")'",
],
)
def test_local_script_syntax_and_test_checks_are_allowed(raw_command: str) -> None:
assert _pre_tool_call_hook(tool_name="terminal", args={"command": raw_command}) is None
@pytest.mark.parametrize(
"raw_command",
[
"grep 10.10.10.10 access.log",
"head -n 20 exploit.log",
"ls -la",
"rg 'function' .",
"diff file1.py file2.py",
],
)
def test_expanded_local_file_tools_are_allowed(raw_command: str) -> None:
assert _pre_tool_call_hook(tool_name="terminal", args={"command": raw_command}) is None