Back to skill

Security audit

Eventkit Integration

Security checks for vulnerabilities and agentic risk

Overview

The skill is a readable EventKit guide, but it teaches overly broad calendar permissions, invisible identifiers in user notes, and unsafe deletion patterns that could affect private or important reminder data.

Review this skill carefully before installing. Its examples should be changed to request only the EventKit permissions needed, avoid invisible note markers unless users explicitly opt in and can remove them, and add confirmation, backup, or undo safeguards before deleting reminders or local task records.

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

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:112
Finding

Invisible Tracking Identifier Embedded in User Notes

Content
View full analysis

Vulnerability Details

File Location: SKILL.md, lines 112–134
Vulnerability Type: Hidden metadata insertion using zero-width Unicode characters
Risk Level: Medium

Complete Code Snippet

swift
func buildNotes(from task: IdentityMap) -> String {
    let baseNotes = task.notesSnapshot ?? ""

    // Embed zero-width signature for identity tracking
    let signature = "\u{200B}TIMEFLOW:\(task.localUUID)\u{200C}"

    return baseNotes.isEmpty ? signature : baseNotes + "\n" + signature
}

func extractSignature(from notes: String?) -> String? {
    guard let notes = notes else { return nil }

    let pattern = #"\u{200B}TIMEFLOW:([^\u{200B}]+)\u{200C}"#
    guard let regex = try? NSRegularExpression(pattern: pattern),
          let match = regex.firstMatch(in: notes, range: NSRange(notes.startRange, in: notes)) else {
        return nil
    }

    guard let range = Range(match.range(at: 1), in: notes) else { return nil }
    return String(notes[range])
}

Technical Analysis

The recommended implementation deliberately places a local task UUID inside user-authored EventKit notes and conceals it between zero-width Unicode characters. The metadata is therefore not readily visible to users reviewing or editing the note.

Because EventKit notes may be synchronized through calendar providers, included in backups, exported, or shared with other users and applications, the hidden identifier can leave the application's local trust boundary. Other software may also preserve, modify, or unintentionally expose the identifier. Invisible modifications make informed review and removal difficult and can cause interoperability or data-integrity problems.

The extraction expression also treats concealed note content as an authoritative identity signal. If notes can be imported or edited by another participant or synchronized application, an external party could copy or alter the hidden signature and poten ...[truncated 1092 chars]

Remediation
View remediation

Remediation Suggestions

  • Do not encode identity metadata with invisible Unicode characters.
  • Maintain the EventKit-to-local identity mapping in a protected local database or another documented application metadata mechanism.
  • If metadata must be stored in notes, make it visible and documented, obtain informed user consent, and provide controls to inspect and remove it.
  • Treat identifiers extracted from externally synchronized notes as untrusted input.
  • Validate extracted identifiers against the expected UUID format and verify that the referenced local object is eligible for association.
  • Detect duplicate or conflicting signatures instead of silently trusting the first match.
  • Provide a migration routine that identifies and removes previously inserted zero-width signatures without deleting the user's visible note content.

T05 · Unauthorized Access and Privilege Escalation

Error
Location
SKILL.md:28
Finding

Unnecessary Full Access to Calendar Events

Content
View full analysis

Vulnerability Details

File Location: SKILL.md, lines 28–36
Vulnerability Type: Excessive permission request violating least privilege
Risk Level: High

Complete Code Snippet

swift
func initialize() async throws {
    let remindersGranted = try await eventStore.requestFullAccessToReminders()
    let eventsGranted = try await eventStore.requestFullAccessToEvents()

    guard remindersGranted && eventsGranted else {
        throw EventKitError.permissionDenied
    }

    timeFlowCalendar = try await getOrCreateTimeFlowCalendar()
}

Technical Analysis

The initialization routine requests full access to reminders and full access to calendar events. The documented implementation creates a reminder calendar and performs reminder synchronization, fetching, updating, and deletion. No demonstrated initialization requirement justifies access to unrelated calendar events.

Calendar-event access can expose sensitive meeting titles, times, locations, URLs, notes, organizer information, and attendee details. Requiring both grants also makes reminder functionality unavailable when a user correctly denies the unnecessary event permission.

This violates the principle of least privilege by expanding the application's authority beyond the operations shown in the skill. If generated application code is later compromised or misused, the unnecessary grant increases the amount of private data available to that code.

Attack Path

  1. A developer implements the skill's initialization pattern.
  2. A user invokes a feature that only requires reminder access.
  3. Initialization requests full access to both reminders and calendar events.
  4. The user grants both permissions to use the reminder feature.
  5. The application process can then access unrelated event information through EKEventStore.
  6. Any compromised, defective, or subsequently added code running with that authority can read or modify d ...[truncated 547 chars]
