T09 · Insecure Skill Coding Practices
- Location
scripts/lib/storage.py:24- Finding
Insecure Permissions and Predictable Temporary Files for Sensitive Travel Data
- Content
View full analysis
Vulnerability Details
File Location:
scripts/init_storage.py:6-13;scripts/lib/storage.py:6-12;scripts/lib/storage.py:24-29
Vulnerability Type: Plaintext sensitive-data storage, unmanaged filesystem permissions, and unsafe temporary-file handling
Risk Level: MediumVulnerable Code
scripts/init_storage.py:6-13:python HOTEL_DIR = os.path.expanduser("~/.openclaw/workspace/memory/hotel") TRIPS_FILE = os.path.join(HOTEL_DIR, "trips.json") HOTELS_FILE = os.path.join(HOTEL_DIR, "hotels.json") PREFS_FILE = os.path.join(HOTEL_DIR, "preferences.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)scripts/lib/storage.py:6-12:python HOTEL_DIR = os.path.expanduser("~/.openclaw/workspace/memory/hotel") TRIPS_FILE = os.path.join(HOTEL_DIR, "trips.json") HOTELS_FILE = os.path.join(HOTEL_DIR, "hotels.json") PREFS_FILE = os.path.join(HOTEL_DIR, "preferences.json") def ensure_dir(): os.makedirs(HOTEL_DIR, exist_ok=True)scripts/lib/storage.py:24-29:python 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)Technical Analysis
The skill stores destinations, travel dates, budgets, purposes, notes, hotel candidates, and reusable preferences as plaintext JSON. The storage directory and files are created without explicit restrictive modes. Their effective permissions therefore depend on the process umask and any pre-existing directory permissions.
os.makedirs(..., exist_ok=True)also does not correct an existing directory that has overly permissive permissions. Likewise, ordinaryopen(path, "w")creation uses permissions derived from the current u ...[truncated 2782 chars]- Remediation
View remediation
Remediation Suggestions
-
Create and enforce the storage directory as owner-only:
python os.makedirs(HOTEL_DIR, mode=0o700, exist_ok=True) os.chmod(HOTEL_DIR, 0o700) -
Create initial data files with mode
0600by usingos.openwith explicit flags and permissions rather than relying on the process umask:python fd = os.open(path, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600) with os.fdopen(fd, "w", encoding="utf-8") as f: json.dump(payload, f, indent=2, ensure_ascii=False) -
Replace the fixed
.tmpname with a securely created temporary file in the same directory:python import tempfile directory = os.path.dirname(path) fd, tmp = tempfile.mkstemp(prefix=".hotel-", suffix=".tmp", dir=directory) try: os.fchmod(fd, 0o600) 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) finally: if os.path.exists(tmp): os.unlink(tmp) -
Validate that the storage directory is a real directory owned by the current user and is not a symbolic link before writing.
-
Check and repair permissions on existing JSON files during initialization. Refuse to operate, or issue a clear warning, if ownership or directory permissions are unsafe.
-
Consider minimizing sensitive free-form notes and documenting that the files are plaintext. If stronger local confidentiality is required, use operating-system-backed encryption or a suitable protected credential/data store.
-
