Back to skill

Security audit

Sleep Snooze

Security checks for vulnerabilities and agentic risk

Overview

The skill matches its stated goal, but it persistently intercepts and stores private messages and has delivery/retention flaws that warrant review before installation.

Install only if you are comfortable with a skill that can suppress notifications across connected providers, store private message contents locally, and add cron jobs on your machine. Review or fix retention, file permissions, digest delivery confirmation, and uninstall/cleanup behavior before relying on it for important messages.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/queue-message.js:81
Finding
Queued private messages are stored with insufficient permission and retention controls## Vulnerability Details **File Location**: `scripts/queue-message.js:81-91`; `scripts/digest.js:85-88` **Vulnerability Type**: Plaintext sensitive-data storage and indefinite retention **Risk Level**: Medium ### Vulnerable Code `scripts/queue-message.js:81-91`: ```js const Database = require('better-sqlite3'); const db = new Database(DB_FILE); const insert = db.prepare(` INSERT INTO queue (provider, sender_id, sender_name, message, received_at) VALUES (?, ?, ?, ?, datetime('now')) `); const result = insert.run(provider, senderId, senderName || senderId, message); db.close(); ``` `scripts/digest.js:85-88`: ```js // Mark all as delivered const ids = rows.map(r => r.id); db.prepare(`UPDATE queue SET delivered = 1 WHERE id IN (${ids.join(',')})`).run(); db.close(); ``` ### Technical Analysis The Skill stores complete private-message bodies, provider identifiers, sender identifiers, and sender names in a local SQLite database. The database and its parent data directory are created without explicit owner-only permissions, so their effective permissions depend on the user's process umask and existing directory permissions. Digest processing only sets `delivered = 1`; it does not delete delivered records or impose a retention period. Consequently, `queue.db` becomes a persistent archive of message history. This conflicts with the declared behavior in `SKILL.md`, which states that the queue is cleared after digest delivery. SQLite parameter binding is correctly used, so the insertion itself is not vulnerable to SQL injection. The issue is the confidentiality and retention of the stored content. ### Attack Path 1. The Skill receives non-urgent messages during a sleep window. 2. `queue-message.js` writes the complete message content and sender metadata to `queue.db`. 3. Morning digest processing marks records as delivered but leaves them in the database. 4. A local account or compromised p ...[truncated 788 chars]
Remediation
## Remediation Suggestions 1. Create the data directory with mode `0700` and verify its existing permissions: ```js fs.mkdirSync(DATA_DIR, { recursive: true, mode: 0o700 }); fs.chmodSync(DATA_DIR, 0o700); ``` 2. Create and maintain `queue.db`, `state.json`, and `vip-contacts.json` with mode `0600`. 3. Delete queue records only after confirmed digest delivery instead of retaining them with a delivered flag. 4. If delivery history is required, make retention explicit and configurable, and purge records after a short documented period. 5. Consider encrypting message content at rest when the host platform provides a suitable user-bound secret or operating-system keystore. 6. Update the privacy documentation to disclose the actual retention behavior.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/digest.js:85
Finding
Digest records are marked delivered before any delivery confirmation## Vulnerability Details **File Location**: `scripts/digest.js:85-103`; `scripts/sleep-init.js:84-87` **Vulnerability Type**: Non-atomic message delivery and premature state transition **Risk Level**: Medium ### Vulnerable Code `scripts/digest.js:85-103`: ```js // Mark all as delivered const ids = rows.map(r => r.id); db.prepare(`UPDATE queue SET delivered = 1 WHERE id IN (${ids.join(',')})`).run(); db.close(); // Update lastDigestAt in state try { const state = JSON.parse(fs.readFileSync(STATE_FILE, 'utf8')); state.lastDigestAt = new Date().toISOString(); fs.writeFileSync(STATE_FILE, JSON.stringify(state, null, 2)); } catch { /* non-fatal */ } // Output digest for OpenClaw to deliver console.log(JSON.stringify({ action: 'deliver_digest', messageCount: rows.length, text: digestText, })); ``` `scripts/sleep-init.js:84-87`: ```js const sleepCron = toCron(sleepStart); const wakeCron = toCron(wakeTime); const sleepJob = `${sleepCron} node ${scriptDir}/set-sleep-mode.js --mode sleep`; const wakeJob = `${wakeCron} node ${scriptDir}/digest.js && node ${scriptDir}/set-sleep-mode.js --mode wake`; ``` ### Technical Analysis `digest.js` changes every selected queue row to the delivered state before emitting the digest JSON and without receiving any acknowledgment that OpenClaw or a provider accepted the message. This violates safe queue-processing semantics: a queued item should remain pending until its downstream delivery succeeds. The generated cron entry directly starts `digest.js` as an ordinary Node.js process. The script only writes JSON to standard output; the reviewed cron command does not pipe that output to an OpenClaw delivery command or otherwise identify a consumer. Therefore, a normal cron execution can mark all messages delivered even though no user-facing digest was sent. A provider outage, OpenClaw failure, terminated process, unconsumed cron output, or d ...[truncated 1167 chars]
Remediation
## Remediation Suggestions 1. Do not update queue records inside the digest-generation operation. 2. Route digest output through a documented OpenClaw delivery API or command rather than relying on unconsumed cron standard output. 3. Have the delivery component acknowledge success with a unique digest or batch identifier. 4. Mark or delete records only after confirmed provider delivery. 5. Use a transactional queue state such as `pending`, `processing`, and `delivered`, with a timeout that returns abandoned `processing` records to `pending`. 6. Preserve pending records and retry with bounded exponential backoff when OpenClaw or a provider is unavailable. 7. Record `lastDigestAt` only after confirmed delivery, not merely after digest generation.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/sleep-init.js:101
Finding
Predictable temporary file permits a local symlink race during crontab installation## Vulnerability Details **File Location**: `scripts/sleep-init.js:101-113` **Vulnerability Type**: Insecure predictable temporary file **Risk Level**: Medium ### Vulnerable Code ```js const newCrontab = [ filtered, `# sleep-snooze: activate sleep mode`, sleepJob, `# sleep-snooze: deliver morning digest and deactivate sleep mode`, wakeJob, '', ].join('\n'); const tmpFile = `/tmp/sleep-snooze-cron-${Date.now()}.txt`; fs.writeFileSync(tmpFile, newCrontab); execSync(`crontab ${tmpFile}`); fs.unlinkSync(tmpFile); ``` ### Technical Analysis The setup script constructs a filename directly under the shared `/tmp` directory using only the current millisecond timestamp. It then opens that path with `fs.writeFileSync` without exclusive creation, without first creating a private temporary directory, and without protecting against symbolic links. A local attacker who predicts or observes the setup timing may pre-create the path as a symbolic link. The write operation follows symbolic links and executes with the victim user's filesystem permissions. Depending on platform hardening and target permissions, this can overwrite or truncate a file writable by the victim. There is also a race interval between writing the temporary file and importing it with `crontab`. A local actor who can replace or modify the file may cause attacker-selected cron content to be installed under the victim's account. Modern protected-symlink settings may mitigate some variants, but the implementation should not depend on optional operating-system hardening. The cron registration itself is disclosed and functionally related to automatic sleep and wake scheduling. It is not an unrelated backdoor and does not, by itself, constitute malicious persistence. ### Attack Path 1. A local attacker monitors for execution of `sleep-init.js` or estimates the `Date.now()` value used in the filename. 2. The attacker creates `/tmp/sleep-snooze ...[truncated 1138 chars]
Remediation
## Remediation Suggestions 1. Create a private temporary directory with `fs.mkdtempSync()` rather than placing a predictable file directly in `/tmp`. 2. Set the temporary directory to mode `0700` and the crontab file to mode `0600`. 3. Open the file with exclusive creation flags such as `O_CREAT | O_EXCL | O_WRONLY`. 4. Invoke `crontab` with `execFileSync('crontab', [tmpFile])` to avoid unnecessary shell interpretation. 5. Remove the temporary directory and file in a `finally` block so failures do not leave sensitive artifacts. 6. Where supported, provide crontab content through standard input instead of a filesystem path. 7. Validate the sleep and wake values before constructing cron expressions.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (21)

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding
The skill introduces persistence mechanisms—cron registration, local state files, SQLite storage, and VIP contact handling—that are materially more invasive than the top-level description suggests. Undisclosed persistence and scheduled execution increase risk because the skill can continue affecting communications and retaining sensitive message content beyond the immediate user interaction.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding
The skill introduces persistence mechanisms—cron registration, local state files, SQLite storage, and VIP contact handling—that are materially more invasive than the top-level description suggests. Undisclosed persistence and scheduled execution increase risk because the skill can continue affecting communications and retaining sensitive message content beyond the immediate user interaction.

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding
The skill introduces persistence mechanisms—cron registration, local state files, SQLite storage, and VIP contact handling—that are materially more invasive than the top-level description suggests. Undisclosed persistence and scheduled execution increase risk because the skill can continue affecting communications and retaining sensitive message content beyond the immediate user interaction.

