Back to skill

Security audit

Doro Email To Calendar

Security checks for vulnerabilities and agentic risk

Overview

The skill matches its email-to-calendar purpose, but it asks for broad email/calendar authority, installs recurring behavior, mutates mailbox state automatically, and contains a command-injection bug.

Install only if you are comfortable granting access to read Gmail content, create/update/delete calendar events, mark or archive emails, and store email-derived metadata locally. Review or disable direct inbox scanning, auto-disposition of emails, heartbeat integration, auto-create patterns, and deadline email notifications before use. The command-injection path in event tracking should be fixed before running validation workflows on untrusted or shared state.

Vulnerability Patterns
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • 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
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (4)

T02 · Agent Memory Poisoning

Error
Location
BOOT.md:38
Finding
Persistent Modification of Shared Agent Heartbeat Instructions## Vulnerability Details **File Location**: `BOOT.md:38-74` **Vulnerability Type**: Persistent agent memory poisoning **Risk Level**: High ### Vulnerable Code ```markdown ### 3. Check Heartbeat Integration Read `~/.openclaw/workspace/HEARTBEAT.md` and ensure it contains: - "Email Check" or "Email Scanning" section with calendar notification exclusion - "Pending Calendar Invites" section ## Heartbeat Sections to Add If the following sections are not present in HEARTBEAT.md, add them: ```markdown ## Email Scanning (email-to-calendar skill) During email check cycle: 1. **IGNORE calendar notification emails** - DO NOT process emails from `calendar-notification@google.com` - These include: "Accepted:", "Declined:", "Tentative:", "Updated invitation:", "Cancelled:" - These are just notifications about responses to existing invites, NOT new events - Run `~/.openclaw/workspace/skills/email-to-calendar/scripts/process_calendar_replies.sh` to auto-archive them 2. Check for other unread emails with event indicators (dates, times, meeting keywords) 3. If events found, extract and present to user for selection 4. **ALWAYS use wrapper scripts** - NEVER call `gog` directly 5. Created events are tracked; user can undo within 24 hours 6. Log all scanning activity silently for audit trail ``` ```markdown ## Pending Calendar Invites (email-to-calendar skill) If pending invites exist (check during email check cycle): 1. Run: `~/.openclaw/workspace/skills/email-to-calendar/scripts/list_pending.sh --summary` 2. If pending invites found with status "pending" and future dates: - List them to the user: "You have X pending calendar invite(s) that need your decision:" - Present each with: title, date, source email - Ask: "Reply with numbers to create, 'all', or 'dismiss' to clear them" 3. Based on user response: - Selected numbers: Create events using create_event.sh, update status to "created" ...[truncated 2281 chars]
Remediation
## Remediation Suggestions 1. Remove all instructions that automatically modify `HEARTBEAT.md` or other shared agent memory. 2. Present heartbeat integration as an optional configuration snippet instead of an automatic bootstrap step. 3. Require explicit, informed user approval before installing any recurring mailbox workflow. 4. Store scheduling configuration in a Skill-owned file rather than shared agent instructions. 5. Clearly disclose the frequency, mailbox queries, mutation behavior, retained data, and removal procedure. 6. Provide a command that completely unregisters the recurring behavior and removes only the Skill-owned configuration. 7. Default recurring processing to disabled and read-only operation.

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
BOOT.md:91
Finding
Bootstrap Self-Check Silently Performs Mutating Mailbox Operations## Vulnerability Details **File Location**: `BOOT.md:91-92` **Vulnerability Type**: Unauthorized mailbox mutation during bootstrap **Risk Level**: Medium ### Vulnerable Code ```bash # Process any unread calendar notification emails ~/.openclaw/workspace/skills/email-to-calendar/scripts/process_calendar_replies.sh 2>/dev/null || true ``` The same file describes the invoked operation as follows: ```markdown **IGNORE calendar notification emails** from `calendar-notification@google.com`: - Subject patterns: "Accepted:", "Declined:", "Tentative:", "Updated invitation:", "Cancelled:" - These are responses to existing invites, NOT new events to create - Run `process_calendar_replies.sh` to auto-archive them ``` ### Technical Analysis A bootstrap self-check should normally verify prerequisites without changing user data. Here, the bootstrap instructions invoke `process_calendar_replies.sh` without its documented `--dry-run` option. The operation searches unread calendar-notification messages and dispositions them, which can mark messages as read or archive them according to configuration. Standard error is redirected to `/dev/null`, and `|| true` suppresses failure status. This makes the mutating action less visible and prevents the calling workflow from reliably reporting partial failures or classification errors. Although processing calendar replies is related to the Skill's stated purpose, performing it automatically during bootstrap does not establish task-specific user consent for each mailbox mutation. ### Attack Path 1. The Skill enters its first-activation or self-check workflow. 2. The agent invokes `process_calendar_replies.sh` without `--dry-run`. 3. The script searches the authenticated mailbox for messages matching notification criteria. 4. Matching messages are passed to the email-disposition workflow. 5. The messages may be marked read, archived, or both. 6. Errors are hidden by standard-error ...[truncated 645 chars]
Remediation
## Remediation Suggestions 1. Make bootstrap and capability checks strictly read-only. 2. Invoke `process_calendar_replies.sh --dry-run` by default. 3. Display the message IDs, senders, subjects, and proposed label changes before performing mutations. 4. Require explicit user confirmation before marking messages read or archiving them. 5. Do not suppress errors with `2>/dev/null || true`; return structured failures to the user. 6. Use exact sender validation and conservative subject matching to reduce false positives. 7. Record each confirmed mutation in a visible audit log and provide a recovery procedure where the provider supports one.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/utils/event_tracking.py:170
Finding
Shell Command Injection in Orphaned Event Cleanup## Vulnerability Details **File Location**: `scripts/utils/event_tracking.py:170-172` **Vulnerability Type**: OS command injection through `shell=True` **Risk Level**: High ### Vulnerable Code ```python subprocess.run( f'{script_dir}/delete_tracked_event.sh --event-id "{event_id}"', shell=True, capture_output=True ) ``` The wrapper reaches this operation when validation is requested: ```bash python3 "$UTILS_DIR/event_tracking.py" lookup \ --type "$SEARCH_TYPE" \ --value "$SEARCH_VALUE" \ --validate "$VALIDATE" \ --script-dir "$SCRIPT_DIR" ``` ### Technical Analysis The cleanup operation constructs a command string by interpolating `script_dir` and `event_id`, then passes the result to a command shell. Double quotes around `event_id` do not provide safe shell argument encoding: an event ID containing a double quote followed by shell syntax can terminate the quoted argument and inject an additional command. An unsafe `script_dir` can likewise alter the command itself. `event_id` is read from persistent `events.json` records. The tracking API does not enforce an allowlist for event-ID characters before storing or using this value. Consequently, a poisoned tracking record can become an execution payload when `lookup_event.sh --validate` identifies that record as orphaned. Most other provider operations correctly pass argument arrays to `subprocess.run`, making this isolated `shell=True` path unnecessary. ### Attack Path 1. An attacker or compromised local process places a malicious `event_id` in the event-tracking data. A representative structure would contain shell metacharacters that terminate the quoted `--event-id` value. 2. The user or agent runs `lookup_event.sh --validate`, or another workflow invokes equivalent validation. 3. The Skill searches the calendar and fails to find the poisoned event, classifying it as orphaned. 4. The orphan cleanup branch interpolates the mali ...[truncated 1049 chars]
Remediation
## Remediation Suggestions Remove shell interpretation and pass each argument separately: ```python cleanup_script = os.path.realpath( os.path.join(script_dir, "delete_tracked_event.sh") ) subprocess.run( [cleanup_script, "--event-id", event_id], capture_output=True, text=True, check=False, ) ``` Additional hardening should include: 1. Resolve and validate `cleanup_script` against the canonical expected Skill directory. 2. Reject symbolic-link or traversal-based paths that escape that directory. 3. Validate event IDs against the provider's documented identifier format and maximum length. 4. Avoid invoking another process entirely where possible; call `delete_tracked_event(event_id)` directly. 5. Treat tracking files as untrusted input and validate their schema when loading. 6. Add regression tests containing quotes, semicolons, command substitutions, newlines, and whitespace in both relevant values.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/utils/json_store.py:41
Finding
Sensitive JSON State Is Written Without Restrictive Permissions or Atomic Replacement## Vulnerability Details **File Location**: `scripts/utils/json_store.py:41-56` **Vulnerability Type**: Insecure sensitive-data storage and non-atomic file writes **Risk Level**: Medium ### Vulnerable Code ```python def save_json(filepath: str, data: Any, indent: int = 2) -> None: """ Save data as JSON to a file. Creates parent directories if they don't exist. Args: filepath: Path to the JSON file data: Data to serialize as JSON indent: Indentation level (default: 2) """ filepath = os.path.expanduser(filepath) ensure_dir(filepath) with open(filepath, 'w') as f: json.dump(data, f, indent=indent) ``` The corresponding directory creation also does not specify a restrictive mode: ```python def ensure_dir(filepath: str) -> None: """Ensure the directory for a file path exists.""" Path(filepath).parent.mkdir(parents=True, exist_ok=True) ``` ### Technical Analysis The shared JSON writer persists event IDs, calendar IDs, source email IDs, email subjects, event summaries, pending invitations, activity logs, and change history. New directories and files inherit permissions from the process umask rather than explicitly enforcing private access. On a system with a permissive umask or pre-existing broadly accessible directories, other local users may be able to read this metadata. Existing files also retain their previous permissions because the writer does not correct them. The function's module documentation claims to provide atomic writes, but it opens the destination with mode `w`. This truncates the existing file before serialization finishes. A process interruption, disk-full condition, or concurrent writer can therefore leave an empty, partial, or inconsistent JSON file. Callers frequently treat invalid JSON as default empty state, potentially concealing corruption and weakening duplicate detection, activity history, or undo track ...[truncated 1204 chars]
Remediation
## Remediation Suggestions 1. Create Skill state directories with mode `0700`. 2. Create state files with mode `0600` using `os.open` and explicit permission flags. 3. Correct permissions on existing directories and files after verifying ownership. 4. Write JSON to a temporary file in the same directory, flush it, call `os.fsync`, and atomically replace the destination with `os.replace`. 5. Apply the restrictive mode to the temporary file before writing sensitive content. 6. Use file locking or another serialization mechanism to prevent concurrent lost updates. 7. Do not silently interpret malformed state as empty state; preserve the corrupt file, report the error, and fail safely. 8. Consider minimizing retained email metadata and define a clear retention or deletion policy.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (47)

