Back to skill

Security audit

IMAP IDLE Watcher

Security checks for vulnerabilities and agentic risk

Overview

The skill openly implements an email-triggered automation service, but it installs persistent system-level command execution with sensitive email credentials in ways that need review before use.

Install only after reviewing the service file and hardening it. Prefer a dedicated unprivileged service user, avoid shell=True-style handler commands, do not pass app passwords on the command line, keep credentials in a safer secret mechanism, and assume any configured handler may receive sensitive environment variables unless the daemon is changed.

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)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/setup_service.sh:207
Finding
Persistent Arbitrary Shell Command Execution with Root Privileges## Vulnerability Details **File Location**: `scripts/setup_service.sh:207-231` and `scripts/imap_idle_daemon.py:179-186` **Vulnerability Type**: Root-level arbitrary command execution through a persistent system service **Risk Level**: High ### Vulnerable Code `scripts/setup_service.sh:207-231`: ```bash # Write systemd unit cat > "$unit_file" <<EOF [Unit] Description=IMAP IDLE Watcher ($ACCOUNT) After=network-online.target Wants=network-online.target [Service] Type=simple EnvironmentFile=$env_file ExecStart=$(command -v python3) $DAEMON_SCRIPT Restart=always RestartSec=10 StandardOutput=journal StandardError=journal [Install] WantedBy=multi-user.target EOF echo " ✅ Unit file: $unit_file" # Enable and start systemctl daemon-reload systemctl enable "$SERVICE_NAME" systemctl start "$SERVICE_NAME" ``` `scripts/imap_idle_daemon.py:179-186`: ```python result = subprocess.run( ON_NEW_MAIL_CMD, shell=True, capture_output=True, text=True, timeout=300, env=env, ) ``` ### Technical Analysis The installer creates a system-wide unit under `/etc/systemd/system` and enables it at startup. The unit does not specify `User=` or `Group=`, so systemd runs the daemon as root by default. The daemon obtains `ON_NEW_MAIL_CMD` from its environment file and passes the complete string to `subprocess.run` with `shell=True`. Consequently, shell operators, command substitutions, redirections, pipelines, and multiple commands are accepted. This is intentional command functionality, but it becomes a privilege-escalation boundary violation because the handler inherits the service's root privileges. The persistence mechanism itself is consistent with the Skill's declared real-time monitoring functionality. However, running the watcher and user-defined handler as root is not necessary for connecting to an IMAP server or processing email headers. The enabled service also ca ...[truncated 1535 chars]
Remediation
## Remediation Suggestions 1. Create a dedicated system account with no interactive login and run the unit using explicit `User=` and `Group=` directives. 2. Avoid accepting a shell command string. Represent the handler as a validated executable path and argument list, then invoke it with `shell=False`. 3. Reject shell metacharacters if compatibility requires accepting a textual command. 4. Install the daemon into a root-owned directory that is not writable by the service account or ordinary users. 5. Add systemd sandboxing controls, including: - `NoNewPrivileges=true` - `PrivateTmp=true` - `ProtectSystem=strict` - `ProtectHome=true` - `ProtectKernelTunables=true` - `ProtectKernelModules=true` - `ProtectControlGroups=true` - `RestrictSUIDSGID=true` - `LockPersonality=true` - `CapabilityBoundingSet=` - `ReadWritePaths=` limited to explicitly required locations 6. Use a per-user systemd service when system-wide installation is unnecessary. 7. Validate that the configured handler is an absolute path to an approved, non-writable executable. 8. Document that enabling the service creates persistence and require explicit confirmation before enabling it.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/setup_service.sh:80
Finding
Python Code Injection Through Unescaped Connection-Test Parameters## Vulnerability Details **File Location**: `scripts/setup_service.sh:80-99` **Vulnerability Type**: Source-code injection through shell interpolation into `python3 -c` **Risk Level**: High ### Vulnerable Code ```bash # Simple Python test as fallback python3 -c " import imaplib, ssl, sys try: ctx = ssl.create_default_context() m = imaplib.IMAP4_SSL('$HOST', $PORT, ssl_context=ctx) m.login('$ACCOUNT', '$PASSWORD') m.select('$FOLDER') typ, caps = m.capability() cap_str = caps[0].decode() if caps and caps[0] else '' if 'IDLE' not in cap_str: print('⚠️ Server does not advertise IDLE support. Watcher may not work.') else: print('✅ Connection OK — IDLE supported') m.logout() except imaplib.IMAP4.error as e: print(f'❌ Auth failed: {e}') print(' Check your credentials. For Gmail, use an App Password (not your regular password).') sys.exit(1) except Exception as e: print(f'❌ Connection failed: {e}') sys.exit(1) " 2>&1 ``` ### Technical Analysis The values of `HOST`, `PORT`, `ACCOUNT`, `PASSWORD`, and `FOLDER` are inserted directly into Python source code. These values can originate from command-line arguments or interactive input and are not escaped as Python literals. A value containing a quote, closing delimiter, newline, or additional Python expression can terminate the intended string and insert arbitrary statements into the program passed to `python3 -c`. `PORT` is especially exposed because it is inserted without quotation marks or integer validation. This is source-code injection rather than ordinary shell injection: shell expansion constructs the Python program, and the Python interpreter then executes the attacker-controlled program. Installation generally requires elevated privileges because the script writes to `/etc` and invokes systemd, so the injected code may execute as root. ### Attack Path 1. An attacker ...[truncated 1154 chars]
Remediation
## Remediation Suggestions 1. Never construct Python source code using interpolated configuration values. 2. Pass connection parameters through environment variables or positional arguments and read them using `os.environ` or `sys.argv`. 3. Validate `PORT` before invoking Python, ensuring it contains only digits and falls within the valid TCP port range. 4. Validate host and folder values according to the formats accepted by the IMAP client. 5. Use a fixed Python helper script rather than a dynamically generated `python3 -c` program. 6. Preserve argument boundaries by passing every value as a separate argument. 7. Add regression tests containing quotes, backslashes, newlines, command substitutions, and Python delimiters in each accepted parameter. 8. Drop elevated privileges before performing network connection tests where possible.

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:30
Finding
IMAP App Password Exposed Through Command-Line Arguments## Vulnerability Details **File Location**: `SKILL.md:30-39` **Vulnerability Type**: Sensitive credential exposure through command-line usage **Risk Level**: Medium ### Vulnerable Code ```bash bash scripts/setup_service.sh \ --account "user@gmail.com" \ --password "xxxx xxxx xxxx xxxx" \ --command "python3 /path/to/handler.py" \ --service-name my-watcher ``` ```bash bash scripts/setup_service.sh --test --account "user@gmail.com" --password "xxxx" ``` The same command-line pattern is also implemented by `scripts/setup_service.sh:283`: ```bash --password) PASSWORD="$2"; shift 2 ;; ``` It is repeated in `SKILL.md:98-101` and `references/troubleshooting.md:35`. ### Technical Analysis The documented non-interactive and test workflows place the IMAP app password directly in the process argument list. Depending on the operating system configuration, command-line arguments can be visible to other local users through process inspection while the command is running. The command may also be retained in interactive shell history, terminal recordings, automation logs, audit records, support transcripts, or CI/CD job output. Quoting the password does not prevent these disclosures. An IMAP app password is a reusable authentication secret. Although it may be narrower than the user's primary password, disclosure can still grant mailbox access allowed by the provider. ### Attack Path 1. A user follows the documented setup or troubleshooting command and supplies the real app password through `--password`. 2. The command is recorded in shell history or automation logs, or its arguments are observed through local process inspection. 3. A local attacker, log reader, backup operator, or compromised automation component retrieves the password. 4. The attacker authenticates to the configured mail provider using the exposed account name and app password. 5. Access continues until the app password is revoked ...[truncated 559 chars]
Remediation
## Remediation Suggestions 1. Remove app passwords from all documented command-line examples. 2. Prefer hidden interactive input with `read -s` or read the password from standard input. 3. For unattended installation, use a root-readable credential file, systemd credentials, or a dedicated secret-management system. 4. If a file is used, validate its ownership and permissions before reading it and avoid copying the secret into logs. 5. Deprecate `--password`; if retained for compatibility, display a clear warning about process listings and shell history. 6. Ensure diagnostic output never prints the password or complete environment. 7. Advise users who previously followed the documented command to remove relevant history entries and rotate the app password if logs or history may have been exposed.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
Findings (26)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The declared purpose frames the skill as a simple IMAP watcher, but the documented behavior extends to filtering on message metadata and storing email credentials locally for a persistent service. That mismatch is dangerous because users may authorize the skill under a narrower trust model than its real behavior, leading to credential exposure or unexpected persistence on the host.

