T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/lib/storage.py:6
- Finding
- Potentially Sensitive Case Data Stored Without Restrictive File Permissions## Vulnerability Details **File Location**: `scripts/lib/storage.py:6-27` and `scripts/init_storage.py:6-16` **Vulnerability Type**: Plaintext sensitive-data storage with permissions dependent on the process umask **Risk Level**: Medium ### Vulnerable Code `scripts/lib/storage.py:6-27`: ```python VERIFIER_DIR = os.path.expanduser("~/.openclaw/workspace/memory/verifier") CASES_FILE = os.path.join(VERIFIER_DIR, "cases.json") def ensure_dir(): os.makedirs(VERIFIER_DIR, exist_ok=True) def _safe_load(path, default): ensure_dir() if not os.path.exists(path): return default try: with open(path, "r", encoding="utf-8") as f: return json.load(f) except (json.JSONDecodeError, OSError): return default def _atomic_save(path, data): ensure_dir() tmp = path + ".tmp" with open(tmp, "w", encoding="utf-8") as f: json.dump(data, f, indent=2, ensure_ascii=False) os.replace(tmp, path) ``` `scripts/init_storage.py:6-16`: ```python VERIFIER_DIR = os.path.expanduser("~/.openclaw/workspace/memory/verifier") CASES_FILE = os.path.join(VERIFIER_DIR, "cases.json") def write_json_if_missing(path, payload): if not os.path.exists(path): with open(path, "w", encoding="utf-8") as f: json.dump(payload, f, indent=2, ensure_ascii=False) def main(): os.makedirs(VERIFIER_DIR, exist_ok=True) write_json_if_missing(CASES_FILE, { ``` ### Technical Analysis The Skill stores arbitrary claims, suspicious messages, profile information, offers, notes, source labels, and evidence in a plaintext JSON file under the user's home directory. This information may contain personal, confidential, or security-sensitive data. The storage directory, final JSON file, and predictable temporary file are created without explicit owner-only permissions. Their permissions consequently depend on the process umask. Under a common `022` umask, newly created directories are typically mode `0755` and files m ...[truncated 1776 chars]
- Remediation
- ## Remediation Suggestions 1. Create the storage directory with owner-only permissions and repair permissions if it already exists: ```python def ensure_dir(): os.makedirs(VERIFIER_DIR, mode=0o700, exist_ok=True) os.chmod(VERIFIER_DIR, 0o700) ``` 2. Securely create the temporary file with mode `0600` rather than relying on the process umask: ```python def _atomic_save(path, data): ensure_dir() tmp = path + ".tmp" fd = os.open(tmp, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o600) try: with os.fdopen(fd, "w", encoding="utf-8") as f: json.dump(data, f, indent=2, ensure_ascii=False) f.flush() os.fsync(f.fileno()) os.replace(tmp, path) os.chmod(path, 0o600) except Exception: try: os.unlink(tmp) except OSError: pass raise ``` 3. Prefer `tempfile.NamedTemporaryFile` in the same directory with restrictive permissions and a non-predictable name, followed by `os.replace()`. 4. During initialization, inspect and correct permissions on an existing storage directory and `cases.json`. 5. Document that case records are stored in plaintext and advise users not to include credentials, authentication tokens, private keys, or unnecessary personal data. 6. If the deployment threat model includes hostile local users or compromised backups, provide authenticated encryption at rest with keys stored separately from the case database.
