Back to skill

Security audit

schedule-reminder

Security checks for vulnerabilities and agentic risk

Overview

The skill is a real reminder tool, but it automatically installs background scheduled jobs that keep running and can send stored schedule details without clear opt-in or uninstall controls.

Review this skill before installing. It will create persistent OS-level scheduled tasks, store reminder data locally, and send reminder or briefing content through configured messaging channels. Install only if you want background reminder checks and daily briefings, and be prepared to manually remove cron or LaunchAgent entries if you uninstall the skill.

Vulnerability Patterns
  • System PersistenceInstalls backdoors, hooks, services, or scheduled tasks that survive the run
  • 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)

T06 · System Persistence

Warning
Location
scripts/install.mjs:92
Finding

Automatic Installation of Persistent OS-Level Scheduled Tasks

Content
View full analysis
/dev/null || echo ""`, { encoding: 'utf-8', }); let nextCrontab = currentCrontab.trim(); let modified = false; if (!nextCrontab.includes(BACKUP_SCRIPT)) { nextCrontab += `\n# 双保险提醒系统 - 备用检查\n${backupCronLine}\n`; modified = true; } if (!nextCrontab.includes(DAILY_BRIEF_SCRIPT)) { nextCrontab += `\n# 双保险提醒系统 - 每日早报\n${dailyCronLine}\n`; modified = true; } if (!modified) { console.log('ℹ️ Linux crontab 已配置'); return; } execSync(`printf %s ${shellQuote(nextCrontab)} | ${crontabBin} -`, { stdio: 'ignore' }); console.log('✅ Linux crontab 已更新'); ``` On macOS, the generated backup LaunchAgent is configured to run at login and every 60 seconds: ```xml RunAtLoad StartInterval 60 ``` The installer then loads and enables both the backup worker and daily-briefing LaunchAgents: ```js try { execSync(`launchctl bootstrap gui/${uid} ${shellQuote(plistPath)}`, { stdio: 'ignore' }); execSync(`launchctl enable gui/${uid}/${SERVICE_LABEL}`, { stdio: 'ignore' }); execSync(`launchctl bootstrap gui/${uid} ${shellQuote(dailyPlistPath)}`, { stdio: 'ignore' }); execSync(`launchctl enable gui/${uid}/${DAILY_SERVICE_LABEL}`, { stdio: 'ignore' ...[truncated 3151 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • YARA SignaturesMalware Match, Webshell Match, Cryptominer Match
Findings (43)

Vague Triggers

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The trigger list includes very broad everyday words such as '明天', '下午', '会议', '计划', and '安排', which can appear in many normal conversations unrelated to reminder creation. In this skill's context, that can cause unintended activation, silent extraction of schedule details, and unwanted creation or sending of reminders across external channels.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
node scripts/install.mjs

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The script executes a binary path selected from environment variables or runtime configuration, allowing externally influenced command execution in the context of this skill. Even though execFileSync avoids shell injection, an attacker who can modify OPENCLAW_BIN or the runtime file can redirect execution to a malicious program and gain arbitrary code execution when the briefing runs.

Content

No source excerpt is available for this finding.

YARA rule 'backdoor_persistence': Backdoor persistence with malicious payloads (shell commands, SSH key injection, hidden root users) [malware]

High
Category
YARA Match
Confidence
75% confidence
Finding

YARA rule matched a known malware signature (reverse shell, backdoor, ransomware, C2 framework, or info stealer).

Content

Scanner excerpt · scripts/install.mjs (reported line 81)May include surrounding context.

