Body:
Checklist:
We scanned Serena as part of our MCP security registry at AgentSeal. Score: 35/100 (Risky). Found 10 issues across the codebase, 4 of which are high-impact and have clear fixes. Sharing here for your evaluation.
Summary
| # |
Finding |
Severity |
Fix complexity |
| 1 |
Memory path traversal via unsanitized name |
Critical |
One-line fix |
| 2 |
Shell execution with no timeout |
Critical |
Small fix |
| 3 |
Cross-project poisoning via global memory |
High |
Medium |
| 4 |
Arbitrary directory activation |
High |
Small fix |
| 5 |
Prompt injection to RCE via file content |
High |
Medium |
| 6 |
System prompt extraction via initial_instructions |
Medium |
Small fix |
1. Memory path traversal via unsanitized name
MemoriesManager.get_memory_file_path() in src/serena/project.py constructs paths by splitting the name on / without checking for traversal:
parts = name.split("/")
filename = f"{parts[-1]}.md"
if len(parts) > 1:
subdir = self._project_memory_dir / "/".join(parts[:-1])
subdir.mkdir(parents=True, exist_ok=True)
return subdir / filename
A memory name like ../../etc/cron.d/backdoor would write outside the memories directory. The mkdir(parents=True, exist_ok=True) creates intermediate directories along the traversal path.
How to reproduce: Call write_memory with name "../../tmp/test_traversal" and check if /tmp/test_traversal.md is created.
Suggested fix:
path = (base_dir / "/".join(parts)).resolve()
if not path.is_relative_to(base_dir.resolve()):
raise ValueError(f"Memory name would escape base directory: {name}")
2. Shell execution with no timeout
execute_shell_command in src/serena/util/shell.py uses subprocess.Popen with shell=True and calls process.communicate() with no timeout:
process = subprocess.Popen(command, shell=True, ...)
stdout, stderr = process.communicate()
A hanging command (sleep 99999, a reverse shell, cat /dev/urandom) blocks the Serena process indefinitely. This is both a DoS risk and an exploitation vector for maintaining persistent connections.
Suggested fix:
try:
stdout, stderr = process.communicate(timeout=60)
except subprocess.TimeoutExpired:
process.kill()
return ShellCommandResult(stdout="", stderr="Command timed out", return_code=-1, cwd=cwd)
3. Cross-project poisoning via global memory
Global memories stored in ~/.serena/memories/global/ are shared across all projects. Any project can write to the global namespace using the global/ prefix, and global memory names appear in every session's system prompt via create_system_prompt():
global_memories = MemoriesManager(...).list_global_memories()
Impact: An attacker who achieves a single prompt injection in one project can write persistent instructions into global memory that load into every future conversation on that machine, across all projects.
Suggested fix: Require user confirmation for global memory writes. Add per-project allowlist for global access. Log all global modifications.
4. Arbitrary directory activation
activate_project_from_path_or_name() in src/serena/agent.py accepts any filesystem path:
elif os.path.isdir(project_root_or_name):
project_instance = self.serena_config.add_project_from_path(project_root_or_name)
No allowlist or restriction. A prompt injection could call activate_project('/etc') activate_project('/home/user/.ssh') then use read_file to access sensitive files.
Suggested fix: Restrict to pre-configured paths in serena_config.yml. Require user confirmation for activating new paths.
5. Prompt injection to RCE via file content
read_file and search_for_pattern return file contents directly into LLM context. A malicious repo can embed prompt injection in README, docstrings, or test fixtures instructing the LLM to call execute_shell_command. The onboarding workflow automatically reads project files at the start of every session, making this a reliable entry point.
Suggested fix: Require user confirmation before shell command execution. Consider making execute_shell_command opt-in via config.
6. System prompt extraction via initial_instructions
initial_instructions returns the complete output of create_system_prompt(), exposing tool names, markers, global memory names, context/mode prompts, project path, and initial_prompt. A prompt injection can invoke this to map the full attack surface.
Suggested fix: Restrict to one-time use at conversation start. Omit sensitive configuration details from the returned prompt.
How we found this
Scanned with https://github.com/AgentSeal/agentseal, an open-source MCP server security scanner. Static analysis on tool schemas followed by deep LLM-based classification for MCP-specific attack patterns. All findings verified against source code on this repo.
Full report
https://agentseal.org/mcp/https-githubcom-oraios-serena
Happy to rescan after changes.
Body:
Checklist:
.serena/project.ymlWe scanned Serena as part of our MCP security registry at AgentSeal. Score: 35/100 (Risky). Found 10 issues across the codebase, 4 of which are high-impact and have clear fixes. Sharing here for your evaluation.
Summary
1. Memory path traversal via unsanitized name
MemoriesManager.get_memory_file_path()insrc/serena/project.pyconstructs paths by splitting the name on/without checking for traversal:A memory name like ../../etc/cron.d/backdoor would write outside the memories directory. The mkdir(parents=True, exist_ok=True) creates intermediate directories along the traversal path.
How to reproduce: Call write_memory with name "../../tmp/test_traversal" and check if /tmp/test_traversal.md is created.
Suggested fix:
2. Shell execution with no timeout
execute_shell_command in src/serena/util/shell.py uses subprocess.Popen with shell=True and calls process.communicate() with no timeout:
A hanging command (sleep 99999, a reverse shell, cat /dev/urandom) blocks the Serena process indefinitely. This is both a DoS risk and an exploitation vector for maintaining persistent connections.
Suggested fix:
3. Cross-project poisoning via global memory
Global memories stored in ~/.serena/memories/global/ are shared across all projects. Any project can write to the global namespace using the global/ prefix, and global memory names appear in every session's system prompt via create_system_prompt():
Impact: An attacker who achieves a single prompt injection in one project can write persistent instructions into global memory that load into every future conversation on that machine, across all projects.
Suggested fix: Require user confirmation for global memory writes. Add per-project allowlist for global access. Log all global modifications.
4. Arbitrary directory activation
activate_project_from_path_or_name() in src/serena/agent.py accepts any filesystem path:
No allowlist or restriction. A prompt injection could call activate_project('/etc') activate_project('/home/user/.ssh') then use read_file to access sensitive files.
Suggested fix: Restrict to pre-configured paths in serena_config.yml. Require user confirmation for activating new paths.
5. Prompt injection to RCE via file content
read_file and search_for_pattern return file contents directly into LLM context. A malicious repo can embed prompt injection in README, docstrings, or test fixtures instructing the LLM to call execute_shell_command. The onboarding workflow automatically reads project files at the start of every session, making this a reliable entry point.
Suggested fix: Require user confirmation before shell command execution. Consider making execute_shell_command opt-in via config.
6. System prompt extraction via initial_instructions
initial_instructions returns the complete output of create_system_prompt(), exposing tool names, markers, global memory names, context/mode prompts, project path, and initial_prompt. A prompt injection can invoke this to map the full attack surface.
Suggested fix: Restrict to one-time use at conversation start. Omit sensitive configuration details from the returned prompt.
How we found this
Scanned with https://github.com/AgentSeal/agentseal, an open-source MCP server security scanner. Static analysis on tool schemas followed by deep LLM-based classification for MCP-specific attack patterns. All findings verified against source code on this repo.
Full report
https://agentseal.org/mcp/https-githubcom-oraios-serena
Happy to rescan after changes.