Env Variable Harvesting

High
Category
Data Exfiltration
Content
_last_run = now

    # Try to get metadata for the command
    env = os.environ.copy()
    meta = None
    try:
        meta = fetch_latest_metadata(imap)
Confidence
99% confidence
Finding
Copying the full process environment into a child command is a classic secret propagation issue. Because this daemon stores mail credentials in environment variables and then forwards the entire environment to a configurable command, any downstream process can access those secrets even if it only needs mail metadata. In an automation skill that is explicitly designed to execute external commands, this creates a strong credential-exposure pathway.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
log.info(f"🔄 Running: {ON_NEW_MAIL_CMD}")
    try:
        result = subprocess.run(
            ON_NEW_MAIL_CMD,
            shell=True,
            capture_output=True,
Confidence
98% confidence
Finding
This is a tool-parameter abuse risk because the code hands a fully user-controlled command string to the shell. The feature is intended to run a user-defined command, but without constraints it effectively grants arbitrary code execution to anyone who can set or alter configuration, and email arrival provides an automatic trigger path. Within a persistent systemd service, such execution may occur repeatedly and with stable privileges.

Credential Access

High
Category
Privilege Escalation
Content
# ── Install service ───────────────────────────────────────────────────────

install_service() {
    local env_file="/etc/${SERVICE_NAME}.env"
    local unit_file="/etc/systemd/system/${SERVICE_NAME}.service"

    echo ""
Confidence
91% confidence
Finding
Defining an environment file under /etc for IMAP credentials indicates intentional plaintext credential storage for service operation. In the context of an email watcher that needs long-lived authentication, this is functionally convenient but increases the blast radius of host compromise and operational secret leakage.

Credential Access

High
Category
Privilege Escalation
Content
uninstall_service() {
    local svc="${SERVICE_NAME:-imap-idle-watcher}"
    local env_file="/etc/${svc}.env"
    local unit_file="/etc/systemd/system/${svc}.service"

    echo "🗑️  Uninstalling service: $svc"
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Chaining Abuse

High
Category
Tool Misuse
Content
echo "   Disabled."
    fi

    [ -f "$unit_file" ] && rm -f "$unit_file" && echo "   Removed: $unit_file"
    [ -f "$env_file" ] && rm -f "$env_file" && echo "   Removed: $env_file"

    systemctl daemon-reload
Confidence
75% confidence
Finding
Tool calls are chained to bypass individual safety checks or escalate capabilities beyond what any single tool call would allow.

Chaining Abuse

High
Category
Tool Misuse
Content
echo "   Disabled."
    fi

    [ -f "$unit_file" ] && rm -f "$unit_file" && echo "   Removed: $unit_file"
    [ -f "$env_file" ] && rm -f "$env_file" && echo "   Removed: $env_file"

    systemctl daemon-reload
Confidence
75% confidence
Finding
Tool calls are chained to bypass individual safety checks or escalate capabilities beyond what any single tool call would allow.

Lp3

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding
The skill documents capabilities that clearly involve shell execution, network access, and environment-variable handling, but it does not declare any tool scope or permission boundaries. That omission makes it easier for an agent or operator to invoke the skill without understanding that it can install services, execute commands, and handle credentials, increasing the chance of unintended privileged actions.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The non-interactive examples place email app passwords directly on the command line, which can leak through shell history, process listings, logs, or transcripts. Because these credentials grant mailbox access, exposing them can directly compromise the user's email account and any downstream systems that trust it.

Description-Behavior Mismatch

Medium
Confidence
93% confidence
Finding
The documentation says the skill is not for reading or parsing email bodies, but then instructs the agent to write arbitrary handlers and even gives a 'summarize new emails' use case. That broadens the skill beyond passive metadata-triggered automation into general email-processing behavior, which can lead agents to generate code that accesses more content or performs more powerful actions than users expect.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The workflow instructs the agent to write a handler to disk and install a persistent service, but it does not clearly warn that this modifies the local system and may survive reboots. In an agent setting, persistence without prominent consent is risky because it can create long-lived automation, ongoing network access, and repeated command execution beyond the user's immediate intent.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The document instructs users to generate and copy a Gmail app password but provides no warning that this is a long-lived credential equivalent to account access for IMAP. In the context of an automation skill that relies on persistent email access, omission of secure-handling guidance increases the chance users will paste the secret into logs, shell history, service files, or other insecure storage.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The document instructs users to generate and copy an Outlook app password but provides no guidance on treating that password as a sensitive secret. In the context of an email-watcher skill that relies on long-lived IMAP credentials, this omission increases the chance that users will paste the app password into logs, shell history, config files with weak permissions, or other insecure locations, potentially exposing full mailbox access.

Description-Behavior Mismatch

Medium
Confidence
92% confidence
Finding
The manifest limits the skill to real-time monitoring and explicitly says it is not for reading/parsing email bodies, which implies a narrow watcher role. The code goes beyond pure notification by fetching unseen-message headers (From, Subject, Date), decoding them, filtering on them, and exporting them to the triggered command, which constitutes reading/parsing message content metadata rather than just detecting arrival.

Context-Inappropriate Capability

Medium
Confidence
96% confidence
Finding
The child command receives os.environ.copy(), which includes IMAP_ACCOUNT, IMAP_PASSWORD, and any other secrets present in the daemon environment. Any triggered script, binary, or subprocess can read, log, exfiltrate, or further propagate those credentials, expanding trust far beyond what an inbox watcher needs. In this context, where arbitrary user-defined commands are launched automatically, broad secret inheritance is particularly dangerous.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
log.info(f"🔄 Running: {ON_NEW_MAIL_CMD}")
    try:
        result = subprocess.run(
            ON_NEW_MAIL_CMD,
            shell=True,
            capture_output=True,
Confidence
98% confidence
Finding
The daemon executes a command taken from configuration using subprocess.run(..., shell=True). Because shell parsing is enabled, any metacharacters in ON_NEW_MAIL_CMD are interpreted by the shell, turning a configurable automation hook into arbitrary command execution with the daemon's privileges. In this skill's context, command execution is a core feature, but the unsafe shell invocation substantially increases risk and can be abused through misconfiguration or untrusted configuration sources.

Tainted flow: 'ON_NEW_MAIL_CMD' from os.environ.get (line 42, credential/environment) → subprocess.run (code execution)

Medium
Category
Data Flow
Content
log.info(f"🔄 Running: {ON_NEW_MAIL_CMD}")
    try:
        result = subprocess.run(
            ON_NEW_MAIL_CMD,
            shell=True,
            capture_output=True,
Confidence
97% confidence
Finding
ON_NEW_MAIL_CMD originates from an environment variable and flows directly into subprocess.run for execution. That means whoever can influence the service environment, deployment manifest, or startup wrapper can cause arbitrary code execution; using shell=True further amplifies the danger by enabling shell injection semantics. For an email-triggered automation daemon, this is especially sensitive because the command may run continuously as a long-lived service.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
The script explicitly asks the user for an arbitrary command and persists it for later execution by a long-running systemd service whenever new mail arrives. In this skill’s context, that creates a built-in remote trigger path from email delivery to shell command execution, which is dangerous because a misconfigured or overly broad mailbox watch can turn inbound email into code execution automation.

Description-Behavior Mismatch

Medium
Confidence
91% confidence
Finding
The installer writes IMAP credentials into an environment file under /etc and installs a system-wide persistent systemd unit. While this is consistent with the tool’s purpose, it creates privileged persistence and stores sensitive secrets on disk in a location that may be exposed to administrators, backups, or accidental disclosure through support workflows.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The command-line setup path writes the supplied app password directly into a root-owned env file without prominently warning the user that the secret will be persisted on disk. Even with mode 600, plaintext secret persistence increases exposure via backups, filesystem access by privileged users, incident response collection, or accidental disclosure.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
IDLE_TIMEOUT=$IDLE_TIMEOUT
DEBOUNCE_SECONDS=$DEBOUNCE
EOF
    chmod 600 "$env_file"
    echo "   ✅ Env file: $env_file (mode 600)"

    # Write systemd unit
Confidence
80% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Session Persistence

Medium
Category
Rogue Agent
Content
# Enable and start
    systemctl daemon-reload
    systemctl enable "$SERVICE_NAME"
    systemctl start "$SERVICE_NAME"

    echo "   ✅ Service started!"
Confidence
88% confidence
Finding
Enabling the service creates boot-time persistence for a process that continuously monitors an inbox and may execute a configured action on new mail. Persistence is expected for a watcher, but it also means any unsafe command configuration or compromised daemon behavior will automatically survive reboots.

Session Persistence

Medium
Category
Rogue Agent
Content
echo "   Stopped."
    fi

    if systemctl is-enabled --quiet "$svc" 2>/dev/null; then
        systemctl disable "$svc"
        echo "   Disabled."
    fi
Confidence
80% 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
89% confidence
Finding
In non-interactive mode, providing --account and --password automatically triggers a live authentication test against the IMAP server without an explicit warning or opt-in at that point. This is risky because operators may not expect credential use or outbound network access during setup, especially in automation pipelines or logs-sensitive environments.

Description-Behavior Mismatch

Low
Confidence
83% confidence
Finding
The manifest frames the skill as only monitoring for new mail and explicitly says it is not for reading/parsing email bodies. This documentation shows the skill extracts and passes message metadata such as From, Subject, Date, and UID to user-defined commands, which goes beyond a pure arrival notification and constitutes limited email reading behavior.

Static analysis

No suspicious patterns detected.