T05 · Unauthorized Access and Privilege Escalation
Warning
- Location
- record.py:83
- Finding
- Global latest-session selection can record an unrelated conversation<![CDATA[ ## Vulnerability Details **File Location**: `record.py:15`, `record.py:83-106` **Related Location**: `skill.py:18`, `skill.py:141-164`, `skill.py:209-224` **Vulnerability Type**: `T05: Unauthorized Access and Privilege Escalation` **Risk Level**: Medium ### Vulnerable Code ```python SESSIONS_DIR = Path.home() / ".openclaw" / "agents" / "main" / "sessions" ``` ```python def get_latest_session_file(): """获取最新的会话文件""" # 查找今天的会话文件 today_str = datetime.now().strftime('%Y-%m-%d') patterns = [ SESSIONS_DIR / f"*{today_str}*.jsonl", SESSIONS_DIR / f"*.jsonl.reset.*", SESSIONS_DIR / f"*.jsonl", ] latest_file = None latest_mtime = 0 for pattern in patterns: for filepath in glob.glob(str(pattern)): try: mtime = os.path.getmtime(filepath) if mtime > latest_mtime: latest_mtime = mtime latest_file = filepath except: pass return latest_file ``` ### Technical Analysis The declared purpose is to record the current conversation after a session ends. Instead of receiving an authenticated current-session identifier, the implementation enumerates all JSONL files in the main agent's session directory and selects whichever file has the newest modification time. File modification time is not an authorization or session-identity boundary. In an environment with concurrent sessions, different channels, multiple users, or reset files, the newest file may belong to a different conversation. The fallback patterns also include every `*.jsonl` file and every `*.jsonl.reset.*` file, broadening access beyond the minimum scope necessary to record the invoking session. The same selection logic is duplicated in `skill.py`. This issue does not grant additional operating-system privileges, but it breaks conversation-level isolation by allowing the recorder to read and duplicate a session o ...[truncated 1551 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Require the OpenClaw runtime to pass an explicit current-session ID or exact session-file path to the recorder. 2. Resolve the supplied path with `Path.resolve()` and verify that it remains beneath the expected session directory. 3. Validate that the session identifier belongs to the invoking agent, user, and channel. 4. Reject reset files and files that do not match the expected session format. 5. Do not use modification time to determine which session the caller is authorized to record. 6. If an explicit session identity is unavailable, fail closed rather than recording the globally newest session. 7. Add tests covering concurrent sessions, reset files, symlinks, multiple channels, and rapid modification-time changes. 8. Consolidate the duplicated implementation in `record.py` and `skill.py` so that security fixes cannot diverge. ]]>
