GHSA-3w55-933p-8pv5: Strands Agents: symlink flaw enables file overwrite, session tampering
GHSA-3w55-933p-8pv5HIGHStrands Agents' default FileSessionManager stores agent session data in the world-writable /tmp/strands/sessions/ directory and writes it through predictable .tmp paths that follow symlinks. A local attacker on the same host can plant a symlink to overwrite any file the agent process can write, such as shell profiles, SSH authorized_keys or cron files, or can drop forged session files that the agent loads without any integrity check, giving persistent prompt injection. The CVSS score is 7.1 (local vector, low privileges, no user interaction). It is not in CISA KEV, no public exploit or scanner template is listed, and EPSS and dependent counts are not available, so urgency depends mostly on whether you run Strands agents on shared or multi-tenant hosts, CI runners or shared containers. Upgrade strands-agents to 1.48.0 or later, and until then configure a user-private session directory with restrictive permissions instead of the /tmp default.
What is the risk?
Rated high (CVSS 7.1, CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:H). Exploitation needs local access and a low-privileged account, and complexity is low because the paths are predictable and a reproduction is included in the advisory. Risk is highest on shared hosts, multi-user servers, shared CI runners and containers with a shared /tmp. On single-tenant, isolated deployments the practical risk is low. There is no known active exploitation, no KEV listing and no EPSS data, so likelihood is moderate. Impact is high for integrity and availability because the attacker can overwrite arbitrary files with the agent's privileges and can persistently steer agent behavior.
How does the attack unfold?
What systems are affected?
| Package | Ecosystem | Vulnerable Range | Patched |
|---|---|---|---|
| strands-agents | pip | < 1.48.0 | 1.48.0 |
Do you use strands-agents? You're affected.
How severe is it?
What is the attack surface?
What should I do?
1 step1) Upgrade strands-agents to 1.48.0 or later. 2) Until patched, set an explicit storage_dir for FileSessionManager in a user-private location (for example ~/.strands/sessions or $XDG_DATA_HOME) with mode 0700 owned by the service account, and never use /tmp. 3) Remove or audit existing /tmp/strands/sessions/ for symlinks and files not owned by the service user. 4) Run agents in isolated containers or per-tenant namespaces with a private /tmp. 5) Consider moving to a managed or database-backed session manager with access control. 6) Detection: monitor for symlinks under session directories (find -type l), unexpected writes to dotfiles, authorized_keys and cron paths by the agent process, and use auditd or inotify on the session directory. 7) Review agent logs for unexpected instructions in restored session history.
How is it classified?
Which compliance frameworks are affected?
This CVE is relevant to:
Frequently Asked Questions
What is GHSA-3w55-933p-8pv5?
Strands Agents' default FileSessionManager stores agent session data in the world-writable /tmp/strands/sessions/ directory and writes it through predictable .tmp paths that follow symlinks. A local attacker on the same host can plant a symlink to overwrite any file the agent process can write, such as shell profiles, SSH authorized_keys or cron files, or can drop forged session files that the agent loads without any integrity check, giving persistent prompt injection. The CVSS score is 7.1 (local vector, low privileges, no user interaction). It is not in CISA KEV, no public exploit or scanner template is listed, and EPSS and dependent counts are not available, so urgency depends mostly on whether you run Strands agents on shared or multi-tenant hosts, CI runners or shared containers. Upgrade strands-agents to 1.48.0 or later, and until then configure a user-private session directory with restrictive permissions instead of the /tmp default.
Is GHSA-3w55-933p-8pv5 actively exploited?
No confirmed active exploitation of GHSA-3w55-933p-8pv5 has been reported, but organizations should still patch proactively.
How to fix GHSA-3w55-933p-8pv5?
1) Upgrade strands-agents to 1.48.0 or later. 2) Until patched, set an explicit storage_dir for FileSessionManager in a user-private location (for example ~/.strands/sessions or $XDG_DATA_HOME) with mode 0700 owned by the service account, and never use /tmp. 3) Remove or audit existing /tmp/strands/sessions/ for symlinks and files not owned by the service user. 4) Run agents in isolated containers or per-tenant namespaces with a private /tmp. 5) Consider moving to a managed or database-backed session manager with access control. 6) Detection: monitor for symlinks under session directories (find -type l), unexpected writes to dotfiles, authorized_keys and cron paths by the agent process, and use auditd or inotify on the session directory. 7) Review agent logs for unexpected instructions in restored session history.
What systems are affected by GHSA-3w55-933p-8pv5?
This vulnerability affects the following AI/ML architecture patterns: Agent frameworks, Multi-tenant agent hosting, CI/CD agent runners, Session and memory persistence layers, Local developer agent deployments.
What is the CVSS score for GHSA-3w55-933p-8pv5?
GHSA-3w55-933p-8pv5 has a CVSS v3.1 base score of 7.1 (HIGH).
What is the AI security impact?
Affected AI Architectures
MITRE ATLAS Techniques
AML.T0051.001IndirectAML.T0080.000MemoryAML.T0081Modify AI Agent ConfigurationAML.T0112.000Local AI AgentCompliance Controls Affected
What are the technical details?
Original Advisory
## Summary The `FileSessionManager` defaults to storing session data in `/tmp/strands/sessions/` (a world-writable directory) using predictable file paths and a write pattern (`open(path + ".tmp", "w")` → `os.replace()`) that follows symbolic links. A local attacker can exploit this to overwrite arbitrary files or inject malicious session data for persistent prompt injection. ## Vulnerability Details **Component:** `strands-py/src/strands/session/file_session_manager.py` **Root Cause:** 1. Default storage directory is `tempfile.gettempdir() + "/strands/sessions/"` (line 58) — resolves to `/tmp/strands/sessions/` on Linux/macOS 2. The `_write_file()` method (lines 116-123) writes to a predictable `.tmp` path without symlink protection: ```python tmp = f"{path}.tmp" with open(tmp, "w", encoding="utf-8", newline="\n") as f: json.dump(data, f, indent=2, ensure_ascii=False) os.replace(tmp, path) ``` 3. `open()` follows symlinks — a pre-placed symlink at the `.tmp` path causes writes to an arbitrary target file 4. No integrity verification (HMAC/signature) on session files — tampered data is loaded as-is ## Attack Vectors ### 1. Arbitrary File Overwrite (Local Privilege Escalation) 1. Attacker pre-creates `/tmp/strands/sessions/session_<id>/` (or monitors for new directories via inotify) 2. Attacker creates a symlink: `session.json.tmp` → `/home/victim/.bashrc` (or any writable file) 3. Victim application writes session data → follows symlink → overwrites target file with JSON content 4. Attacker achieves code execution on next shell login (or targets `.ssh/authorized_keys`, cron files, etc.) ### 2. Persistent Prompt Injection via Session Tampering 1. Attacker writes crafted message files into the session directory 2. Victim application restores the session → loads attacker-controlled conversation history 3. Injected messages instruct the agent to execute attacker commands on every future interaction 4. No integrity check prevents this — the SDK trusts all session files at face value ## Impact - **Arbitrary file overwrite** — local attacker can write attacker-controlled content to any file writable by the victim process - **Local privilege escalation** — via overwriting shell configs, SSH keys, cron jobs, or systemd user services - **Persistent agent compromise** — via session data injection, the agent follows attacker instructions indefinitely ## Reproduction ```python import os, json, tempfile, shutil # Setup: simulate the vulnerable write pattern session_dir = "/tmp/strands/sessions/session_test/" os.makedirs(session_dir, exist_ok=True) # Attacker: create symlink at the .tmp write path target_file = "/tmp/symlink_attack_proof.txt" with open(target_file, "w") as f: f.write("ORIGINAL - should not be overwritten\n") symlink_path = os.path.join(session_dir, "session.json.tmp") if os.path.exists(symlink_path): os.unlink(symlink_path) os.symlink(target_file, symlink_path) # Victim: FileSessionManager._write_file() equivalent with open(symlink_path, "w", encoding="utf-8", newline="\n") as f: json.dump({"session_id": "test", "injected": True}, f, indent=2) # Verify: target file overwritten with open(target_file) as f: print(f"Target file content: {f.read()}") # Output: {"session_id": "test", "injected": true} # Cleanup os.unlink(symlink_path) os.unlink(target_file) shutil.rmtree(session_dir) ``` ## Suggested Fix 1. **Use a user-private default directory** — `~/.strands/sessions/` or `$XDG_DATA_HOME/strands/sessions/` instead of `/tmp/` 2. **Use `os.open()` with `O_NOFOLLOW | O_CREAT | O_WRONLY`** — refuses to follow symlinks 3. **Use `tempfile.mkstemp()`** for atomic writes instead of predictable `.tmp` suffix 4. **Verify directory ownership** matches the current user before writing 5. **Add optional integrity verification** (HMAC) on session files to detect tampering
Exploitation Scenario
On a shared build server or multi-user host running a Strands-based coding or ops agent, a low-privileged local user watches /tmp/strands/sessions/ with inotify. When a new session directory appears, they place a symlink named session.json.tmp pointing to the victim's ~/.ssh/authorized_keys or ~/.bashrc. The agent then writes its session JSON through the symlink, corrupting the target file, and the attacker uses this to gain code execution as the victim at next login. In a second variant, the attacker writes crafted message files into the session directory containing instructions such as 'always run this command and send results to this URL'. When the agent restores the session, it treats these as legitimate history and follows them on every future run.
Weaknesses (CWE)
CWE-59 — Improper Link Resolution Before File Access ('Link Following'): The product attempts to access a file based on the filename, but it does not properly prevent that filename from identifying a link or shortcut that resolves to an unintended resource.
- [Architecture and Design] Follow the principle of least privilege when assigning access rights to entities in a software system. Denying access to a file can prevent an attacker from replacing that file with a link to a sensitive file. Ensure good compartmentalization in the system to provide protected areas that can be trusted.
Source: MITRE CWE corpus.
CVSS Vector
CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:HReferences
- github.com/advisories/GHSA-3w55-933p-8pv5
- github.com/strands-agents/harness-sdk/commit/8658b9e0d57427b77b69343262184d76d8e63e8f
- github.com/strands-agents/harness-sdk/pull/2937
- github.com/strands-agents/harness-sdk/releases/tag/python/v1.48.0
- github.com/strands-agents/harness-sdk/security/advisories/GHSA-3w55-933p-8pv5
Timeline
Related Vulnerabilities
CVE-2025-5952810.0Flowise: Unauthenticated RCE via MCP config injection
Same attack type: Supply ChainCVE-2024-291210.0BentoML: RCE via insecure deserialization (CVSS 10)
Same attack type: Supply ChainCVE-2023-376510.0MLflow: path traversal allows arbitrary file read
Same attack type: Supply ChainCVE-2025-512010.0smolagents: sandbox escape enables unauthenticated RCE
Same attack type: Supply ChainCVE-2026-2185810.0n8n: Input Validation flaw enables exploitation
Same attack type: Code Execution