Back to skill

Security audit

Smart Reminder

Security checks for vulnerabilities and agentic risk

Overview

This reminder skill is mostly coherent, but it stores cross-channel routing identifiers and creates scheduled jobs without enough cleanup, consent, or scoping safeguards.

Install only if you are comfortable with a reminder skill keeping local reminder history and delivery identifiers. For safer use, avoid cross-channel reminders unless the target account is confirmed, periodically review/remove cron jobs, and do not store sensitive reminder text until cancellation and retention behavior is fixed.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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
Findings (2)

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
scripts/manage_tasks.py:27
Finding

Session Enumeration and Plaintext Storage of Routing Metadata

Content
View full analysis

Vulnerability Details

File Location: SKILL.md:96-98, SKILL.md:252-254, scripts/manage_tasks.py:27-44, scripts/manage_tasks.py:80
Vulnerability Type: Excessive session discovery and insecure storage of session routing identifiers
Risk Level: Medium

Vulnerable Code and Instructions

SKILL.md:96-98:

markdown
- **`delivery`** — **Required field**
  - `channel` — Target channel ID
  - `sessionKey` — Target session key obtained from `openclaw sessions`

SKILL.md:252-254:

markdown
2. **Delivery must be stored.**
3. **How to obtain sessionKey:** use `openclaw sessions --agent main --active 60 --json` to view recent sessions.

scripts/manage_tasks.py:27-44:

python
STATE_DIR = os.path.join(os.path.dirname(__file__), "..", "..", "memory")
STATE_FILE = os.path.join(STATE_DIR, "smart-reminder-tasks.json")

def _ensure_state():
    os.makedirs(STATE_DIR, exist_ok=True)
    if not os.path.exists(STATE_FILE):
        with open(STATE_FILE, "w", encoding="utf-8") as f:
            json.dump({"config": {}, "tasks": {}}, f, ensure_ascii=False, indent=2)
    with open(STATE_FILE, "r", encoding="utf-8") as f:
        state = json.load(f)
    if "config" not in state:
        state["config"] = {}
    if "tasks" not in state:
        state["tasks"] = {}
    return state

def _save_state(state):
    with open(STATE_FILE, "w", encoding="utf-8") as f:
        json.dump(state, f, ensure_ascii=False, indent=2)

scripts/manage_tasks.py:80:

python
task["delivery"] = {"channel": channel, "sessionKey": session_key}

Technical Analysis

The Skill directs the agent to enumerate recently active sessions for the entire main agent to identify a delivery destination. This query can disclose metadata for sessions unrelated to the user who requested the reminder. The design therefore exceeds the least-privilege requirement of accessing only the inv ...[truncated 1989 chars]

Remediation
View remediation

Remediation Suggestions

  1. Obtain the channel and destination identifier directly from trusted invocation context instead of enumerating all recent main-agent sessions.
  2. Restrict session discovery to the current user, account, and invoking session when enumeration is unavoidable.
  3. Do not retain a full session key unless persistent cross-channel delivery strictly requires it.
  4. Store an opaque, narrowly scoped delivery reference instead of a general session identifier where supported.
  5. Segregate state by authenticated user or tenant and verify ownership before reading or using delivery metadata.
  6. Create the state directory and file with owner-only permissions, such as directory mode 0700 and file mode 0600, while accounting for platform differences.
  7. Use atomic writes with explicit permissions to prevent replacement or accidental permission widening.
  8. Redact session keys from command output, logs, diagnostics, and task-listing interfaces.
  9. Define a retention period and remove routing metadata when its associated reminder is canceled, deleted, or expires.
  10. Validate the destination against the authenticated requester's permitted channels before every delivery.

T06 · System Persistence

Warning
Location
SKILL.md:221
Finding

Reminder Cancellation Does Not Remove the Persistent Cron Job

Content
View full analysis

Vulnerability Details

File Location: SKILL.md:106-147, SKILL.md:221, SKILL.md:232; related deletion behavior in scripts/manage_tasks.py:168-179
Vulnerability Type: Incomplete cleanup of persistent scheduled tasks
Risk Level: Medium

Vulnerable Instructions and Code

SKILL.md:106-147 requires creation of a persistent cron job:

markdown
### Step 3: Create cron task

After storing the task configuration, a cron task must also be created.

Use the `cron(add)` tool:
- One-time reminder: `schedule: {kind: "at", at: "ISO-8601 with offset"}`
- Repeating reminder: `schedule: {kind: "cron", expr: "...", tz: "Asia/Shanghai"}`
- All reminders: `payload: {kind: "systemEvent", text: "SMART_REMINDER task_id"}`

