Back to skill

Security audit

Hotel

Security checks for vulnerabilities and agentic risk

Overview

This skill is a local hotel-planning helper that stores trip and hotel details on the user's machine without network access or credential use.

Install only if you are comfortable storing destinations, travel dates, budgets, hotel candidates, and notes as plaintext JSON under ~/.openclaw/workspace/memory/hotel. For shared machines or sensitive travel plans, restrict file permissions or avoid saving sensitive notes.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/lib/storage.py:24
Finding
Insecure Permissions and Predictable Temporary Files for Sensitive Travel Data## 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**: Medium ### Vulnerable 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, ordinary `open(path, "w")` creation uses permissions derived from the current u ...[truncated 2782 chars]
Remediation
## Remediation Suggestions 1. Create and enforce the storage directory as owner-only: ```python os.makedirs(HOTEL_DIR, mode=0o700, exist_ok=True) os.chmod(HOTEL_DIR, 0o700) ``` 2. Create initial data files with mode `0600` by using `os.open` with 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) ``` 3. Replace the fixed `.tmp` name 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) ``` 4. Validate that the storage directory is a real directory owned by the current user and is not a symbolic link before writing. 5. 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. 6. 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.
Vulnerability Patterns
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (4)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The declared description emphasizes hotel-focused decision support: capturing hotel options, comparing properties, scoring tradeoffs, and surfacing the best-fit hotel. The supplied code does not do any of that. It only adds a new trip entry to storage and calculates the number of nights from check-in/check-out dates. While storing trip context could be a supporting part of a larger hotel-planning system, this specific code chunk’s primary behavior is trip record creation, not hotel decisioning. Therefore the description does not accurately represent what this code chunk actually does.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The declared description presents a broad hotel decision and recommendation system with comparison, tradeoff scoring, shortlist support, and accommodation planning. The supplied code only saves one preference key/value pair to storage. While preference storage could be a supporting component of such a system, this chunk by itself does not implement or demonstrate the primary declared capabilities. Therefore the code behavior is materially narrower than the declared purpose, indicating a mismatch.

Lp3

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding
The skill declares file read/write behavior through local storage but does not define any explicit tool scope or permissions boundary. In an agent environment, this can cause the skill to receive broader filesystem capabilities than intended, increasing the risk of unintended local data access or modification if the skill is invoked in the wrong context.

Vague Triggers

Medium
Confidence
94% confidence
Finding
The activation language is broad enough to match ordinary travel conversation, making accidental invocation more likely. Because the skill can write local memory files, overbroad triggering increases the chance of unintended data capture, persistence of user travel details, or interference with other travel-related skills.

Static analysis

No suspicious patterns detected.