Skip to content

Commit e50d5a1

Browse files
AaronWardWardekzhu
authored
Command line code sanitation (#1627)
* UPDATE - add commandline sanitation class, update local_commandline_code_executor.py and renamed test for code_utils.py * FIX - precommit run * UPDATE - moved sanitation function to LocalCommandlineCodeExecutor, moved testo to test_commandline_code_executor.py * UPDATE - added docstring notice to sanitize_code * Update autogen/coding/local_commandline_code_executor.py Co-authored-by: Eric Zhu <[email protected]> * FIX - regular expression * FIX - function invocation in tests * UPDATE - pre-commit run * FIX - pre-commit run -_- --------- Co-authored-by: Ward <[email protected]> Co-authored-by: Eric Zhu <[email protected]>
1 parent 5aee911 commit e50d5a1

File tree

3 files changed

+47
-0
lines changed

3 files changed

+47
-0
lines changed

autogen/coding/local_commandline_code_executor.py

+28
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import os
2+
import re
23
import uuid
34
import warnings
45
from typing import Any, ClassVar, List, Optional
@@ -43,6 +44,8 @@ class LocalCommandlineCodeExecutor(BaseModel):
4344
the working directory, and a unique file is generated and saved in the
4445
working directory for each code block.
4546
The code blocks are executed in the order they are received.
47+
Command line code is sanitized using regular expression match against a list of dangerous commands in order to prevent self-destructive
48+
commands from being executed which may potentially affect the users environment.
4649
Currently the only supported languages is Python and shell scripts.
4750
For Python code, use the language "python" for the code block.
4851
For shell scripts, use the language "bash", "shell", or "sh" for the code
@@ -108,6 +111,28 @@ def code_extractor(self) -> CodeExtractor:
108111
"""(Experimental) Export a code extractor that can be used by an agent."""
109112
return MarkdownCodeExtractor()
110113

114+
@staticmethod
115+
def sanitize_command(lang: str, code: str) -> None:
116+
"""
117+
Sanitize the code block to prevent dangerous commands.
118+
This approach acknowledges that while Docker or similar
119+
containerization/sandboxing technologies provide a robust layer of security,
120+
not all users may have Docker installed or may choose not to use it.
121+
Therefore, having a baseline level of protection helps mitigate risks for users who,
122+
either out of choice or necessity, run code outside of a sandboxed environment.
123+
"""
124+
dangerous_patterns = [
125+
(r"\brm\s+-rf\b", "Use of 'rm -rf' command is not allowed."),
126+
(r"\bmv\b.*?\s+/dev/null", "Moving files to /dev/null is not allowed."),
127+
(r"\bdd\b", "Use of 'dd' command is not allowed."),
128+
(r">\s*/dev/sd[a-z][1-9]?", "Overwriting disk blocks directly is not allowed."),
129+
(r":\(\)\{\s*:\|\:&\s*\};:", "Fork bombs are not allowed."),
130+
]
131+
if lang in ["bash", "shell", "sh"]:
132+
for pattern, message in dangerous_patterns:
133+
if re.search(pattern, code):
134+
raise ValueError(f"Potentially dangerous command detected: {message}")
135+
111136
def execute_code_blocks(self, code_blocks: List[CodeBlock]) -> CommandlineCodeResult:
112137
"""(Experimental) Execute the code blocks and return the result.
113138
@@ -119,6 +144,9 @@ def execute_code_blocks(self, code_blocks: List[CodeBlock]) -> CommandlineCodeRe
119144
logs_all = ""
120145
for i, code_block in enumerate(code_blocks):
121146
lang, code = code_block.language, code_block.code
147+
148+
LocalCommandlineCodeExecutor.sanitize_command(lang, code)
149+
122150
print(
123151
colored(
124152
f"\n>>>>>>>> EXECUTING CODE BLOCK {i} (inferred language is {lang})...",

test/coding/test_commandline_code_executor.py

+19
Original file line numberDiff line numberDiff line change
@@ -177,3 +177,22 @@ def _test_conversable_agent_code_execution(executor: CodeExecutor) -> None:
177177
sender=ConversableAgent("user", llm_config=False, code_execution_config=False),
178178
)
179179
assert "hello extract code" in reply # type: ignore[operator]
180+
181+
182+
# Test cases for dangerous commands that should be caught by the sanitizer
183+
@pytest.mark.parametrize(
184+
"lang, code, expected_message",
185+
[
186+
("bash", "rm -rf /", "Use of 'rm -rf' command is not allowed."),
187+
("bash", "mv myFile /dev/null", "Moving files to /dev/null is not allowed."),
188+
("bash", "dd if=/dev/zero of=/dev/sda", "Use of 'dd' command is not allowed."),
189+
("bash", "echo Hello > /dev/sda", "Overwriting disk blocks directly is not allowed."),
190+
("bash", ":(){ :|:& };:", "Fork bombs are not allowed."),
191+
],
192+
)
193+
def test_dangerous_commands(lang, code, expected_message):
194+
with pytest.raises(ValueError) as exc_info:
195+
LocalCommandlineCodeExecutor.sanitize_command(lang, code)
196+
assert expected_message in str(
197+
exc_info.value
198+
), f"Expected message '{expected_message}' not found in '{str(exc_info.value)}'"
File renamed without changes.

0 commit comments

Comments
 (0)