Remediation
View remediation

Remediation Suggestions

  • Request full reminder access only for the reminder integration.
  • Remove requestFullAccessToEvents() and the corresponding eventsGranted initialization requirement unless a separately documented feature genuinely needs it.
  • Request event access just in time, immediately before a user invokes an event-specific feature.
  • Explain the concrete purpose of each permission in the user interface and platform usage-description strings.
  • Separate reminder and event authorization states so denial of event access does not disable reminder functionality.
  • Check current authorization status before each protected operation and handle restricted, denied, and not-determined states explicitly.
  • Add tests confirming that the core reminder workflow functions without calendar-event permission.

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:196
Finding

Legitimate Tasks Can Be Deleted by Title-Only Deduplication

Content
View full analysis

Vulnerability Details

File Location: SKILL.md, lines 196–207
Vulnerability Type: Unsafe destructive deduplication
Risk Level: High

Complete Code Snippet

swift
// Group by title to identify duplicates
let grouped = Dictionary(grouping: zombies, by: { $0.titleSnapshot })

for (title, tasks) in grouped where tasks.count > 1 {
    // Keep oldest, delete duplicates
    let sorted = tasks.sorted { $0.createdAt < $1.createdAt }
    for task in sorted.dropFirst() {
        context.delete(task)
    }
}

try? context.save()

Technical Analysis

The cleanup logic assumes that tasks with the same title are duplicates. Task titles are not stable or unique identifiers: users can legitimately create multiple tasks with identical titles for different dates, projects, contexts, or recurrence instances.

Once multiple records satisfy the preceding “zombie” selection conditions, the code retains only the oldest task in each title group and deletes every newer task. It does not compare notes, due dates, project identifiers, creation sources, synchronization history, or cryptographically strong identity values. It also performs no user confirmation, quarantine, soft deletion, or recoverable transaction log.

The call to try? context.save() suppresses save errors, making cleanup failures difficult to detect and potentially obscuring inconsistent state. The one-hour grace period reduces timing-related false positives but does not make title equality a valid identity test.

Attack Path

  1. A user creates two or more legitimate tasks with the same title.
  2. Synchronization fails, is delayed, or otherwise leaves their ekIdentifier values unset for longer than the grace period.
  3. The background zombie-cleanup routine fetches those records.
  4. The records are grouped solely by titleSnapshot.
  5. The oldest record is retained, while every newer same-title record is passed to context.delete.

...[truncated 726 chars]

Remediation
View remediation

Remediation Suggestions

  • Never use title equality alone as proof that two tasks are duplicates.
  • Deduplicate using a stable EventKit identifier, an application-generated UUID, or a collision-resistant fingerprint covering all identity-relevant fields.
  • Treat missing identifiers as an unresolved synchronization state rather than evidence that a record is disposable.
  • Move suspected duplicates into a quarantine or soft-deleted state and retain them for a defined recovery period.
  • Require user confirmation when identity cannot be established unambiguously.
  • Record the identifiers, timestamps, comparison basis, and disposition of every cleanup decision in an audit log.
  • Replace try? context.save() with explicit error handling and reporting.
  • Add tests for legitimate same-title tasks with different due dates, projects, notes, recurrence data, and creation times.
  • Ensure cleanup is idempotent and create a restorable backup or undo mechanism before destructive processing.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
Findings (4)

Ssd 2

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The skill explicitly promotes zero-width character steganography for identity tracking in user-visible notes, which conceals metadata from users and other tools. Hidden identifiers can leak internal IDs, bypass user expectations of transparency, and create a covert metadata channel that survives sync/export into other systems.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The sample localized error strings are written only in Chinese, which imposes a specific language choice in the skill content without offering user selection or explaining a region-specific requirement. This is a natural-language policy issue because the file does not provide any language/locale opt-in or justification.

Content

No source excerpt is available for this finding.

Ssd 2

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

This code gives concrete instructions for embedding and extracting invisible signatures in EventKit notes, intentionally concealing identifiers within normal content. In the EventKit context, notes are user-facing and often synced across devices/services, so hidden data may propagate broadly, complicate privacy review, and enable covert persistence or tracking without informed consent.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

This markdown file includes a batch delete pattern that removes EventKit reminders and commits the deletions, but the surrounding documentation does not warn users that the example performs irreversible data deletion. Under the markdown criteria for missing user warnings, destructive behavior affecting user data should be explicitly disclosed.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.