T09 · Insecure Skill Coding Practices
Error
- Location
- lib/store.py:90
- Finding
- Plaintext Persistent Session Key Lacks Restrictive File Permissions<![CDATA[ ## Vulnerability Details **File Location**: `lib/store.py:90-107` **Vulnerability Type**: Plaintext cryptographic key storage with insufficient access controls **Risk Level**: High ### Vulnerable Code ```python # Store key in session file (for multi-command usage) self.session_file.write_bytes(self._session_key) print("🔓 Vault unlocked") def lock(self) -> None: """Lock the vault and clear session key.""" self._session_key = None if self.session_file.exists(): self.session_file.unlink() print("🔒 Vault locked") def is_unlocked(self) -> bool: """Check if vault is currently unlocked.""" if self._session_key: return True if self.session_file.exists(): self._session_key = self.session_file.read_bytes() return True return False ``` ### Technical Analysis The derived AES-256 vault key is written directly to `~/.openclaw/vault/session` as plaintext. Unlike the encrypted vault file, the session file is not explicitly assigned mode `0600`. Its effective permissions therefore depend on the process umask. The key remains on disk after the unlocking process terminates and can persist across reboots until `vault lock` is explicitly invoked. Any process or local account able to read this file can decrypt every credential without knowing or brute-forcing the master password. Persisting a raw encryption key is necessary only for the current multi-command session design, not for the core encrypted-storage functionality. The implementation consequently exceeds the minimum exposure required for a memory-only vault session. ### Attack Path 1. The victim executes `vault unlock`. 2. The application derives the AES key and writes it to `~/.openclaw/vault/session`. 3. The victim leaves the vault unlocked or reboots without invoking `vault lock`. 4. A local process or account with permission to read the session file copies its 32-byte contents. 5. The attacker reads `~/.openclaw/vault/vault.enc.json`. ...[truncated 637 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Prefer a memory-only session key and require the user to keep a dedicated process or agent running while the vault is unlocked. 2. If cross-process persistence is required, store the key in an operating-system credential service or protected keyring rather than a regular file. 3. If a file must be used: - Create it atomically with owner-only mode `0600`. - Reject symbolic links and non-regular files. - Verify ownership and permissions before reading it. - Place it in a directory with mode `0700`. - Replace the file atomically rather than following an existing path. 4. Add a short expiration time and remove stale sessions automatically. 5. Clear the session during normal process termination and integrate with operating-system logout or reboot mechanisms where possible. 6. Document that any process running as the vault owner can access secrets while the vault is unlocked. ]]>
