Back to skill

Security audit

macOS Calendar Assistant

Security checks for vulnerabilities and agentic risk

Overview

This calendar skill is mostly purpose-aligned, but it asks for real Calendar access and installs a cron job with unsafe scripting patterns that could lead to unintended calendar changes or user-level command execution from crafted configuration values.

Review carefully before installing. Only run this on a Mac account where you are comfortable granting Calendar access, inspect config.json yourself, avoid untrusted configuration files, and do not run the cron installer or regression test until the cron validation, AppleScript escaping, and live-calendar test isolation issues are fixed.

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 (5)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/install.sh:13
Finding

Cron command injection through insufficient check_time validation

Content
View full analysis
/dev/null || true ) | sed '/calendar_clean_notify.sh/d' > "$TMPCRON" echo "$MIN $HOUR * * * CAL_SKILL_CONFIG=$CONFIG_PATH $SCRIPT_DIR/calendar_clean_notify.sh" >> "$TMPCRON" crontab "$TMPCRON" ``` ### Technical Analysis The installer reads `check_time` from `config.json` and inserts the resulting values directly into a crontab file. Validation only verifies that the derived hour and minute strings are nonempty. It does not: - Require numeric values. - Enforce hour and minute ranges. - Reject newline or carriage-return characters. - Reject shell or cron metacharacters. - Safely encode `CONFIG_PATH` or `SCRIPT_DIR` for execution by cron's shell. A crafted configuration value can therefore inject additional crontab records or alter the shell command installed by the Skill. Since crontab entries survive the installer process, successful exploitation results in persistent execution. The scheduled duplicate-check feature is documented and functionally relevant, but unsafe generation of the crontab entry exceeds what is necessary to implement it securely. ### Attack Path 1. An attacker gains the ability to modify or supply the project's `config.json`, including through an untrusted project archive or configuration automation. 2. The attacker places newline-delimited cron content or shell syntax in `check_time`. 3. The user or Agent runs `scripts/install.sh`. 4. The installer writes the malicious value into the tempor ...[truncated 639 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/calendar_clean_notify.sh:43
Finding

AppleScript injection through the configured notification title

Content
View full analysis
"$ALERT" if [[ "$NOTIFY_ENABLED" == "true" ]]; then /usr/bin/osascript -e "display notification \"$MSG\" with title \"$NOTIFY_TITLE\"" fi fi ``` ### Technical Analysis `notification.title` is controlled by `config.json` and is embedded directly into AppleScript source passed to `osascript -e`. The value is not escaped for AppleScript string-literal syntax. Quotes, backslashes, and line breaks can consequently terminate the intended string and introduce additional AppleScript statements. AppleScript can invoke local commands through functionality such as `do shell script`. This turns a notification customization field into a potential arbitrary-code execution channel. Because the vulnerable script is installed as a daily cron job, malicious configuration can remain dormant until duplicate candidates are found and the notification branch is reached. ### Attack Path 1. An attacker modifies `config.json` and places AppleScript syntax in `notification.title`. 2. The user installs or has already installed the daily duplicate-check cron job. 3. The scheduled script runs and detects one or more duplicate candidates. 4. The script constructs an `osascript -e` program containing the malicious title. 5. The title terminates the intended string literal and inserts attacker-controlled AppleScript. 6. The injected statements execute under the user's account. ### Impact Assessment Su ...[truncated 382 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/set_alarm.py:10
Finding

AppleScript injection through incompletely escaped event UID