js
bin:/sbin:/bin')}`,
    openclawBin ? `OPENCLAW_BIN=${shellQuote(openclawBin)}` : '',
    `${shellQuote(nodeBin)} ${shellQuote(DAILY_BRIEF_SCRIPT)} >> ${shellQuote(LOG_FILE)} 2>&1`,
  ].filter(Boolean).join(' ');

  const backupCronLine = `* * * * * /bin/sh -lc ${shellQuote(shellCommand)}`;
  const dailyCronLine = `0 8 * * * /bin/sh -lc ${shellQuote(dailyShellCommand)}`;

  try {
    const currentCrontab = execSync(`${crontabBin} -l 2>/dev/null || echo ""`, {
      encoding: 'utf-8',
    });

    let nextCrontab = currentCrontab.trim();
    let modified = false;
    
    if (!nextCrontab.includes(BACKUP_SCRIPT)) {
      nextCrontab += `\n# 双保险提醒系统 - 备用检查\n${backupCronLine}\n`;
      modified = true;
    }
    
    if (!nextCrontab.includes(DAILY_BRIEF_SCRIPT)) {
      nextCrontab += `\n# 双保险提醒系统 - 每日早报\n${dailyCronLine}\n`;
      modified = true;
    }

    if (!modified) {
      console.log('ℹ️  Linux crontab 已配置');
      return;

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
84% confidence
Finding

The skill declares required tools for cron and messaging, but it does not explicitly scope or document broader capabilities such as environment-variable access that may be used by associated scripts. Missing permission boundaries makes it harder to review what sensitive data the skill may read, and increases the chance of over-privileged execution during installation or reminder delivery.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The skill advertises daily automatic schedule pushes and multi-channel delivery to platforms like WeChat and Telegram, yet it does not provide a clear privacy notice about what data is collected, stored, or transmitted. Because reminders may contain sensitive personal or business schedule information, users may unknowingly expose data to local files, logs, cron jobs, or third-party messaging services.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The dialogue-trigger behavior is underspecified and encourages proactive capture of time-and-task information from ordinary conversation, but it does not define strict boundaries, exclusions, or consent requirements. This increases the risk of the assistant inferring reminders from incidental discussion and storing or forwarding personal scheduling information without sufficiently explicit user intent.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

Hard-coding a default timezone of Asia/Shanghai without clear user choice or applicability constraints can cause reminders to fire at the wrong local time. For a scheduling skill, this context makes the issue more consequential because mistimed reminders can lead to missed deadlines, meetings, or accidental disclosure when messages are sent at unintended times.

Content

No source excerpt is available for this finding.

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 · SKILL.md (reported line 154)May include surrounding context.

md
**提醒没收到?**
1. 检查配置:`cat ~/.openclaw/data/schedule-reminder-config.json`
2. 查看日志:`tail ~/.openclaw/data/reminder-backup.log`
3. 检查 crontab:`crontab -l | grep reminder`
4. 手动测试:`node scripts/reminder-backup.mjs`

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The package description is written entirely in Chinese, and the user-facing configuration descriptions are also Chinese-only. This indicates the skill is presented in a fixed language without any documented opt-in, choice, or justification for a locale-specific audience.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The script explicitly formats time using the 'zh-CN' locale, which forces a specific language/locale behavior regardless of user preference. This is a natural-language policy concern because the file does not offer any language or locale choice or document a justified region-specific constraint.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

Natural-language strings and time formatting are fixed to Chinese, including toLocaleTimeString('zh-CN', ...) and all user-facing messages. Under the policy, forcing a specific language or locale without opt-in is a violation unless it is clearly documented and justified as region-specific.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The manifest describes a schedule reminder skill focused on creating reminders, extracting schedule information from conversation, and sending daily schedule previews. This code constructs a richer '幕僚早报' message that includes advisor goals and suggestions from event metadata, which is materially broader than a plain schedule preview and aligns with a briefing/advisory function not stated in the manifest.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The script reads locally stored reminders and sends their contents through an external messaging command, which can expose sensitive schedule details to external channels without clear consent or visibility at execution time. In a reminder skill, calendar items may contain private names, meeting details, deadlines, or strategy notes, so silent transmission increases confidentiality risk.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
97% confidence
Finding

This code reads and rewrites the user's crontab to add recurring tasks, which is a form of persistence. In the context of an installer for a reminder skill, that persistence is functionally expected, but it remains security-sensitive because it causes code to execute indefinitely and could be abused if the installed scripts are later modified.

Content

Scanner excerpt · scripts/install.mjs (reported line 81)May include surrounding context.

js
const dailyCronLine = `0 8 * * * /bin/sh -lc ${shellQuote(dailyShellCommand)}`;

  try {
    const currentCrontab = execSync(`${crontabBin} -l 2>/dev/null || echo ""`, {
      encoding: 'utf-8',
    });

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% 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 · scripts/install.mjs (reported line 115)May include surrounding context.

js
function installMacLaunchd({ nodeBin, openclawBin }) {
  const launchAgentsDir = path.join(HOME_DIR, 'Library', 'LaunchAgents');
  const plistPath = path.join(launchAgentsDir, `${SERVICE_LABEL}.plist`);
  const dailyPlistPath = path.join(launchAgentsDir, `${DAILY_SERVICE_LABEL}.plist`);
  const uid = execSync('id -u', { encoding: 'utf-8' }).trim();
  const envPath = process.env.PATH || '/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin';

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% 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 · scripts/install.mjs (reported line 116)May include surrounding context.

js
function installMacLaunchd({ nodeBin, openclawBin }) {
  const launchAgentsDir = path.join(HOME_DIR, 'Library', 'LaunchAgents');
  const plistPath = path.join(launchAgentsDir, `${SERVICE_LABEL}.plist`);
  const dailyPlistPath = path.join(launchAgentsDir, `${DAILY_SERVICE_LABEL}.plist`);
  const uid = execSync('id -u', { encoding: 'utf-8' }).trim();
  const envPath = process.env.PATH || '/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin';

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% 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 · scripts/install.mjs (reported line 122)May include surrounding context.

js
function installMacLaunchd({ nodeBin, openclawBin }) {
  const launchAgentsDir = path.join(HOME_DIR, 'Library', 'LaunchAgents');
  const plistPath = path.join(launchAgentsDir, `${SERVICE_LABEL}.plist`);
  const dailyPlistPath = path.join(launchAgentsDir, `${DAILY_SERVICE_LABEL}.plist`);
  const uid = execSync('id -u', { encoding: 'utf-8' }).trim();
  const envPath = process.env.PATH || '/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin';

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% 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 · scripts/install.mjs (reported line 123)May include surrounding context.

js
function installMacLaunchd({ nodeBin, openclawBin }) {
  const launchAgentsDir = path.join(HOME_DIR, 'Library', 'LaunchAgents');
  const plistPath = path.join(launchAgentsDir, `${SERVICE_LABEL}.plist`);
  const dailyPlistPath = path.join(launchAgentsDir, `${DAILY_SERVICE_LABEL}.plist`);
  const uid = execSync('id -u', { encoding: 'utf-8' }).trim();
  const envPath = process.env.PATH || '/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin';

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% 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 · scripts/install.mjs (reported line 124)May include surrounding context.

js
function installMacLaunchd({ nodeBin, openclawBin }) {
  const launchAgentsDir = path.join(HOME_DIR, 'Library', 'LaunchAgents');
  const plistPath = path.join(launchAgentsDir, `${SERVICE_LABEL}.plist`);
  const dailyPlistPath = path.join(launchAgentsDir, `${DAILY_SERVICE_LABEL}.plist`);
  const uid = execSync('id -u', { encoding: 'utf-8' }).trim();
  const envPath = process.env.PATH || '/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin';

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% 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 · scripts/install.mjs (reported line 152)May include surrounding context.

js
function installMacLaunchd({ nodeBin, openclawBin }) {
  const launchAgentsDir = path.join(HOME_DIR, 'Library', 'LaunchAgents');
  const plistPath = path.join(launchAgentsDir, `${SERVICE_LABEL}.plist`);
  const dailyPlistPath = path.join(launchAgentsDir, `${DAILY_SERVICE_LABEL}.plist`);
  const uid = execSync('id -u', { encoding: 'utf-8' }).trim();
  const envPath = process.env.PATH || '/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin';

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% 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 · scripts/install.mjs (reported line 156)May include surrounding context.

js
function installMacLaunchd({ nodeBin, openclawBin }) {
  const launchAgentsDir = path.join(HOME_DIR, 'Library', 'LaunchAgents');
  const plistPath = path.join(launchAgentsDir, `${SERVICE_LABEL}.plist`);
  const dailyPlistPath = path.join(launchAgentsDir, `${DAILY_SERVICE_LABEL}.plist`);
  const uid = execSync('id -u', { encoding: 'utf-8' }).trim();
  const envPath = process.env.PATH || '/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin';

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% 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 · scripts/install.mjs (reported line 157)May include surrounding context.

js
function installMacLaunchd({ nodeBin, openclawBin }) {
  const launchAgentsDir = path.join(HOME_DIR, 'Library', 'LaunchAgents');
  const plistPath = path.join(launchAgentsDir, `${SERVICE_LABEL}.plist`);
  const dailyPlistPath = path.join(launchAgentsDir, `${DAILY_SERVICE_LABEL}.plist`);
  const uid = execSync('id -u', { encoding: 'utf-8' }).trim();
  const envPath = process.env.PATH || '/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin';

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% 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 · scripts/install.mjs (reported line 188)May include surrounding context.

js
function installMacLaunchd({ nodeBin, openclawBin }) {
  const launchAgentsDir = path.join(HOME_DIR, 'Library', 'LaunchAgents');
  const plistPath = path.join(launchAgentsDir, `${SERVICE_LABEL}.plist`);
  const dailyPlistPath = path.join(launchAgentsDir, `${DAILY_SERVICE_LABEL}.plist`);
  const uid = execSync('id -u', { encoding: 'utf-8' }).trim();
  const envPath = process.env.PATH || '/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin';

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% 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 · scripts/install.mjs (reported line 195)May include surrounding context.

js
function installMacLaunchd({ nodeBin, openclawBin }) {
  const launchAgentsDir = path.join(HOME_DIR, 'Library', 'LaunchAgents');
  const plistPath = path.join(launchAgentsDir, `${SERVICE_LABEL}.plist`);
  const dailyPlistPath = path.join(launchAgentsDir, `${DAILY_SERVICE_LABEL}.plist`);
  const uid = execSync('id -u', { encoding: 'utf-8' }).trim();
  const envPath = process.env.PATH || '/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin';

Static analysis

Detected: suspicious.dangerous_exec

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/create-reminder.mjs:160

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/daily-brief.mjs:99

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/install.mjs:30

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/reminder-backup.mjs:85