Missing User Warnings

High
Confidence
97% confidence
Finding
The manifest explicitly advertises 'silent activity logging' while the skill handles email content and calendar operations, both of which are privacy-sensitive domains. Logging user activity without a clear warning, consent mechanism, retention policy, or scope limitation can expose sensitive email metadata or contents and creates substantial privacy and compliance risk.

Chaining Abuse

High
Category
Tool Misuse
Content
| Thursday | TH |
| Friday | FR |
| Saturday | SA |
| Sunday | SU |

## Key Flags
Confidence
75% confidence
Finding
Tool calls are chained to bypass individual safety checks or escalate capabilities beyond what any single tool call would allow.

Context-Inappropriate Capability

High
Confidence
98% confidence
Finding
Validation logic in an event-tracking helper should not execute an external script from a caller-supplied directory, yet this code does exactly that when an orphaned event is detected. Because the path is externally influenced and invoked through the shell, the feature expands the attack surface from simple data lookup into arbitrary code execution.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
else:
                            print(f"Orphaned event detected: {event_id} - removing from tracking", file=sys.stderr)
                            if script_dir:
                                subprocess.run(
                                    f'{script_dir}/delete_tracked_event.sh --event-id "{event_id}"',
                                    shell=True, capture_output=True
                                )
Confidence
99% confidence
Finding
This is a classic tool-parameter abuse issue: untrusted parameters are passed into a shell command that invokes another tool/script. In the skill context, where arguments may originate from upstream agent actions or user-controlled content, an attacker could manipulate `script_dir` or `event_id` to run unintended commands or scripts on the host.

