Back to skill

Security audit

PokeCron · ⌈拍一拍⌋

Security checks for vulnerabilities and agentic risk

Overview

This reminder scheduler is mostly disclosed and purpose-aligned, but its persistent scheduled execution and command-generation code have concrete safety issues that should be reviewed before installation.

Review this skill carefully before installing, especially on macOS or Windows despite the Linux-only wording. Use it only if you want user-level persistent scheduled jobs, avoid command hooks unless the scripts are trusted, avoid executing generated migration commands from untrusted heartbeat config, and inspect or remove created reminders with the management commands when no longer needed.

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/heartbeat-to-poke.sh:153
Finding

Shell Injection in Generated Heartbeat Migration Commands

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
src/scheduler.js:189
Finding

Windows Scheduled-Task Command Injection Through Environment Values

Content
View full analysis
value) .map(([key, value]) => `set "${key}=${String(value).replace(/"/g, '""')}"`) .join(" && "); const command = `${envCommand ? `${envCommand} && ` : ""}${shellEscape(process.execPath)} ${shellEscape( scriptPath )} --deliver ${shellEscape(reminderId)}`; const cwd = path.dirname(scriptPath); ``` ```js cmd.exe /d /s /c "${escapeXml(command)}" ${escapeXml(cwd)} ``` ```js function upsertSchtasks(handle, dueAt, scriptPath, reminderId, envPairs) { const xml = buildWindowsTaskXml(handle, dueAt, scriptPath, reminderId, envPairs); fs.writeFileSync(handle.xmlPath, `\ufeff${xml}`, "utf16le"); execFileSync("schtasks", ["/Create", "/TN", handle.taskName, "/XML", handle.xmlPath, "/F"], { stdio: "ignore" }); } ``` ```js const envPairs = { POKE_STATE_DIR: stateDir, OPENCLAW_STATE_DIR: process.env.OPENCLAW_STATE_DIR || "", OPENCLAW_CONFIG_PATH: process.env.OPENCLAW_CONFIG_PATH || "" }; ``` ### Technical Analysis The Windows backend constructs one command string that sets environment variables and then invokes Node through: ```text cmd.exe /d /s /c ``` Environment values are transformed only by replacing double quotes with two double quotes. This is not a complete escaping strategy for the Windows command processor. `cmd.exe` recognizes metacharacters and expansion syntax including `&`, `|`, `^`, `%...%`, parentheses, and line breaks. XML escaping protects the task XML structure, but ...[truncated 1664 chars]
Remediation
View remediation
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Memory PoisoningPersistent Context Injection, Context Window Stuffing, Memory Manipulation
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (41)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The supplied code does not implement the skill's main declared behavior of creating persisted OS-native timers or running reminder hooks. Instead, it is a narrow macOS entry point for the opt-in heartbeat-to-poke migration helper. That helper is mentioned in the description, so the migration-related behavior itself is not undeclared; however, the description emphasizes Linux-only support while this script explicitly targets macOS, which is a material inconsistency. Therefore this chunk is mismatched relative to the declared purpose.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description presents a full scheduler skill whose primary function is to create persisted OS-native timers and support rich runtime features like command hooks, reply-awareness, escalation, quiet hours, and optional Ollama integration. The supplied code chunk does not implement that scheduler. Instead, it is specifically a conversion/migration utility: it parses openclaw.json, HEARTBEAT.md, and optional heartbeat state, then prints equivalent poke commands to stdout. Its only state-changing behavior is the opt-in --apply patch that disables native heartbeat in openclaw.json with a backup, which matches one narrow part of the description. Quiet-hours/active-hours are only translated into printed flags, not enacted by creating native timers. Since the primary purpose and several key capabilities in the description are absent from the code, this is a material description-behavior mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
90% confidence
Finding

The core declared purpose is mostly accurate: this code clearly implements persisted reminders/tasks, reply-aware handling, escalation, quiet hours/DND, and optional command hooks and vector-tone matching. However, there are material description/behavior gaps. First, the code contains substantial additional capabilities not mentioned in the description: commitment tracking with its own persisted store and CLI, plus path-set storage and placeholder expansion. These are user-facing features, not merely internal implementation details. Second, a notable declared feature—the opt-in --apply migration helper that rewrites OpenClaw config with backup—is absent from this chunk. Third, the description emphasizes Linux-only support, while the code itself does not enforce Linux-only operation and references cross-platform behavior/backend abstraction, making the platform description inaccurate relative to observed behavior. Therefore the description does not fully and accurately represent the supplied code chunk.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The declared description is for a full scheduler/poke system with native timer creation, command execution, optional migration, and optional Ollama integration. The supplied code chunk does none of that. It is clearly a test helper: an in-memory mock runtime used under POKE_RUNTIME_BACKEND=mock, with stub methods that only record calls and return canned values. Its primary purpose is materially different from the declared skill behavior, so this is a strong mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description presents a scheduling/reminder skill whose main function is to create native OS timers and later run commands/prompts. The supplied code does not implement scheduling or timer persistence at all. Its actual purpose is a backend runtime wrapper for OpenClaw: resolving binary/config paths, generating a temporary compatibility config, executing openclaw agent --local / agents list --json, retrying transient failures, and exposing direct CLI access. While some mention of OpenClaw appears in the description, the specific claimed behaviors in the description are absent from this code chunk, and the code instead provides a different subsystem-level capability (agent runtime transport). Therefore the description does not accurately represent this code chunk.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
82% confidence
Finding

The primary purpose broadly matches: this code is clearly for creating persisted OS-native scheduled executions without a daemon, using systemd/launchd/schtasks and running a later delivery command under the user context. However, the description materially misstates platform availability: the code already contains active macOS and Windows implementations, not merely future plans. Additionally, the chunk only schedules a fixed delivery invocation (node <script> --deliver <reminderId>) and passes a few environment variables; it does not show support for the declared configurable command hooks. The migration helper and vector-tone networking features are also absent from this chunk, though those may exist elsewhere. Because the stated platform support is directly contradicted by the code and some declared capabilities are not represented here, this should be flagged as a mismatch.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The comment says "Poke NEVER ... inspects the reply," yet the file contains reply-processing logic that reads inbound reply text, heuristically and agent-classifies it, and then confirms, cancels, snoozes, or triggers pong commands. This is an active contradiction between inline documentation and implemented behavior.

Content

No source excerpt is available for this finding.

Chaining Abuse

High
Category
Tool Misuse
Confidence
86% confidence
Finding

The systemd service runs /bin/sh -c with a compound command that chains delivery, timer disablement, file deletion, and daemon reload using shell metacharacters. Although the individual interpolated values are partly escaped and reminder IDs are sanitized, using a shell at all expands the attack surface and makes the persistence cleanup path brittle; if upstream values such as scriptPath or future arguments bypass escaping, this becomes command-injection with arbitrary code execution under the user account.

Content

Scanner excerpt · src/scheduler.js (reported line 107)May include surrounding context.

js
.map(([key, value]) => `Environment=${systemdEscape(`${key}=${value}`)}`);
  const unitBase = handle.unitName;
  const deliverCmd = [process.execPath, scriptPath, "--deliver", reminderId].map(systemdEscape).join(" ");
  const cleanupCmd = `systemctl --user disable --now ${shellEscape(`${unitBase}.timer`)} 2>/dev/null; rm -f ${shellEscape(handle.servicePath)} ${shellEscape(handle.timerPath)}; systemctl --user daemon-reload`;
  return [
    "[Unit]",
    `Description=Text reminder: ${reminderId}`,

Memory Manipulation

High
Category
Memory Poisoning
Confidence
80% confidence
Finding

Skill manipulates agent memory, state, or stored context. Memory corruption can alter personality, override safety rules, or cause unpredictable behavior.

Content

Scanner excerpt · sub-skills/management.md (reported line 23)May include surrounding context.

text

These bypass the reply classifier (no need for `--reply`). Use them
when the operator (you, the agent, or a script) needs to clear state
directly — not when a user's chat message arrives (that's `--reply`).

## History & stats

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill advertises powerful capabilities including filesystem writes, process execution, environment access, and optional network use, but it does not declare an explicit restrictive tool scope such as permissions or allowed-tools. In a security-sensitive agent ecosystem, this weakens policy enforcement and can let a broadly described skill be invoked with more authority than reviewers or users expect.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The invocation guidance uses broad everyday phrases like 'remind me', 'wake me', 'every morning', and 'keep poking until I reply', which can cause the skill to trigger in ordinary conversation more often than intended. Because this skill can create persisted schedulers and later execute commands or prompts under the user account, accidental invocation has a materially higher security and safety impact than a read-only skill.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The manifest describes a scheduler that persists OS-native timers, runs configured hooks, and optionally uses vector-tone matching. In this file, the --paths-save/--paths-show/--paths-delete features and {{paths:name}} expansion add a separate capability for storing and injecting arbitrary file paths into reminder/task content, which is not disclosed in the manifest description.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The manifest frames the skill as a time-based reminder scheduler with hooks, reply handling, quiet hours, migration helper, and vector-tone mode. This file also implements a separate persisted commitments feature (--commit, --commitments, --commit-done, --commit-cancel) and includes due commitments in task prompts, materially expanding the skill's behavior beyond the stated reminder purpose.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

This code executes persisted user-configured commands automatically via execFileSync during reminder delivery, but there is no runtime consent prompt or execution-time warning when those hooks fire. In this skill's context, reminders are scheduled to run later under the user's account via OS-native timers, so a user may forget hooks were attached and end up with unattended command execution, which materially raises the risk of destructive local actions.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The manifest says the skill is 'Linux only for now; mac coming VERY soon. Windows eventually.' However, backend detection explicitly selects launchd on macOS and schtasks on Windows, and the rest of the file contains concrete create/remove/query implementations for both. This is a direct mismatch between the documented platform scope and actual behavior.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
93% confidence
Finding

This code constructs a LaunchAgents plist path under the user's Library, enabling persisted execution via launchd. In the context of a scheduler skill, persistence is intentional, but it still creates an autorun mechanism under the user's account that can be abused if reminders or command hooks are created without sufficiently explicit user approval.

Content

Scanner excerpt · src/scheduler.js (reported line 82)May include surrounding context.

js
return {
        backend,
        label: `ai.openclaw.poke.${safeId}`,
        plistPath: path.join(os.homedir(), "Library", "LaunchAgents", `ai.openclaw.poke.${safeId}.plist`)
      };
    case "schtasks":
      return {

Session Persistence

Medium
Category
Rogue Agent
Confidence
90% confidence
Finding

The function builds a launchd plist that will later execute the reminder delivery command. Generating persistence artifacts is core functionality here, but launchd registration creates durable execution capability that increases risk if upstream inputs or command hooks are abused.

Content

Scanner excerpt · src/scheduler.js (reported line 144)May include surrounding context.

js
.join("\n");
}

function buildLaunchdPlist(handle, dueAt, scriptPath, reminderId, stateDir, envPairs) {
  const interval = buildLaunchdCalendarParts(dueAt);
  const envXml = Object.entries(envPairs)
    .filter(([, value]) => value)

Session Persistence

Medium
Category
Rogue Agent
Confidence
88% confidence
Finding

This finding is a duplicate match on the same plist-emission site. The relevant risk is persisted execution via launchd, not XML injection, since values are escaped.

Content

Scanner excerpt · src/scheduler.js (reported line 156)May include surrounding context.

js
const logDir = path.join(stateDir, "logs");
  ensureDirectory(logDir);
  return `<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>Label</key>