SKILL.md:221 defines cancellation only as a local state update:

markdown
- **Cancel task** → `enabled = false`

SKILL.md:232 repeats the same behavior:

markdown
- "Cancel this reminder" → `enabled = false`

scripts/manage_tasks.py:168-179 deletes only the JSON record:

python
def cmd_delete(args):
    if not args:
        print("Usage: delete <task_id>")
        sys.exit(1)
    state = _ensure_state()
    if args[0] in state["tasks"]:
        del state["tasks"][args[0]]
        _save_state(state)
        print(f"Deleted {args[0]}")
    else:
        print(f"Task '{args[0]}' not found")

Technical Analysis

Reminder creation installs a cron job that survives the original Skill invocation. Cancellation, however, only sets the local task's enabled field to false; deletion only removes the task from JSON state. Neither operation records and removes the associated cron job through cron(remove).

The documented trigger workflow does not explicitly require an enabled check before generating or delivering a reminder. Consequently, a repeating cron job can continue generating system events after cancellation. The cross-channel ...[truncated 1823 chars]

Remediation
View remediation

Remediation Suggestions

  1. Capture and persist the scheduler-generated cron job ID when creating every reminder.
  2. On cancellation or deletion, call cron(remove) with the stored job ID before confirming success.
  3. Treat cancellation as successful only after both scheduler cleanup and state update complete.
  4. Add a mandatory trigger-time check that rejects missing, disabled, expired, or unauthorized tasks before producing any message.
  5. For isolated cross-channel agentTurn jobs, remove or disable the scheduler entry because those jobs cannot safely rely only on local task-state checks.
  6. Make cleanup idempotent so repeated cancellation requests safely handle already-removed jobs.
  7. If cron removal fails, preserve enough state to retry and clearly report that cancellation is incomplete.
  8. Add reconciliation logic that periodically compares stored tasks with scheduler jobs and removes orphaned entries.
  9. Remove obsolete delivery metadata when a task is canceled or deleted.
  10. Add tests covering creation, cancellation, deletion, one-time execution, repeating execution, and scheduler-cleanup failures.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (9)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
87% confidence
Finding

The skill instructs reading and writing persistent state files but does not declare any explicit tool scope or allowed-tools boundary. That weakens least-privilege controls and can let an agent with broader ambient capabilities modify files beyond what the skill actually needs, increasing the chance of unintended state tampering or data exposure.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The skill persistently stores nickname, reminder history, completion status, and scheduling metadata without any user-facing retention, deletion, or privacy disclosure. Because this data can reveal routines, habits, and personal preferences over time, silent long-term storage raises privacy and profiling risks beyond what a user may reasonably expect from a reminder feature.

Content

No source excerpt is available for this finding.

Ssd 3

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The skill stores delivery routing data including channel and sessionKey alongside user task records for reuse in future reminders. Persisting reusable identifiers for future messaging increases the blast radius of any state-file leak or misuse, enabling unauthorized or misrouted contact with the user and exposing internal conversation-routing details.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The skill describes cross-channel delivery to WeChat using stored recipient identifiers and account metadata, but does not require a clear user-facing consent or privacy notice before routing reminders to another channel. This can surprise users, expose reminder content in a different platform context, and create privacy issues if sensitive tasks are delivered to the wrong account or shared device.

Content

No source excerpt is available for this finding.

Ssd 3

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The cross-channel delivery flow explicitly tells the agent to remember recipient identity details and later use them to message the user on WeChat from another context. This is more dangerous than ordinary reminder state because it enables out-of-band contact using stored identity mappings; if those mappings are stale, wrong, or abused, the agent could send sensitive reminders to an unintended recipient or channel.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The file gives conflicting instructions about cron creation: earlier it says to use the cron tool and not the CLI, while the rules section later says reminders must call openclaw cron add. Contradictory operational guidance can cause the agent to choose the wrong execution path, bypass intended platform safeguards, or fail open in ways that create jobs in the wrong scope or with the wrong visibility.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The file's instructions and all example utterances are written in Chinese, and it directs the agent on how to phrase responses in that language and register. There is no indication that the user can opt into another language or that the locale restriction is intentionally limited to a Chinese-speaking context.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The delete command removes task data from persistent state and immediately writes the change to disk, but there is no confirmation prompt or prior user-facing warning that the action is destructive. Although the module docstring lists the command, it does not warn that deletion is irreversible for the stored task record.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
80% confidence
Finding

The helper functions automatically create the memory directory and write the JSON state file, including overwriting the full file on each save. While this is part of state management, the code does not include an inline warning or disclosure that running commands will modify on-disk state under the memory path.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.