Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion core/harness/command_guard.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ def screen_command(command: str) -> str | None:
continue
if not tokens:
continue
reason = _classify(tokens[0].lower(), tokens[1:])
reason = _classify(_program(tokens[0]), tokens[1:])
if reason is not None:
return reason

Expand Down
47 changes: 47 additions & 0 deletions tests/test_command_guard.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,50 @@ def test_unparseable_command_defers_to_sandbox():
# Unbalanced quotes can't be tokenised; the screen must not raise and must
# pass the command through (None) so the sandbox stays the boundary.
assert screen_command('echo "unterminated') is None


@pytest.mark.parametrize(
"command",
[
"/bin/rm -rf /",
"/usr/bin/rm -rf /tmp/x",
"/bin/rm -r -f /tmp/x", # split flags behind a path
"./rm --recursive --force /tmp/x",
"/usr/bin/sudo reboot",
"/bin/dd if=/dev/zero of=/dev/sda",
"/sbin/mkfs.ext4 /dev/sda1",
"/bin/chmod 777 /etc",
"/usr/bin/chmod a+rwx /etc",
"C:/Windows/System32/shutdown.exe /s", # Windows extension stripping
"/usr/bin/rm.exe -rf C:/temp",
"echo hi && /bin/rm -rf /", # path-qualified stage in a sequence
"ls | /usr/bin/rm -rf /", # path-qualified stage in a pipeline
],
)
def test_blocks_path_qualified_destructive_commands(command):
"""An absolute or relative path to the program must not defeat the screen.

``screen_egress`` / ``screen_install`` resolve the program through
``_program()``, which drops the directory and any Windows extension before
matching. ``screen_command`` compared ``tokens[0].lower()`` directly, so the
very same command was classified when typed bare and passed when typed with
its path — ``/bin/rm -rf /`` slipped past the check that ``rm -rf /``
trips.
"""

assert screen_command(command) is not None


@pytest.mark.parametrize(
"command",
[
"/bin/ls -la", # path-qualified but benign
"/usr/bin/rm notes.txt", # plain remove stays allowed
"/usr/local/bin/python train.py",
"/bin/echo done && /bin/ls -la", # benign path-qualified sequence
],
)
def test_allows_path_qualified_benign_commands(command):
"""Normalising the program must not turn every absolute path into a hit."""

assert screen_command(command) is None