Back to skill

Security audit

Yahoo Mail IMAP Export

Security checks for vulnerabilities and agentic risk

Overview

This skill is mostly an email export pipeline, but it can move and delete mailbox contents repeatedly and process copied email data with weak safeguards.

Review carefully before installing. Do not run against a real mailbox until you remove the embedded password, provide your own credentials securely, test with --dry-run and --no-delete, and verify message counts and backups. Avoid enabling the documented cron job unless you add an expiration and human approval before deletion. Treat the local ~/email-purge outputs, SQLite database, reports, and Ollama prompts as sensitive copies of your email.

Vulnerability Patterns
  • System PersistenceInstalls backdoors, hooks, services, or scheduled tasks that survive the run
  • 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

Error
Location
move_to_exports.py:8
Finding
Hard-Coded Yahoo Mail App Password## Vulnerability Details **File Location**: `move_to_exports.py`, lines 8-23 **Vulnerability Type**: Hard-coded authentication credential **Risk Level**: High ### Vulnerable Code ```python HOST = "imap.mail.yahoo.com" # EDIT THIS: Your Yahoo Mail email address EMAIL = "your-email@yahoo.com" PASS = "zgvpnfymmwxebpof" EXPORT_FOLDERS = ["export1", "export2", "export3"] BATCH = 1000 # messages per MOVE call def count(m, folder): typ, data = m.status(f'"{folder}"', '(MESSAGES)') if typ == 'OK' and data: match = re.search(r'MESSAGES (\d+)', str(data)) if match: return int(match.group(1)) return 0 m = imaplib.IMAP4_SSL(HOST, 993) m.login(EMAIL, PASS) ``` ### Technical Analysis The script embeds a Yahoo-style app password directly in source code. Anyone who can read the distributed package, repository, backup, build artifact, or source history can recover the credential without accessing a dedicated secret store. The password is supplied to Yahoo through an encrypted IMAP connection, so this is not evidence of covert exfiltration or plaintext network transmission. The vulnerability is the credential's exposure at rest in source code. Although the included account address is a placeholder, the credential could still be abused if an attacker identifies its associated account through repository history, logs, other configuration, or credential reuse. ### Attack Path 1. An attacker obtains a copy of the project or its source history. 2. The attacker reads `move_to_exports.py` and extracts the embedded password. 3. The attacker identifies the corresponding Yahoo address from related configuration, logs, documentation, or prior revisions. 4. The attacker attempts authentication against Yahoo Mail using the exposed app password. 5. If the credential remains active, the attacker can exercise the mailbox permissions granted to that app password. ### Impact Assessment Successful ...[truncated 432 chars]
Remediation
## Remediation Suggestions 1. Revoke and rotate the exposed Yahoo app password immediately. 2. Remove the credential from the current source and all repository history. 3. Load credentials from a protected environment variable or operating-system secret store: ```python EMAIL = os.environ["YAHOO_EMAIL"] password = os.environ["YAHOO_PASSWORD"] ``` 4. Fail closed when either variable is absent; do not provide literal credential fallbacks. 5. Restrict secret-file permissions if environment injection is performed through a file. 6. Add automated secret scanning to pre-commit and CI workflows. 7. Review Yahoo account access history for unauthorized sessions.

T09 · Insecure Skill Coding Practices

