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

Content
View full analysis

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
View 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

Content
View full analysis

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
View 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

Content
View full analysis

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
View 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.

Content

No source excerpt is available for this finding.

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.

Content

No source excerpt is available for this finding.

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.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

High
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Tool Parameter Abuse

High
Category
Tool Misuse
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.

Content

Scanner excerpt · references/setup.md (reported line 146)May include surrounding context.

Reset everything:

bash
rm -rf ~/.openclaw/skills/sleep-snooze/data/
node ~/.openclaw/skills/sleep-snooze/scripts/sleep-init.js

Tool Parameter Abuse

High
Category
Tool Misuse
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.

Content

Scanner excerpt · references/setup.md (reported line 146)May include surrounding context.

Reset everything:

bash
rm -rf ~/.openclaw/skills/sleep-snooze/data/
node ~/.openclaw/skills/sleep-snooze/scripts/sleep-init.js

Undeclared Tool Scope

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.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
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.

Content

Scanner excerpt · SKILL.md (reported line 123)May include surrounding context.

md
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

Missing User Warnings

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
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.

Content

Scanner excerpt · references/setup.md (reported line 34)May include surrounding context.

Manual Configuration

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

json
{

Session Persistence

Medium
Category
Rogue Agent
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.

Content

Scanner excerpt · references/setup.md (reported line 136)May include surrounding context.

md
## 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`

Missing User Warnings

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
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.

Content

Scanner excerpt · scripts/sleep-init.js (reported line 93)May include surrounding context.

js
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')

Missing User Warnings

Low
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

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