T09 · Insecure Skill Coding Practices
- Location
scripts/sessions_cli.py:91- Finding
Path Traversal Enables Deletion of Files Outside the Session Directory
- Content
View full analysis
Vulnerability Details
File Location:
scripts/sessions_cli.py, lines 91–93
Vulnerability Type: Path traversal and insufficient path validation
Risk Level: HighVulnerable Code:
python session_file = SESSIONS_DIR / f"{found_data.get('sessionId', found_key)}.jsonl" if session_file.exists(): session_file.unlink()Technical Analysis
The history filename is constructed from the
sessionIdvalue stored in~/.openclaw/agents/main/sessions/sessions.json. The application treats this metadata as trusted and does not validate that the identifier is a UUID or otherwise a safe filename.A value containing
..path components can escapeSESSIONS_DIR. An absolute path can also causepathlibto discard the intended base directory. The code neither rejects path separators nor resolves the candidate path and verifies that it remains inside the expected session directory.The appended
.jsonlextension restricts potential targets to filenames ending in.jsonl, but it does not prevent deletion outside session storage.Attack Path
-
An attacker or compromised local component obtains write access to
~/.openclaw/agents/main/sessions/sessions.json. -
The attacker creates or modifies a session record with a benign session key and a malicious
sessionId, such as../../../../path/to/target. -
The victim invokes:
bash python3 scripts/sessions_cli.py delete <benign-session-key> -
The CLI finds the record by its session key.
-
It constructs a path equivalent to:
text ~/.openclaw/agents/main/sessions/../../../../path/to/target.jsonl -
If the resolved target exists and is writable by the current user,
unlink()deletes it.
Impact Assessment
Successful exploitation allows deletion of an arbitrary existing
.jsonlfile accessible to the user running the CLI. This can result in loss of application data, logs, session ...[truncated 574 chars]-
- Remediation
View remediation
Remediation Suggestions
-
Validate
sessionIdagainst the identifier format expected by OpenClaw. If session IDs must be UUIDs, parse them with Python'suuid.UUIDand reject invalid values. -
Reject identifiers containing path separators, absolute paths,
.components, or..components. -
Resolve both the session directory and candidate history path before deletion, then verify that the candidate's parent is exactly the approved directory:
python from uuid import UUID raw_id = found_data.get("sessionId") try: safe_id = str(UUID(raw_id)) except (TypeError, ValueError, AttributeError): raise ValueError("Invalid session ID") base_dir = SESSIONS_DIR.resolve() session_file = (base_dir / f"{safe_id}.jsonl").resolve() if session_file.parent != base_dir: raise ValueError("Session file is outside the session directory") if session_file.is_file(): session_file.unlink() -
Consider deleting the history file before committing the metadata update, or perform both operations transactionally where possible, to avoid inconsistent state when deletion fails.
-
Handle filesystem and malformed-JSON errors explicitly and return a nonzero exit status without partially updating session metadata.
-
