Back to skill

Security audit

Cron Local

Security checks for vulnerabilities and agentic risk

Overview

This skill is a local reminder schedule manager that stores schedule data on the user's machine and does not show evidence of network sync, hidden execution, or credential access.

Install only if you are comfortable with reminders, notes, and tags being stored locally under ~/.openclaw/workspace/memory/cron. Confirm before allowing the agent to create or modify jobs, override the timezone if Asia/Tokyo is not correct for you, and avoid putting highly sensitive details in job notes unless your local account and home directory permissions are protected.

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 (2)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/lib/storage.py:24
Finding
Schedule data files are created without enforced restrictive permissions## Vulnerability Details **File Location**: `scripts/init_storage.py:11-14`; `scripts/lib/storage.py:24-29` **Vulnerability Type**: Insecure local file permissions **Risk Level**: Medium ### Vulnerable Code `scripts/init_storage.py:11-14` ```python 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: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 job titles, notes, tags, schedule metadata, and run information in JSON files under `~/.openclaw/workspace/memory/cron`. Both initial creation and subsequent atomic saves rely exclusively on process-default permissions. The code does not explicitly enforce mode `0600` on data files or mode `0700` on the storage directory. Consequently, the effective permissions depend on the caller's umask and existing parent-directory configuration. In an environment with a permissive umask, other local users may be able to read schedule data. Atomic updates create a new fixed-name temporary file and replace the destination with it. The replacement file inherits the temporary file's newly derived permissions rather than preserving a previously hardened destination mode. ### Attack Path 1. A user runs the Skill in an environment with a permissive umask or inadequately protected parent directories. 2. The user creates a schedule containing private information in its title, notes, tags, or timing metadata. 3. `init_storage.py` or `_atomic_save()` creates the corresponding JSON file without explicitly restrictive permissions. 4. Another local account examines `~/.openclaw/workspace/memory/cron`. ...[truncated 703 chars]
Remediation
## Remediation Suggestions - Create the storage directory with mode `0700` and verify its ownership before use. - Create data and temporary files with mode `0600`, independent of the process umask. - Apply `os.chmod(path, 0o600)` to existing files after validating that they are owned by the expected user. - Use secure, exclusive temporary-file creation, such as `tempfile.mkstemp()` in the destination directory. - Flush and synchronize the temporary file before replacement when durability is required. - Verify that destination and temporary paths are regular files and are not unexpected symbolic links. - Preserve restrictive permissions across atomic replacements.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/add_job.py:49
Finding
Truncated UUID job identifiers can silently overwrite existing jobs## Vulnerability Details **File Location**: `scripts/add_job.py:49`; `scripts/add_job.py:81-83` **Vulnerability Type**: Insufficient identifier entropy and missing collision detection **Risk Level**: Medium ### Vulnerable Code `scripts/add_job.py:49` ```python job_id = f"JOB-{str(uuid.uuid4())[:4].upper()}" ``` `scripts/add_job.py:81-83` ```python data = load_jobs() data["jobs"][job_id] = job save_jobs(data) ``` ### Technical Analysis Although the code generates a UUIDv4 value, it retains only the first four hexadecimal characters. This produces an identifier space of only 65,536 possible values. The generated identifier is used directly as a dictionary key without checking whether it already exists. If a collision occurs, the assignment replaces the existing job object in memory, and `save_jobs()` persists that replacement. No warning, confirmation, retry, or backup is performed. Under the birthday paradox, collision probability increases substantially as the number of generated jobs grows. An actor capable of repeatedly invoking `add_job.py` can accelerate this condition, although selecting a particular victim identifier remains probabilistic because UUID generation is random. ### Attack Path 1. A valid existing job is stored under an identifier such as `JOB-ABCD`. 2. A user or automated process repeatedly invokes `add_job.py`. 3. A newly generated UUID eventually has the same first four hexadecimal characters as an existing job. 4. The code executes `data["jobs"][job_id] = job` without detecting the collision. 5. The existing job is silently replaced by the newly supplied title, schedule, notes, and other fields. 6. `save_jobs(data)` commits the data loss to `jobs.json`. Exploitation requires permission to invoke the local job-creation workflow and write the Skill's storage files. The collision is probabilistic rather than a deterministic overwrite of a selected job. ### Impact Assessment A ...[truncated 396 chars]
Remediation
## Remediation Suggestions - Use the complete UUID value as the persistent job identifier. - If short human-readable identifiers are required, use substantially more entropy and check for collisions before insertion. - Generate identifiers only after loading current jobs, and retry while the candidate identifier already exists. - Refuse to overwrite an existing dictionary key unless the caller explicitly requests an update operation. - Save a recoverable backup or maintain an append-only change history for critical schedule records. - Add automated tests that force duplicate identifiers and verify that existing jobs remain unchanged.
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • 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
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (4)

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding
The skill advertises capabilities such as natural-language schedule capture, pause/resume, job inspection, and recurring schedule storage, but the analyzed behavior reportedly does not implement those functions. This mismatch is dangerous because users and orchestrators may trust the skill to manage time-based actions correctly when it may silently fail, mis-schedule, or omit expected controls like pause/resume.

Lp3

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding
The skill declares local file storage and references multiple scripts that read and write under the user's home directory, but it does not declare any explicit tool scope or permissions boundary. That omission can cause the agent to invoke file-capable behavior without clear user-visible constraints, increasing the risk of unintended file access or modification.

Vague Triggers

Medium
Confidence
96% confidence
Finding
The description uses very broad activation cues like recurring timing, schedules, cadence, and weekly/daily/monthly routines, which can cause the skill to trigger on ordinary planning conversations. Unintended activation is risky here because the skill has local file-writing behavior and may create or alter persistent schedule state when the user did not intend to invoke it.

Natural-Language Policy Violations

Low
Confidence
93% confidence
Finding
The script sets `--timezone` to `Asia/Tokyo` by default, which imposes a specific locale assumption on all users unless they explicitly override it. This is a natural-language policy concern because the file provides no user opt-in, choice prompt, or documented regional justification for that default.

Static analysis

No suspicious patterns detected.