Error
Location
purge_cycle.py:235
Finding
Partial Local Files Can Be Mistaken for Verified Backups Before Remote Deletion## Vulnerability Details **File Location**: `purge_cycle.py`, lines 235-279 **Vulnerability Type**: Unsafe verification and non-atomic file handling before destructive deletion **Risk Level**: High ### Vulnerable Code ```python for index, uid in enumerate(uids, start=1): uid_int = int(uid) eml_path = folder_dir / f"{uid_int}.eml" if eml_path.exists() and eml_path.stat().st_size > 0: skipped_existing += 1 downloaded_uids.append(uid) continue try: typ, data = y.ensure().uid("fetch", uid, "(RFC822)") if typ != "OK" or not data or not data[0] or not isinstance(data[0], tuple): raise PurgeError(f"bad fetch response: {typ} {data[:1] if data else data}") raw = data[0][1] if not raw: raise PurgeError("empty RFC822 payload") eml_path.write_bytes(raw) meta_f.write(json.dumps(extract_metadata(raw, folder, uid_int), ensure_ascii=False) + "\n") downloaded_uids.append(uid) ``` The trusted UID list is subsequently used for remote deletion: ```python deleted = 0 if delete_after and downloaded_uids: log(f" Deleting {len(downloaded_uids)} successfully downloaded messages from {folder}") y.select(folder, readonly=False) for batch in chunks(downloaded_uids, DELETE_CHUNK): uid_set = b",".join(batch).decode("ascii") try: typ, _ = y.ensure().uid("store", uid_set, "+FLAGS", "\\Deleted") if typ != "OK": raise PurgeError(f"UID STORE returned {typ}") y.ensure().expunge() deleted += len(batch) log(f" Deleted {deleted}/{len(downloaded_uids)}") time.sleep(1) ``` ### Technical Analysis A pre-existing `.eml` file is considered verified solely because it exists and has a size greater than zero. No expected byte count, message identifier, cryptographic digest, parse val ...[truncated 2052 chars]
Remediation
## Remediation Suggestions 1. Write each message to a temporary file in the destination directory. 2. Flush user-space buffers and call `os.fsync()` before committing the file. 3. Validate the downloaded message before deletion, including: - Successful RFC822 parsing - Expected message identifier or UID association - Nontrivial structural checks - Expected server-reported size, where available - A cryptographic digest recorded in durable state 4. Atomically rename the verified temporary file to the final `.eml` path with `os.replace()`. 5. Store a separate durable verification record only after the rename and metadata commit succeed. 6. Do not treat file existence or nonzero size alone as proof of a complete download. 7. Make `--no-delete` the default and require explicit confirmation for remote deletion. 8. Before deletion, revalidate every UID against its committed local verification record. 9. Back up or quarantine malformed existing files rather than trusting or silently overwriting them. 10. Add interruption, disk-full, truncated-file, and restart tests to verify failure safety.

T06 · System Persistence

Error
Location
YAHOO_EXPORT_GUIDE.md:137
Finding
Documentation Establishes Recurring Execution of a Destructive Mailbox Workflow## Vulnerability Details **File Location**: `YAHOO_EXPORT_GUIDE.md`, lines 137-149 **Vulnerability Type**: Persistent scheduled execution **Risk Level**: High ### Vulnerable Instructions ```bash openclaw cron create \ --name "email-purge-cycle" \ --every 15m \ --message "Run: cd ~/email-purge && python3 scripts/purge_cycle.py" \ --session isolated \ --model "moonshot/kimi-k2.5" \ --no-deliver ``` ### Technical Analysis The guide instructs users to create an OpenClaw cron task that survives the current execution session and runs every 15 minutes. The invoked `purge_cycle.py` workflow moves messages and, unless `--no-delete` is supplied, deletes downloaded messages from Yahoo export folders and expunges them. The persistence is user-visible and requires the user to follow the documentation; static analysis found no code that covertly installs the task. Nevertheless, the instruction creates a recurring cross-session execution mechanism for a destructive operation without a bounded run count, mandatory dry run, deletion opt-in, or explicit human approval for each cycle. The scheduled command also references `scripts/purge_cycle.py`, while the audited package places `purge_cycle.py` at the project root. Users may adapt this path, but the inconsistency increases the chance of invoking an unintended or stale script from the target directory. ### Attack Path 1. A user follows the guide and creates the recurring OpenClaw cron task. 2. The task remains active beyond the current session and runs every 15 minutes. 3. Each invocation executes the mailbox purge workflow without `--dry-run` or `--no-delete`. 4. The configured Yahoo mailbox is repeatedly mutated: messages are moved, downloaded, marked deleted, and expunged. 5. An archive corruption, stale file, incorrect folder configuration, credential compromise, or script replacement can be repeatedly acted upon without contemporaneous user review. 6. Unless ...[truncated 584 chars]
Remediation
## Remediation Suggestions 1. Prefer manual execution for destructive mailbox operations. 2. If scheduling is retained, require an explicit and prominently documented opt-in. 3. Schedule the workflow with `--no-delete` by default. 4. Separate download and deletion into independent phases, with human approval between them. 5. Add a maximum number of cycles or a defined expiration time to the scheduled task. 6. Automatically disable and remove the task when the inbox reaches the terminal completion state. 7. Require integrity and count reconciliation before each deletion phase. 8. Document commands for listing, disabling, and removing the scheduled task. 9. Use an absolute, verified script path and reject execution if ownership or file integrity differs from the approved version. 10. Run under a dedicated least-privileged local account with restricted archive-directory access. 11. Emit prominent deletion notifications rather than relying solely on unattended logs or `--no-deliver`.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (28)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
Undisclosed LLM-based triage and scoring of email content materially changes the risk profile of the skill, especially when the description promises only archive export. Sensitive communications may be processed, scored, and persisted without clear authorization, creating privacy, regulatory, and misuse concerns.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
Undisclosed LLM-based triage and scoring of email content materially changes the risk profile of the skill, especially when the description promises only archive export. Sensitive communications may be processed, scored, and persisted without clear authorization, creating privacy, regulatory, and misuse concerns.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
Undisclosed LLM-based triage and scoring of email content materially changes the risk profile of the skill, especially when the description promises only archive export. Sensitive communications may be processed, scored, and persisted without clear authorization, creating privacy, regulatory, and misuse concerns.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
Undisclosed LLM-based triage and scoring of email content materially changes the risk profile of the skill, especially when the description promises only archive export. Sensitive communications may be processed, scored, and persisted without clear authorization, creating privacy, regulatory, and misuse concerns.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
Undisclosed LLM-based triage and scoring of email content materially changes the risk profile of the skill, especially when the description promises only archive export. Sensitive communications may be processed, scored, and persisted without clear authorization, creating privacy, regulatory, and misuse concerns.