Natural-Language Policy Violations

High
Confidence
92% confidence
Finding
The urgency bypass relies on simplistic keyword matching and explicitly treats the phrase "help me" as automatically urgent. In a messaging context, an external sender can trivially include that phrase to force immediate delivery during the user's sleep window, bypassing the snooze control and defeating the intended notification suppression policy.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
**Reset everything:**
```bash
rm -rf ~/.openclaw/skills/sleep-snooze/data/
node ~/.openclaw/skills/sleep-snooze/scripts/sleep-init.js
```
Confidence
95% confidence
Finding
The documented `rm -rf ~/.openclaw/skills/sleep-snooze/data/` command irreversibly deletes all local data for the skill, including queued messages and configuration, and is presented without guardrails or a confirmation step. In a user-facing setup guide, destructive shell commands are dangerous because users may execute them verbatim without understanding the permanence of the loss.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
**Reset everything:**
```bash
rm -rf ~/.openclaw/skills/sleep-snooze/data/
node ~/.openclaw/skills/sleep-snooze/scripts/sleep-init.js
```
Confidence
95% confidence
Finding
The documented `rm -rf ~/.openclaw/skills/sleep-snooze/data/` command irreversibly deletes all local data for the skill, including queued messages and configuration, and is presented without guardrails or a confirmation step. In a user-facing setup guide, destructive shell commands are dangerous because users may execute them verbatim without understanding the permanence of the loss.

