|
| 1 | +"""R2 Red-team attack vector tests.""" |
| 2 | +from openspace.security import check_code_safety |
| 3 | +from openspace.skill_engine.review_gate import check_ast_safety |
| 4 | +from openspace.skill_engine.types import SkillLineage, SkillOrigin, SkillRecord |
| 5 | + |
| 6 | + |
| 7 | +def test_gate(label, py_code): |
| 8 | + record = SkillRecord( |
| 9 | + skill_id="test", name="test", description="test", path="/t/SKILL.md", |
| 10 | + lineage=SkillLineage( |
| 11 | + origin=SkillOrigin.FIXED, generation=1, |
| 12 | + parent_skill_ids=["p"], |
| 13 | + content_snapshot={"SKILL.md": "name: test\n", "handler.py": py_code} |
| 14 | + ) |
| 15 | + ) |
| 16 | + result = check_ast_safety(record) |
| 17 | + print(f" {label}: verdict={result.verdict}, detail={result.detail[:140]}") |
| 18 | + return result |
| 19 | + |
| 20 | + |
| 21 | +print("=" * 60) |
| 22 | +print("BYPASS VECTOR TESTING") |
| 23 | +print("=" * 60) |
| 24 | + |
| 25 | +# 1. Aliased module: import os as o; o.system() |
| 26 | +print("\n--- 1. Aliased module name ---") |
| 27 | +test_gate("import os as o; o.system()", "import os as o\no.system('cmd')\n") |
| 28 | + |
| 29 | +# 2. Double-layer: exec(compile(..., 'exec')) |
| 30 | +print("\n--- 2. exec(compile(..., 'exec')) ---") |
| 31 | +test_gate("exec+compile", "exec(compile('import os', '', 'exec'))\n") |
| 32 | + |
| 33 | +# 3. Renamed import: from os import system as x; x() |
| 34 | +print("\n--- 3. from os import system as x; x() ---") |
| 35 | +test_gate("aliased bare name", "from os import system as x\nx('id')\n") |
| 36 | + |
| 37 | +# 4. globals() dispatch |
| 38 | +print("\n--- 4. globals()['eval']('...') ---") |
| 39 | +test_gate("globals dispatch", "globals()['eval']('1')\n") |
| 40 | + |
| 41 | +# 5. __builtins__.__import__ |
| 42 | +print("\n--- 5. __builtins__.__import__ ---") |
| 43 | +test_gate("builtins import", "import builtins\nbuiltins.__import__('os')\n") |
| 44 | + |
| 45 | +# 6. getattr on non-module (should NOT block) |
| 46 | +print("\n--- 6. getattr on data object (should pass) ---") |
| 47 | +test_gate("getattr on data", "class C: pass\nc = C()\ngetattr(c, 'x')\n") |
| 48 | + |
| 49 | +# 7. lambda + __import__ |
| 50 | +print("\n--- 7. lambda + __import__() ---") |
| 51 | +test_gate("lambda __import__", "(lambda: __import__('os'))()\n") |
| 52 | + |
| 53 | +# 8. compile with 'exec' mode |
| 54 | +print("\n--- 8. compile(..., 'exec') ---") |
| 55 | +test_gate("compile exec mode", "compile('x=1', '', 'exec')\n") |
| 56 | + |
| 57 | +# 9. compile with 'eval' mode (should not trigger) |
| 58 | +print("\n--- 9. compile(..., 'eval') should pass ---") |
| 59 | +test_gate("compile eval mode", "compile('1+1', '', 'eval')\n") |
| 60 | + |
| 61 | +# 10. os.path.join (benign, should pass) |
| 62 | +print("\n--- 10. os.path.join (benign) ---") |
| 63 | +test_gate("os.path.join", "import os\nos.path.join('a', 'b')\n") |
| 64 | + |
| 65 | +# 11. Unicode confusable: fullwidth 'e' in eval |
| 66 | +print("\n--- 11. Unicode confusable eval ---") |
| 67 | +try: |
| 68 | + test_gate("fullwidth eval", "\uff45val('1+1')\n") |
| 69 | +except Exception as e: |
| 70 | + print(f" Error (expected?): {e}") |
| 71 | + |
| 72 | +# 12. String concatenation to build dangerous call |
| 73 | +print("\n--- 12. getattr(os, 'sys'+'tem')('id') ---") |
| 74 | +test_gate("getattr concat", "import os\ngetattr(os, 'sys'+'tem')('id')\n") |
| 75 | + |
| 76 | +# 13. type() constructor trick |
| 77 | +print("\n--- 13. type metaclass with __init_subclass__ ---") |
| 78 | +test_gate("type constructor", "type('X', (), {'__init_subclass__': lambda **kw: None})\n") |
| 79 | + |
| 80 | +# 14. Nested exec in exec |
| 81 | +print("\n--- 14. exec('exec(...)') ---") |
| 82 | +test_gate("nested exec", "exec('exec(chr(49))')\n") |
| 83 | + |
| 84 | +# 15. importlib.import_module bare call |
| 85 | +print("\n--- 15. importlib.import_module ---") |
| 86 | +test_gate("importlib", "import importlib\nimportlib.import_module('os')\n") |
| 87 | + |
| 88 | +# 16. os.* wildcard attribute access (should be caught by import rule) |
| 89 | +print("\n--- 16. from os import * ---") |
| 90 | +test_gate("from os import *", "from os import *\n") |
| 91 | + |
| 92 | +# 17. Chained getattr: getattr(getattr(...), 'system') |
| 93 | +print("\n--- 17. chained getattr ---") |
| 94 | +test_gate("chained getattr", "import os\ngetattr(getattr(os, 'path'), 'join')('a','b')\n") |
| 95 | + |
| 96 | +# 18. sys.modules manipulation |
| 97 | +print("\n--- 18. sys.modules['os'] ---") |
| 98 | +test_gate("sys.modules", "import sys\nsys.modules['os'].system('id')\n") |
| 99 | + |
| 100 | +print("\n" + "=" * 60) |
| 101 | +print("DONE") |
0 commit comments