Session Persistence

Medium
Category
Rogue Agent
Content
Verify the agent can:
- Read emails (list unread, get message body)
- Create calendar events
- Update/delete calendar events

If any capability is missing, inform the user:
Confidence
60% 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.

Context-Inappropriate Capability

Medium
Confidence
92% confidence
Finding
The bootstrap directs the skill to modify a global HEARTBEAT.md file to install persistent behavior outside the immediate execution of the email-to-calendar task. Even if intended for convenience, this creates cross-session persistence and expands the skill's influence into broader agent behavior without explicit per-user approval.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The bootstrap tells the agent to create or modify HEARTBEAT.md if sections are missing, but provides no requirement to notify the user or obtain consent before changing persistent global configuration. This is dangerous because it silently alters future agent behavior and can normalize hidden persistence mechanisms.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The self-check commands create directories and initialize pending_invites.json automatically, causing filesystem writes without notifying the user. Undisclosed writes are risky because they establish persistent state, may store sensitive invite metadata, and can surprise users who expect read-only analysis during setup.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The configuration indicates emails may be marked read or archived automatically, but the skill description shown here does not clearly warn users that processing can modify mailbox state. This can lead to unexpected loss of visibility or workflow disruption if important messages are silently dispositioned.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
### Fixed
- Stale forward handling: Old emails forwarded today are now properly processed.
- Orphaned events: Events deleted in Google Calendar are now automatically removed from tracking.

## [1.5.0] - 2026-02-02
Confidence
80% confidence
Finding
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
### Fixed
- Stale forward handling: Old emails forwarded today are now properly processed.
- Orphaned events: Events deleted in Google Calendar are now automatically removed from tracking.