Content
View full analysis
0 then set foundEvent to item 1 of matches set foundCal to c exit repeat end if end try end repeat if foundEvent is missing value then error "Event not found: " & eventUid try repeat with a in (every display alarm of foundEvent) delete a end repeat end try make new display alarm at end of display alarms of foundEvent with properties {trigger interval:(-minutesBefore * minutes)} return "OK alarm set: " & minutesBefore & " min before (calendar=" & (name of foundCal) & ")" end tell ''' p = subprocess.run(["osascript"], input=APPLESCRIPT, capture_output=True, text=True) ``` ### Technical Analysis The UID is embedded into executable AppleScript source. The code escapes double quotes but does not first escape existing backslashes. A crafted sequence containing backslashes and quotes can interfere with the intended escaping and terminate the AppleScript string literal. The command-line interface accepts arbitrary UID text. In an Agent workflow, an attacker may be able to persuade the Agent to pass untrusted text as a UID, making this flaw reachable from chat or other untrusted scheduling input. The alarm value is parsed as an integer and is not affected by the same issue. ...[truncated 766 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/regression_test.py:31
Finding

Regression test can modify and delete real user calendar data

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Note
Location
scripts/uninstall.sh:7
Finding

Installer and uninstaller remove unrelated cron entries by broad substring matching

Content
View full analysis
/dev/null || true ) | sed '/calendar_clean_notify.sh/d' > "$TMPCRON" ``` From `scripts/uninstall.sh`: ```sh ( crontab -l 2>/dev/null || true ) | sed '/calendar_clean_notify.sh/d' > "$TMPCRON" crontab "$TMPCRON" ``` ### Technical Analysis Both scripts delete every crontab line containing the substring `calendar_clean_notify.sh`. The removal is not tied to: - The exact project installation path. - A unique job identifier. - A managed begin/end marker. - The exact cron expression originally installed by this project. As a result, an unrelated cron task with a script of the same name, a different copy of this Skill, or even the substring in an argument or comment will be removed. The project’s scheduled task is disclosed and has a legitimate daily-notification purpose. The security concern is the overly broad modification of the user's existing crontab rather than the mere presence of persistence. ### Attack Path 1. The user already has another cron entry containing `calendar_clean_notify.sh`, potentially from a separate installation or unrelated project. 2. The user runs this project's installer or uninstaller. 3. `sed` removes every matching line from the current crontab. 4. The modified crontab replaces the original one. 5. The unrelated scheduled task is silently lost. ### Impact Assessment The vulnerability can disable legitimate scheduled jobs under the current user account. It does not directly grant additional privileges or execute attacker-controlled code, but it can disrupt monitoring, backups, notifications, or other user tasks whose lines happen to match the substring. ]]>
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (34)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The skill claims richer parsing, rescheduling, conflict handling, review sync, and duplicate cleanup than the provided command set substantiates, and the idempotency model appears limited. In a calendar-management context, such gaps are dangerous because agents may rely on nonexistent safeguards and unintentionally create duplicate, conflicting, or incorrectly modified events.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The skill claims richer parsing, rescheduling, conflict handling, review sync, and duplicate cleanup than the provided command set substantiates, and the idempotency model appears limited. In a calendar-management context, such gaps are dangerous because agents may rely on nonexistent safeguards and unintentionally create duplicate, conflicting, or incorrectly modified events.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The skill claims richer parsing, rescheduling, conflict handling, review sync, and duplicate cleanup than the provided command set substantiates, and the idempotency model appears limited. In a calendar-management context, such gaps are dangerous because agents may rely on nonexistent safeguards and unintentionally create duplicate, conflicting, or incorrectly modified events.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

The skill claims richer parsing, rescheduling, conflict handling, review sync, and duplicate cleanup than the provided command set substantiates, and the idempotency model appears limited. In a calendar-management context, such gaps are dangerous because agents may rely on nonexistent safeguards and unintentionally create duplicate, conflicting, or incorrectly modified events.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The skill claims richer parsing, rescheduling, conflict handling, review sync, and duplicate cleanup than the provided command set substantiates, and the idempotency model appears limited. In a calendar-management context, such gaps are dangerous because agents may rely on nonexistent safeguards and unintentionally create duplicate, conflicting, or incorrectly modified events.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The skill claims richer parsing, rescheduling, conflict handling, review sync, and duplicate cleanup than the provided command set substantiates, and the idempotency model appears limited. In a calendar-management context, such gaps are dangerous because agents may rely on nonexistent safeguards and unintentionally create duplicate, conflicting, or incorrectly modified events.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The skill claims richer parsing, rescheduling, conflict handling, review sync, and duplicate cleanup than the provided command set substantiates, and the idempotency model appears limited. In a calendar-management context, such gaps are dangerous because agents may rely on nonexistent safeguards and unintentionally create duplicate, conflicting, or incorrectly modified events.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The skill claims richer parsing, rescheduling, conflict handling, review sync, and duplicate cleanup than the provided command set substantiates, and the idempotency model appears limited. In a calendar-management context, such gaps are dangerous because agents may rely on nonexistent safeguards and unintentionally create duplicate, conflicting, or incorrectly modified events.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The README advertises very broad natural-language examples such as 'add this event', 'extend to 14:00', and 'move to Friday night' for use inside IM conversations. Without a clearly scoped invocation prefix, confirmation gate, or target-event disambiguation, ordinary chat messages or forwarded content could unintentionally trigger calendar writes or edits, especially in a system designed to parse screenshots and conversational context.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The Chinese section repeats similarly broad trigger phrases like '加个日程', '延长到14:00', and '改到周五晚上', again implying that casual IM language can directly cause calendar mutations. Because the skill is intended for high-frequency chat workflows and screenshot-driven extraction, this increases the chance of accidental invocation, social-engineering-induced edits, or unintended scheduling changes from ambiguous messages.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding

The skill declares executable shell, file read, and file write behaviors but does not define any tool scope such as allowed-tools or permissions. This creates an authorization ambiguity where an agent may invoke broader capabilities than users or reviewers expect, especially given the presence of scripts that can modify calendar data and system cron state.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The activation text is broad and likely to match many ordinary calendar-related requests, which can cause the skill to be selected in situations beyond its safest or narrowest intended use. In this skill's context, that matters because the available commands include write, delete, and persistent scheduler actions, increasing the chance of overbroad invocation and unintended system changes.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

This script directly creates calendar events via osascript with no built-in confirmation, dry-run mode, or user-visible warning before modifying local data. In an IM-first assistant context, ambiguous or adversarial chat content could be translated into unintended calendar changes, making silent state-changing behavior materially riskier.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/calendar_clean.py (reported line 22)May include surrounding context.

python
def list_events(start_iso: str, end_iso: str):
    list_events_swift = str(Path(__file__).resolve().parent / "list_events.swift")
    cmd = ["swift", list_events_swift, start_iso, end_iso]
    r = subprocess.run(cmd, capture_output=True, text=True, check=True)
    return json.loads(r.stdout).get("events", [])

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/calendar_clean.py (reported line 73)May include surrounding context.

python
}}
sem.wait()
'''
    p = subprocess.run(["swift", "-"], input=code, capture_output=True, text=True)
    if p.returncode != 0:
        raise SystemExit(p.stderr or p.stdout)
    return p.stdout.strip()

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

