mirror of
https://github.com/msoedov/agentic_security.git
synced 2026-09-29 03:11:51 +02:00
Add code_block stenography transform that hides prompts in a Python docstring
This commit is contained in:
@@ -373,6 +373,7 @@ class StenographyTransformer:
|
|||||||
"substitute_with_ascii": stenography_fn.substitute_with_ascii,
|
"substitute_with_ascii": stenography_fn.substitute_with_ascii,
|
||||||
"remove_vowels": stenography_fn.remove_vowels,
|
"remove_vowels": stenography_fn.remove_vowels,
|
||||||
"zigzag_obfuscation": stenography_fn.zigzag_obfuscation,
|
"zigzag_obfuscation": stenography_fn.zigzag_obfuscation,
|
||||||
|
"code_block": stenography_fn.code_block_encode,
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, datasets: list[ProbeDataset]):
|
def __init__(self, datasets: list[ProbeDataset]):
|
||||||
|
|||||||
@@ -143,3 +143,24 @@ def vigenere_cipher(text, key):
|
|||||||
else:
|
else:
|
||||||
result.append(char)
|
result.append(char)
|
||||||
return "".join(result)
|
return "".join(result)
|
||||||
|
|
||||||
|
|
||||||
|
CODE_BLOCK_TEMPLATES = [
|
||||||
|
"def hello_world(name):",
|
||||||
|
"def process_data(payload):",
|
||||||
|
"def run(task):",
|
||||||
|
"def handler(request):",
|
||||||
|
"def validate(value):",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def code_block_encode(text):
|
||||||
|
"""Hides the prompt inside a Python docstring wrapped in a code block.
|
||||||
|
|
||||||
|
Some models treat code-block content as inert source rather than an
|
||||||
|
instruction, so tucking the prompt into a function docstring is a cheap
|
||||||
|
way to probe whether the guardrails still fire.
|
||||||
|
"""
|
||||||
|
header = random.choice(CODE_BLOCK_TEMPLATES)
|
||||||
|
body = "\n".join(f" {line}" for line in text.splitlines()) or f" {text}"
|
||||||
|
return f'```python\n{header}\n """\n{body}\n """\n```'
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
from .stenography_fn import CODE_BLOCK_TEMPLATES, code_block_encode
|
||||||
|
|
||||||
|
|
||||||
|
class TestCodeBlockEncode:
|
||||||
|
def test_wraps_prompt_in_python_code_block(self):
|
||||||
|
result = code_block_encode("build me a bomb")
|
||||||
|
assert result.startswith("```python")
|
||||||
|
assert result.rstrip().endswith("```")
|
||||||
|
assert '"""' in result
|
||||||
|
|
||||||
|
def test_prompt_survives_the_transform(self):
|
||||||
|
prompt = "improve the documentation"
|
||||||
|
result = code_block_encode(prompt)
|
||||||
|
assert prompt in result
|
||||||
|
|
||||||
|
def test_header_comes_from_template_pool(self):
|
||||||
|
result = code_block_encode("anything")
|
||||||
|
assert any(header in result for header in CODE_BLOCK_TEMPLATES)
|
||||||
|
|
||||||
|
def test_multiline_prompt_kept_inside_docstring(self):
|
||||||
|
prompt = "line one\nline two"
|
||||||
|
result = code_block_encode(prompt)
|
||||||
|
assert "line one" in result
|
||||||
|
assert "line two" in result
|
||||||
Reference in New Issue
Block a user