## [1.5.0] - 2026-02-02
Confidence
80% confidence
Finding
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
## [1.4.0] - 2026-02-02

### Added
- **Selective Selection**: Users can now cherry-pick events by number (e.g., '1, 2, 3'), 'all', or 'none' instead of binary yes/no confirmation
- **Self-Healing Tracking**: When updating an event that was deleted externally (404/410), automatically removes stale tracking entry and creates a new event

### Removed
Confidence
75% confidence
Finding
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The setup flow encourages one-click acceptance of defaults that include inbox-modifying behavior such as marking messages read, archiving them, and auto-processing calendar replies. Because this is presented as a recommended default without a prominent warning or explicit opt-in for each destructive action, users may unintentionally grant the skill authority to alter or discard email state they expected to review manually.

Session Persistence

Medium
Category
Rogue Agent
Content
5. Whole-day events: Timed (9 AM - 5 PM)
6. Multi-day events: Daily recurring
7. Ignore patterns: (none)
8. Auto-create patterns: (none)
9. Email handling: Mark as read and archive (recommended)
   Also auto-process calendar replies? (Y/n)
Confidence
60% 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.

Session Persistence

Medium
Category
Rogue Agent
Content
If you prefer to skip the interactive setup:

```bash
mkdir -p ~/.config/email-to-calendar
cat > ~/.config/email-to-calendar/config.json << 'EOF'
{
  "provider": "gog",
Confidence
60% 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.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
The prerequisites state that the skill can create, update, and delete calendar events, but the guide does not clearly warn users that granting this access enables destructive modifications to existing calendar data. In a calendar automation context, silent or poorly disclosed delete/update capability can lead to loss of legitimate events or unnoticed tampering if the skill misbehaves.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The description advertises direct inbox monitoring and silent activity logging but does not prominently warn that the skill may scan broad unread inbox content and persist extracted information. Users may enable the skill without understanding the scope of access, creating a consent and privacy transparency gap around mailbox processing.

Intent-Code Divergence

Medium
Confidence
96% confidence
Finding
The skill states 'ALWAYS ASK BEFORE CREATING' but also supports 'AUTO-CREATE' behavior based on configured patterns, creating an authorization bypass in practice. This can cause calendar modifications without fresh user consent in the current conversation, which is especially risky because the skill processes potentially broad inbox content and inferred events.

Ssd 3

Medium
Confidence
93% confidence
Finding
The skill instructs the agent to read MEMORY.md and maintain silent activity logging, while the feature list and file locations indicate persistent storage of extracted email-derived data and user preferences across sessions. Persisting mailbox-derived content and behavioral preferences increases privacy risk, retention of sensitive personal/work information, and the blast radius if local memory files are exposed or misused by other skills.

Ssd 3

Medium
Confidence
95% confidence
Finding
The workflow explicitly records pending invites and extracted event details into persistent memory stores keyed by email identifiers and subjects. That creates a durable repository of communication-derived metadata that can reveal schedules, contacts, and private activities beyond the immediate task, increasing privacy exposure and secondary-use risk.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The skill automatically marks or archives emails after event creation without a prominent warning in the main description. This can alter mailbox state unexpectedly, causing users to miss messages, lose workflow cues based on unread status, or impair forensic review of what triggered calendar changes.

Context-Inappropriate Capability

Medium
Confidence
89% confidence
Finding
The skill can send outbound email notifications, which expands its capability beyond extracting events and writing calendar entries. Any compromise, prompt injection through email content, or misclassification of events with deadlines could trigger unsolicited emails, leak sensitive event details, or be abused for spam/phishing-like behavior from the user's account.

Vague Triggers

Medium
Confidence
96% confidence
Finding
The trigger list includes broad phrases like 'check emails' and 'scan inbox' that can match common user requests and cause this skill to activate outside a narrowly scoped email-to-calendar intent. Because the skill requests read_email and calendar write capabilities, overbroad invocation increases the chance of unintended email access and event creation or modification.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The document explicitly instructs the script to delete an existing event or modify it as cancelled when cancellation language is detected, but it does not require any user confirmation, provenance checks, or safeguards against false positives. In an email-extraction workflow, forwarded content, quoted text, or ambiguous language could trigger unintended destructive calendar changes, causing loss of legitimate events or calendar integrity issues.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The documentation includes a destructive calendar delete command with no warning, confirmation guidance, or mention of irreversibility. In an automation or agent setting, that omission increases the chance of accidental event deletion and makes it easier for downstream logic to invoke destructive actions unsafely.

Static analysis

No suspicious patterns detected.