Lp3

Medium
Category
MCP Least Privilege
Confidence
85% confidence
Finding
The skill invokes environment-dependent behavior (`SLEEP_START`, `WAKE_TIME`, `TIMEZONE`) and multiple local scripts but declares no explicit tool scope or permission boundary. In an agent ecosystem, missing scope makes it easier for the skill to gain broader-than-expected access or be executed in contexts where users and reviewers do not understand that local code and environment state will be used.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
Urgency detection is defined using fixed English keywords like `urgent`, `emergency`, `critical`, `911`, and `help me`. This imposes an English-language policy on a feature that determines whether messages bypass sleep suppression, without giving users a language choice or documenting a justified locale restriction.

Context-Inappropriate Capability

Medium
Confidence
94% confidence
Finding
The manifest describes a skill for snoozing notifications and sending a morning digest. In SKILL.md, the setup flow tells the agent to offer automatic timezone detection using `date +%Z`, which introduces shell-command execution capability not otherwise justified by the declared purpose and not necessary to understand from the manifest alone.

Session Persistence

Medium
Category
Rogue Agent
Content
1. Ask for their sleep start time (e.g. "What time do you usually go to bed?")
2. Ask for their wake time (e.g. "What time do you usually wake up?")
3. Ask for their timezone (offer to detect it automatically using `date +%Z`)
4. Run `node ~/.openclaw/skills/sleep-snooze/scripts/sleep-init.js` to write config and register cron jobs
5. Confirm the schedule back to the user: "Sleep snooze is set: 🌙 10:00 PM → ☀️ 6:00 AM (IST). I'll queue notifications overnight and send your digest at 6:00 AM."