NOTIFY_TITLE and later MSG are fixed in Chinese, which imposes a specific language on notifications regardless of user preference. The file does not provide any opt-in, locale selection, or justification for restricting notifications to Chinese.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The message Calendar发现 ${CANDIDATES} 条重复候选,建议清理 is always shown in Chinese when notifications are enabled. This is a natural-language locale policy issue because the script forces one language and does not let the user choose another.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/config_utils.py (reported line 31)May include surrounding context.

python
def _system_timezone() -> str | None:
    """Detect macOS system timezone via systemsetup."""
    try:
        out = subprocess.check_output(
            ["/usr/sbin/systemsetup", "-gettimezone"],
            text=True, timeout=5, stderr=subprocess.DEVNULL,
        )

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The code defaults to "Asia/Shanghai" in both get_timezone_name and get_zoneinfo when no user configuration is present. This imposes a specific locale/timezone choice by default, which is a natural-language policy concern because users are not offered an explicit opt-in or alternative.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/env_check.py (reported line 10)May include surrounding context.

python
def run(cmd):
    return subprocess.run(cmd, capture_output=True, text=True)


def main():

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/list_calendars.py (reported line 14)May include surrounding context.

python
def main():
    script = Path(__file__).resolve().parent / "list_calendars.swift"
    p = subprocess.run(["swift", str(script)], capture_output=True, text=True)
    if p.returncode != 0:
        print(p.stderr or p.stdout, file=sys.stderr)
        sys.exit(1)

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

This script exports all matching calendar events, including sensitive fields such as titles, locations, and especially notes, directly to stdout once calendar permission is granted. In the context of an IM-driven assistant that may relay results to chat systems or other downstream tools, this can expose private calendar contents without data minimization, per-field consent, or a user-facing disclosure.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/regression_test.py (reported line 16)May include surrounding context.

python
def run(cmd, check=True):
    p = subprocess.run(cmd, capture_output=True, text=True)
    if check and p.returncode != 0:
        raise RuntimeError(f"cmd failed: {' '.join(cmd)}\n{p.stdout}\n{p.stderr}")
    return p

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/regression_test.py (reported line 130)May include surrounding context.

python
# If no candidates, remove exact by title/start as a fallback.
    if parse_candidates(cleanup.stdout) == 0:
        swift_code = f'''import EventKit\nimport Foundation\nlet store = EKEventStore()\nlet fmt = ISO8601DateFormatter()\nlet sem = DispatchSemaphore(value: 0)\nstore.requestAccess(to: .event) {{ granted, _ in\n  guard granted else {{ sem.signal(); return }}\n  guard let start = fmt.date(from: "{iso(start)}") else {{ sem.signal(); return }}\n  guard let cal = store.calendars(for: .event).first(where: {{$0.title == "{cal}"}}) else {{ sem.signal(); return }}\n  let pred = store.predicateForEvents(withStart: start, end: start.addingTimeInterval(60), calendars: [cal])\n  let events = store.events(matching: pred).filter {{$0.title == "{title}"}}\n  for e in events {{ try? store.remove(e, span: .thisEvent) }}\n  sem.signal()\n}}\nsem.wait()\n'''
        subprocess.run(["swift", "-"], input=swift_code, capture_output=True, text=True)

    print(json.dumps({
        "ok": True,

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/add_event.py (reported line 118)May include surrounding context.

python
end tell
'''

    p = subprocess.run(["osascript"], input=APPLESCRIPT, capture_output=True, text=True)
    if p.returncode != 0:
        raise SystemExit(p.stderr.strip() or p.stdout.strip() or f"osascript failed: {p.returncode}")
    print(p.stdout.strip())

Static analysis

No suspicious patterns detected.