Missing User Warnings

High
Confidence
99% confidence
Finding
A hardcoded mailbox credential in source code is a real secret exposure: anyone with access to the file, logs, backups, or repository can reuse it to authenticate to the Yahoo Mail account. In the context of an email-export skill, this is especially dangerous because mailbox access enables reading, moving, and deleting sensitive messages, and the static password may be copied into downstream systems unintentionally.

Missing User Warnings

High
Confidence
92% confidence
Finding
The script deletes messages from the server after considering them successfully downloaded, but it does not require an explicit destructive-action acknowledgement at runtime. In an agent skill context, this is more dangerous because a user or orchestrator may trigger the skill expecting export behavior without realizing it performs permanent mailbox deletion, creating significant risk of unintended data loss.

Description-Behavior Mismatch

High
Confidence
98% confidence
Finding
The code does not implement the advertised Yahoo Mail IMAP export workflow. Instead, it accesses a local `~/email-purge` SQLite database and generates a report about email classification, importance, and deletion-oriented actions, which is a strong capability mismatch for the declared skill. In an agent ecosystem, this kind of undeclared local-data triage behavior is dangerous because it can cause unauthorized access to sensitive mailbox-derived data and influence retention/deletion decisions outside the user’s expected scope.

Description-Behavior Mismatch

High
Confidence
98% confidence
Finding
This script performs AI-based email triage, schema mutation, and escalation output generation even though the skill is described as a Yahoo Mail archive export tool. That mismatch materially increases supply-chain risk because users expecting export-only behavior may unknowingly run code that inspects message content, classifies it, and creates additional derivative datasets.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The README materially expands the skill’s scope beyond simple Yahoo Mail export into AI-powered email triage, embeddings, and local LLM processing. That mismatch can cause an agent or user to invoke unreviewed functionality on sensitive mailbox contents, increasing the risk of unexpected data processing, privacy exposure, and unsafe destructive actions outside the declared skill intent.

Lp3

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding
The skill advertises operational capabilities involving network access, file reads/writes, and likely credential use, but it declares no explicit tool scope or permissions. That omission weakens reviewability and containment, making it easier for a skill to exercise broader-than-expected access during execution.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
The manifest lists embedding, filtering, triage, and summary-generation components unrelated to the stated Yahoo export purpose. Unrelated capability bundling increases attack surface and makes it harder to reason about what sensitive data may be processed or exfiltrated through auxiliary pipelines.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The guide recommends a destructive workflow that clears export folders after download, but it does not present a prominent up-front warning that this process mutates the source mailbox and can permanently delete mail if verification is incomplete or a script fails. In a mail-export skill, users may reasonably treat the process as archival/safe backup behavior, so under-communicated deletion steps materially increase the risk of accidental data loss.