## State Management
Confidence
87% confidence
Finding
Registering cron jobs and writing persistent configuration create durable behavior that continues outside the current session and can affect future message delivery automatically. Persistence is risky here because it changes system state, may survive user expectations, and can keep collecting or processing message data even after the initial setup interaction ends.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The skill stores queued messages locally in SQLite and later summarizes them, but the description does not clearly warn users that potentially sensitive cross-provider communications will be retained on disk. Lack of notice and consent around message retention increases privacy risk, especially if the host system is shared, backed up, or compromised.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The handler passes provider, sender ID, sender name, and message content to another script via a subprocess, which is a data-handling operation involving user communications. In this file there is no confirmation, logging, comment explaining the privacy impact, or other user-facing warning that DMs will be queued and processed externally.

Context-Inappropriate Capability

Medium
Confidence
90% confidence
Finding
The manifest describes snoozing notifications and producing a morning digest, which would reasonably involve filtering and queuing messages. Spawning a separate process via child_process is a broader execution capability than that purpose requires and is not disclosed by the manifest description.

Missing User Warnings

Medium
Confidence
77% confidence
Finding
This code mutates `event.context.bootstrapFiles` to inject `SLEEP_MODE_ACTIVE.md`, which changes agent behavior by preventing outbound messages during sleep mode. Although the injected markdown explains the restriction, the handler itself performs this safety-relevant modification with no logging, comment-level disclosure beyond a skip case, or other visible notice at the point of action.

Intent-Code Divergence

Medium
Confidence
92% confidence
Finding
The generated bootstrap notice says 'Do NOT send any message to the user' and explicitly includes 'digests' in the prohibition. That contradicts the skill's stated purpose of snoozing notifications during sleep and then delivering a morning digest when the user wakes up.

Session Persistence

Medium
Category
Rogue Agent
Content
## Manual Configuration

If you prefer to configure manually, create `~/.openclaw/skills/sleep-snooze/data/state.json`:

```json
{
Confidence
60% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Session Persistence

Medium
Category
Rogue Agent
Content
## Troubleshooting

**Digest not arriving in the morning?**
- Check that cron is running: `crontab -l | grep sleep-snooze`
- Verify Node.js is on your cron PATH: `which node`
- Check the queue manually: `node ~/.openclaw/skills/sleep-snooze/scripts/status.js`
Confidence
85% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The setup guide includes a destructive reset sequence that deletes all local skill data but does not explicitly warn the user that queued messages, state, and VIP contact configuration will be permanently lost. In documentation for an automation skill, omission of a data-loss warning materially increases the chance of accidental destructive use.

Context-Inappropriate Capability

Medium
Confidence
90% confidence
Finding
The setup script installs and rewrites entries in the user's system crontab, giving the skill persistent host-level execution outside the normal OpenClaw runtime. While the feature needs scheduled behavior, directly modifying crontab is broader than necessary and can create persistence, interfere with unrelated cron entries, and execute later in a different security context if paths or files are altered.

Session Persistence

Medium
Category
Rogue Agent
Content
try {
  // Read existing crontab, strip any old sleep-snooze entries, append new ones
  let existing = '';
  try { existing = execSync('crontab -l 2>/dev/null').toString(); } catch { /* no crontab yet */ }

  const filtered = existing
    .split('\n')
Confidence
85% confidence
Finding
Reading and then rewriting the user's crontab establishes persistence for the skill across sessions, which is a security-relevant capability even if intended for scheduling. In this context the persistence is not covert, but it still expands the skill's reach beyond handling notifications and can survive restarts or later file changes, making abuse or unintended execution more impactful.

Missing User Warnings

Low
Confidence
80% confidence
Finding
The skill says to offer automatic timezone detection using `date +%Z`, which inspects local system settings, but the description does not explicitly disclose this behavior as system-data access. Under the missing-warning criterion for markdown files, behaviors affecting privacy or system data should be clearly disclosed.

Static analysis

Detected: suspicious.dangerous_exec, suspicious.destructive_delete_command

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
hooks/dm-guard/handler.js:31

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/gate.js:54

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/sleep-init.js:50

Documentation contains a destructive delete command without an explicit confirmation gate.

Warn
Code
suspicious.destructive_delete_command
Location
references/setup.md:146