#!/bin/env python3 import sys def auditor(builtins): # site.exit is a mutable Quitter instance, so keep the hook state immutable. _system_exit = builtins['SystemExit'] # Call the real str implementation directly. Audit arguments can contain # attacker-created str subclasses whose __str__/__contains__ methods lie. _str_contains = builtins['str'].__contains__ blacklist_patterns = ( 'spawn', 'process', 'os', 'sys', 'cpython', 'fork', 'open', 'interpreter', 'ctypes', 'compile', 'gc', '__new__', 'import', ) def func(event, args): # Security decisions use only CPython's canonical event name. Calling # str() on arbitrary arguments both executes attacker code and lets a # str subclass hide the value consumed later by a C API. Blocking the # import event also closes raw extension-loader audit gaps such as # directly invoking _posixsubprocess.fork_exec(). for pattern in blacklist_patterns: if _str_contains(event, pattern): raise _system_exit(1) return func codes = input('$ ') code = compile(codes, "", "exec") sys.addaudithook(auditor(__builtins__.__dict__.copy())) exec(code,{'__builtins__':{}},{})