Session Persistence

Medium
Category
Rogue Agent
Confidence
88% confidence
Finding

This finding is a duplicate match on the same plist-emission site. The relevant risk is persisted execution via launchd, not XML injection, since values are escaped.

Content

Scanner excerpt · src/scheduler.js (reported line 156)May include surrounding context.

js
const logDir = path.join(stateDir, "logs");
  ensureDirectory(logDir);
  return `<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>Label</key>

Session Persistence

Medium
Category
Rogue Agent
Confidence
88% confidence
Finding

This is another match within the launchd plist generation block. The danger comes from establishing a persistent scheduled execution path that survives beyond the current process and can run later without interactive review.

Content

Scanner excerpt · src/scheduler.js (reported line 157)May include surrounding context.

js
ensureDirectory(logDir);
  return `<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>Label</key>
    <string>${escapeXml(handle.label)}</string>

Session Persistence

Medium
Category
Rogue Agent
Confidence
87% confidence
Finding

This location is still part of the plist builder and therefore part of the same persistence mechanism. Persistent scheduler registration is not inherently malicious, but it is security-sensitive because it creates future execution capability under user context.

Content

Scanner excerpt · src/scheduler.js (reported line 185)May include surrounding context.

js
${envXml}
    </dict>
  </dict>
</plist>
`;
}

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

This code creates and removes persistent scheduler artifacts across systemd, launchd, and Windows Task Scheduler using file writes and deletions, but it does so silently with stdio suppressed and without any confirmation prompt, logging, or explanatory comment/docstring. These operations affect system configuration and persistence, which matches the safety-critical file-write/deletion category for code files.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The file invokes systemctl, launchctl, and schtasks to register, restart, stop, disable, and delete scheduled jobs, all with output suppressed and no user-facing warning or nearby explanatory documentation. Because subprocess execution changes system scheduler state and persistence behavior, it should include some form of disclosure unless explicitly documented elsewhere.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
94% confidence
Finding

The code writes the launchd plist to disk, which is the concrete installation step for persistence. In this skill's context, that behavior is expected, but it still materially increases risk because a malicious or mistaken upstream reminder configuration becomes a durable autorun artifact.

Content

Scanner excerpt · src/scheduler.js (reported line 287)May include surrounding context.

js
}

function upsertLaunchd(handle, dueAt, scriptPath, reminderId, envPairs, stateDir) {
  ensureDirectory(path.dirname(handle.plistPath));
  fs.writeFileSync(handle.plistPath, buildLaunchdPlist(handle, dueAt, scriptPath, reminderId, stateDir, envPairs));
  const domain = detectGuiDomain();
  execBestEffort("launchctl", ["bootout", `${domain}/${handle.label}`]);

Session Persistence

Medium
Category
Rogue Agent
Confidence
93% confidence
Finding

This is a duplicate pattern match on the same launchd installation flow. The substantive issue remains persistent scheduled execution via LaunchAgents.

Content

Scanner excerpt · src/scheduler.js (reported line 288)May include surrounding context.

js
function upsertLaunchd(handle, dueAt, scriptPath, reminderId, envPairs, stateDir) {
  ensureDirectory(path.dirname(handle.plistPath));
  fs.writeFileSync(handle.plistPath, buildLaunchdPlist(handle, dueAt, scriptPath, reminderId, stateDir, envPairs));
  const domain = detectGuiDomain();
  execBestEffort("launchctl", ["bootout", `${domain}/${handle.label}`]);
  execBestEffort("launchctl", ["bootout", domain, handle.plistPath]);

Static analysis

Detected: suspicious.dangerous_exec

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
src/reminders.js:457

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
src/runtime/openclaw.js:163

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
src/scheduler.js:46