Back to skill

Security audit

Scheduler Pro

Security checks for vulnerabilities and agentic risk

Overview

This is a local scheduler/reminder helper with implementation quality issues, but no evidence of hidden execution, exfiltration, or unsafe privileged behavior.

Install only if you want a simple local task registry, not a full cron executor. Treat schedules as approximate, confirm mutations before deleting or toggling tasks, and avoid storing sensitive reminder text or operational details unless local plaintext JSON storage is acceptable.

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
SKILL.md:73
Finding

Unvalidated Cron Expressions Cause Scheduler Failure and Incorrect Execution Times

Content
View full analysis
str: parts = cron_expr.strip().split() if len(parts) != 5: return datetime.now().isoformat() minute, hour, day, month, weekday = parts now = datetime.now() if minute == "*" and hour == "*": next_time = now + timedelta(minutes=1) elif minute != "*" and hour == "*": m = int(minute) next_time = now.replace(minute=m, second=0, microsecond=0) if next_time <= now: next_time += timedelta(hours=1) elif minute != "*" and hour != "*": h, m = int(hour), int(minute) next_time = now.replace(hour=h, minute=m, second=0, microsecond=0) if next_time <= now: next_time += timedelta(days=1) else: next_time = now + timedelta(hours=1) return next_time.isoformat() ``` ### Technical Analysis The scheduler accepts a cron expression and splits it into five fields, but it does not validate the syntax or permitted numeric ranges before converting fields with `int()` and passing them to `datetime.replace()`. The documentation presents expressions such as `*/5 * * * *` as supported. For that expression, the `minute != "*"` and `hour == "*"` branch attempts to evaluate `int("*/5")`, raising an uncaught `ValueError`. Numeric expressions outside valid time ranges, such as `99 99 * * *`, can similarly raise exceptions during integer conversion or `datetime.replace()`. The implementation also ignores the `day`, `month`, and `weekday` fields after parsing them. Consequently, weekly and monthly expressions documented by the skill are treated as daily schedules. Invalid expressions containing other unsupported syntax may therefore either terminate task creation or produce a materially incorrect next-run timestam ...[truncated 1120 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:101
Finding

Filtered Task Listings Expose Incorrect Mutable Task Identifiers

Content
View full analysis
bool: if 0 <= task_id < len(self.tasks): self.tasks.pop(task_id) self._save() return True return False def toggle(self, task_id: int) -> Optional[bool]: if 0 <= task_id < len(self.tasks): self.tasks[task_id].enabled = not self.tasks[task_id].enabled self._save() return self.tasks[task_id].enabled return None def list_tasks(self, enabled_only: bool = False) -> List[Dict]: tasks = [t for t in self.tasks if not enabled_only or t.enabled] return [ { "id": i, "name": t.name, "schedule": t.schedule, "enabled": t.enabled, "next_run": t.next_run, "last_run": t.last_run or "never", "run_count": t.run_count, "tags": t.tags, } for i, t in enumerate(tasks) ] ``` ### Technical Analysis Task identifiers are not stable identifiers. They are generated dynamically from a task's position in a list. When `list_tasks(enabled_only=True)` is used, the code first creates a filtered list and then enumerates that filtered list. The returned `id` values therefore represent positions in the filtered list. In contrast, `remove_task()` and `toggle()` interpret the supplied identifier as a position in the original, unfiltered `self.tasks` list. If disabled tasks occur before enabled tasks, the displayed identifier no longer identifies the same object when passed to a mutation method. Deletions also shift all subsequent list positions, making previously returned identifiers stale. ### Attack Path 1. The scheduler contains multiple tasks, including at least one disabled task before an enabled task. 2. A caller invokes ...[truncated 1105 chars]
Remediation
View remediation
Vulnerability Patterns
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (4)

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The description states 'cron语法支持' and the documentation presents standard 5-field cron examples such as weekly schedules and workday ranges. However, _calc_next_run only branches on whether minute and hour are '*' and otherwise ignores the day, month, and weekday fields entirely, so examples like 0 9 * * 1 and 0 10 * * 1-5 will be treated as daily schedules rather than weekly/workday schedules.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The skill persists task names, descriptions, schedules, and tags to a local JSON file without clearly warning users in the markdown that their data will be written to disk. Users may include sensitive reminders or operational details, so undisclosed persistence increases privacy and data-exposure risk, especially on shared systems or environments with lax file permissions.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The activation phrases are very generic everyday terms such as '调度', '定时任务', and '提醒', which can cause accidental invocation in unrelated conversations. In an agent environment, overly broad triggers increase the chance that the skill activates on benign user text and performs unintended persistent changes such as creating or modifying scheduled reminders.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

Example tasks are described as 'Run daily database backup', 'Ping all services', 'Generate and email weekly report', and 'Remind team for daily standup', and the usage example says to 'execute and mark' due tasks. In reality, the implementation has no mechanism to run commands, send reminders, perform checks, or dispatch email; it only persists task records, computes next timestamps approximately, lists due tasks, and updates bookkeeping via mark_run.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.