External Transmission

Medium
Category
Data Exfiltration
Content
def get_embedding(text):
    """Get embedding from Ollama."""
    resp = requests.post(OLLAMA_URL, json={
        "model": EMBED_MODEL,
        "prompt": text,
    })
Confidence
90% confidence
Finding
This code performs an external transmission of sensitive email content to a separate service using requests.post(). In the context of a mail-export/indexing skill, the transmitted prompt can contain private communications and metadata, so a misconfigured endpoint or intercepted local service could leak large volumes of user email data.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The script sends email-derived content, including subject, sender, body preview, and attachment names, to an embedding service over HTTP without any explicit user consent flow, warning, or transport protection. Even though the endpoint is localhost by default, this still exports sensitive mail content to another process and can expose data if Ollama is remote, proxied, containerized, or bound insecurely.

Intent-Code Divergence

Medium
Confidence
88% confidence
Finding
The docstring says the script moves 'seq 1:N (the first N messages)', implying a caller-chosen or variable count. In reality, the loop at L47 hard-codes a 10,000-message operation and L49 always uses '1:BATCH', so the documented intent materially differs from the implemented behavior.

Missing User Warnings

Medium
Confidence
87% confidence
Finding
The script selects INBOX and repeatedly issues IMAP MOVE commands for the first 10,000 messages, which changes the user's mailbox state in bulk. Although there are progress prints, there is no explicit warning, confirmation, or explanatory notice that this is a destructive reorganization of mailbox contents.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The manifest describes a mail archive export skill focused on IMAP folder rotation, resumable downloads, and safe delete-after-verify handling. In contrast, this module reads an existing local emails.jsonl file, classifies messages by content heuristics, and writes multiple filtered output files, which is a different processing function than archive export.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The script writes multiple files containing email metadata, labels, attachment names, and classification results to a fixed local directory without any privacy safeguards, retention controls, or prominent warning about sensitive data handling. In the context of a mail-archive skill, this increases the chance of exposing personal or regulated information through insecure local storage, backups, or accidental sharing.

Missing User Warnings

Medium
Confidence
86% confidence
Finding
This code saves full raw emails to .eml files and appends extracted metadata to local JSONL files, which affects user data on disk. Although the module docstring describes the behavior, the executable path itself provides no explicit user warning or confirmation before persisting potentially sensitive mailbox contents locally.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
The script sends email-derived content, including subject, sender/recipient fields, dates, attachment names, and body previews, to a model service over HTTP. Even if the endpoint is localhost, this is still a data-transfer boundary and can expose sensitive email content to another process or service without explicit user consent or purpose alignment.

External Transmission

Medium
Category
Data Exfiltration
Content
def query_ollama(prompt):
    """Query Ollama for email triage."""
    try:
        resp = requests.post(OLLAMA_URL, json={
            "model": MODEL,
            "prompt": prompt,
            "system": SYSTEM_PROMPT,
Confidence
90% confidence
Finding
The `requests.post` call transmits prompt data containing email content to an external service boundary, here a local Ollama HTTP API. Although not remote by default, it is still a separate service that may log, retain, or expose sensitive material, and this behavior is not justified by the advertised export-only function.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
Sensitive email content is transmitted to a local HTTP endpoint without any visible user-facing notice about disclosure, model retention, logging, or persistence. In a mail-export context, users are unlikely to expect secondary processing of message contents, so the lack of transparency increases privacy and compliance risk.

Context-Inappropriate Capability

Medium
Confidence
92% confidence
Finding
The script alters the email database schema and stores triage metadata such as importance, category, and review flags, which are unrelated to a pure archive export workflow. This expands the data footprint and modifies user datasets in ways that may be unexpected, making accidental misuse or downstream privacy leakage more likely.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The script appends full triage entries to persistent JSONL files, including copied email metadata and body previews, without warning users that sensitive content will be duplicated on disk. This creates additional long-lived copies of private communications, increasing exposure in case of local compromise, backups, or accidental sharing.

Static analysis

No suspicious patterns detected.