T09 · Insecure Skill Coding Practices
Error
- Location
- SKILL.md:274
- Finding
- Unsafe Hard-Cut Logic Can Corrupt or Destroy Active Session State<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:207-225`, `SKILL.md:274-291`, and `tools/safe-trim.py:86-116` **Vulnerability Type**: Unsafe destructive file handling and session-state corruption **Risk Level**: High ### Vulnerable Code `SKILL.md:274-291`: ```text # 1. Lese <workspace>/.openclaw/agents/main/sessions/sessions.json # 2. Finde alle Keys die ":channel:" enthalten UND KEIN ":thread:" haben # 3. Für jeden solchen Key: prüfe Zeilenanzahl der sessionFile (wc -l) # 4. Wenn > 500 Zeilen UND updatedAt > 2h her: # a. Generiere Hash: TRIM_READY_<4 random chars> # b. sessions_send(sessionKey=<key>, timeoutSeconds=90, # message="[WARTUNG] Schreibe jetzt alle offenen Themen und wichtigen Kontext # in memory/active-context.md. Füge danach exakt diese Zeile am Ende ein: # TRIM_HASH: <hash> # Antworte ausschließlich mit NO_REPLY.") # c. Lese memory/active-context.md → suche nach "TRIM_HASH: <hash>" # d. Hash gefunden: # - tail -60 <sessionFile> > /tmp/trim.jsonl && mv /tmp/trim.jsonl <sessionFile> # - Entferne TRIM_HASH-Zeile aus active-context.md # - Log: "<ISO> | <key> | TRIMMED" → memory/trim-log.txt # e. Hash nicht gefunden (Timeout): # - tail -60 <sessionFile> > /tmp/trim.jsonl && mv /tmp/trim.jsonl <sessionFile> # - Log: "<ISO> | <key> | FORCE-TRIM" → memory/trim-log.txt ``` `tools/safe-trim.py:86-116`: ```python # Find safe cutpoints: assistant turns with no pending toolCall candidates = [] for i, line in enumerate(lines): try: entry = json.loads(line) msg = entry.get("message", {}) if msg.get("role") != "assistant": continue content = msg.get("content", []) has_tool_call = any( isinstance(c, dict) and c.get("type") == "toolCall" for c in content ) if not has_tool_call: candidates.append(i) except Exception: continue # Pick the last candidate that s ...[truncated 3614 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Remove every raw `tail -60` truncation instruction and invoke one validated trimming implementation instead. 2. Never hard-cut when no safe boundary exists. Abort the operation, log the condition, and retry after the session reaches a valid completed turn. 3. Validate complete protocol relationships, including tool-call identifiers and corresponding tool results, rather than checking only whether an assistant message contains a `toolCall`. 4. Acquire an exclusive lock before reading and rewriting a session file. Recheck its inode, size, and modification time while holding the lock. 5. Write to a uniquely named temporary file in the same directory as the target, flush it with `fsync`, validate every retained JSONL record, and use an atomic replacement operation. 6. Avoid a predictable shared path such as `/tmp/trim.jsonl`. Use `tempfile.NamedTemporaryFile` or `mkstemp` with restrictive permissions. 7. Require both inactivity and a successful hash handshake before trimming. A timeout should postpone trimming rather than authorize destructive force trimming. 8. Preserve versioned backups and implement automatic rollback if the retained session fails JSON parsing or tool-exchange validation. 9. Restrict accepted session paths to the expected session directory after canonicalization, and reject symbolic links and non-regular files. 10. Add tests for concurrent writes, unmatched tool calls, unmatched tool results, malformed JSON lines, sessions without safe cut points, and simultaneous trim operations. ]]>
