Back to skill

Security audit

Qq Email Watcher

Security checks for vulnerabilities and agentic risk

Overview

This email watcher matches its general purpose, but it ships with hardcoded mailbox credentials and a fixed QQ notification target that could expose email data without clear user control.

Review this skill carefully before installing or running it. Revoke or remove the bundled IMAP authorization code, replace all hardcoded account and target values with your own protected configuration, confirm the QQ recipient, disable or constrain AI summarization for sensitive email, and fix whitelist matching before using it on a real mailbox.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • 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 (3)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/email_watcher.py:19
Finding
Hard-Coded Mailbox Credential and Account Identifiers<![CDATA[ ## Vulnerability Details **File Location**: `scripts/email_watcher.py`, lines 19-25 **Vulnerability Type**: Hard-coded secrets and sensitive account identifiers **Risk Level**: High ### Vulnerable Code ```python EMAIL = "1257037084@qq.com" AUTH_CODE = "xtepatkcgckvhjhf" IMAP_SERVER = "imap.qq.com" IMAP_PORT = 993 WHITELIST_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "whitelist.json") PROCESSED_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "processed_emails.json") QQ_TARGET = "6E07D3F2F7EC1C7107ECF9D495FF4755" ``` ### Technical Analysis The source code contains a QQ mailbox address, an IMAP authorization code, and a QQ OpenID. Any person or system with access to the project package can extract these values without requiring additional privileges. The exposed IMAP authorization code is especially sensitive because `connect_mail()` uses it directly to authenticate to `imap.qq.com`. If the credential remains valid, possession of the source package may be sufficient to access the associated mailbox through IMAP. This implementation also contradicts the documentation's placeholder-based configuration model and prevents secrets from being independently protected or rotated without changing source code. ### Attack Path 1. An attacker obtains a copy of the project directory, source archive, repository history, log attachment, or deployed script. 2. The attacker reads the `EMAIL` and `AUTH_CODE` constants. 3. The attacker connects to `imap.qq.com` on port 993 using IMAPS. 4. The attacker authenticates with the exposed mailbox address and authorization code. 5. If the authorization code is still active, the attacker accesses mailbox content within the permissions granted by QQ's IMAP service. ### Impact Assessment Successful exploitation may disclose email subjects, senders, bodies, verification codes, account recovery messages, financial information, and other sensitive mailbox content accessible through IMAP. The ...[truncated 309 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Revoke the exposed QQ IMAP authorization code immediately and generate a replacement. 2. Remove all real credentials and account identifiers from the source code and repository history. 3. Read secrets from environment variables or a protected secret-management service: ```python EMAIL = os.environ["QQ_EMAIL"] AUTH_CODE = os.environ["QQ_IMAP_AUTH_CODE"] QQ_TARGET = os.environ["QQ_TARGET"] ``` 4. Fail securely at startup if required variables are missing; do not provide sensitive default values. 5. Restrict secret-file permissions to the service account if a local configuration file must be used. 6. Add local secret files to `.gitignore` and distribute only a placeholder configuration template. 7. Enable automated secret scanning in the development and release pipeline. 8. Review mailbox access records for unauthorized use and rotate any related credentials that may also have been exposed. ]]>

T01 · Skill Instruction Hijacking

Error
Location
scripts/email_watcher.py:97
Finding
Indirect Prompt Injection Through Untrusted Email Content<![CDATA[ ## Vulnerability Details **File Location**: `scripts/email_watcher.py`, lines 97-120; invocation at lines 204-205 **Vulnerability Type**: Untrusted content incorporated into agent instructions **Risk Level**: High ### Vulnerable Code ```python def summarize_with_ai(subject, body): """调用 OpenClaw AI 总结邮件内容(隔离session,不打扰用户)""" prompt = f"""你是邮件摘要助手。收到邮件后,提取关键信息,简洁输出。 邮件主题: {subject} 邮件内容: {body[:800]} 要求: 1. 一句话内说明邮件目的 2. 提取所有关键信息(验证码、金额、日期、链接等)用【】标注 3. 直接输出摘要,不要前缀"摘要:"之类的废话 4. 50字以内 """ try: result = subprocess.run( [ "openclaw", "agent", "--session-id", "email-summarizer", "-m", prompt, "--thinking", "off" ], capture_output=True, text=True, timeout=30, env={**os.environ, "OPENCLAW_SESSION_ID": "email-summarizer"} ) ``` The untrusted values are passed to this function as follows: ```python subject = decode_str(msg.get('Subject', '(无主题)')) body = get_email_body(msg) date = msg.get('Date', '') # AI 智能总结 ai_summary = summarize_with_ai(subject, body) ``` ### Technical Analysis The email subject and body are attacker-influenced inputs. They are interpolated directly into the same natural-language prompt that contains the summarizer's trusted instructions. The prompt does not clearly isolate the email as inert data, explicitly prohibit following instructions found inside it, or require a validated structured-output format. An email can therefore contain text such as instructions to ignore the summary requirements, fabricate a verification code, emit misleading links, or reproduce other context available to the agent. Whether more extensive actions are possible depends on the tools and permissions available to the invoked `openclaw agent`; those capabilities are not defined by the reviewed project. Using a named session does not by itself establish a security boundary. The script does not demonstrate that the se ...[truncated 1364 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Invoke a dedicated, stateless, tool-disabled model context for summarization. 2. Explicitly state that the email is untrusted data and that instructions appearing inside it must never be followed. 3. Separate trusted instructions from untrusted content using structured message roles where supported, rather than combining both into one string. 4. Require constrained structured output, such as validated JSON containing only expected fields: ```json { "purpose": "string", "key_items": ["string"] } ``` 5. Validate the result against a strict schema, enforce length limits, and reject unexpected fields or control content before forwarding it. 6. Sanitize or neutralize clickable links unless they are independently verified. 7. Avoid reusing a persistent session ID for unrelated emails, or explicitly clear session state between requests. 8. Apply least privilege to the summarization agent and ensure it cannot invoke tools, access files, read unrelated conversations, or send messages. 9. Add adversarial tests containing phrases such as “ignore previous instructions” and verify that they are treated only as email content. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/email_watcher.py:189
Finding
Whitelist Bypass Through Substring-Based Sender Validation<![CDATA[ ## Vulnerability Details **File Location**: `scripts/email_watcher.py`, lines 189-198 **Vulnerability Type**: Improper sender identity validation **Risk Level**: High ### Vulnerable Code ```python from_addr = msg.get('From', '') sender = from_addr.lower() if '<' in sender and '>' in sender: sender_email = sender.split('<')[1].split('>')[0].strip() else: sender_email = sender.strip() is_whitelisted = any( w in sender_email or w in sender for w in whitelist ) ``` ### Technical Analysis The whitelist check uses substring containment instead of exact mailbox comparison. A whitelist entry can therefore match an attacker-controlled address that merely contains the trusted address as a substring. The secondary comparison against the entire `From` header also allows a whitelist entry placed in an attacker-controlled display name to satisfy the check. Examples of values that may match a whitelist entry such as `trusted@example.com` include: ```text trusted@example.com.attacker.test "trusted@example.com" <attacker@attacker.test> ``` The code manually parses the `From` header using string splitting rather than the standard email address parser. It also does not verify that the sender passed SPF, DKIM, or DMARC checks. Because the `From` header itself can be spoofed, even an exact header-address comparison would not provide cryptographic sender authentication. ### Attack Path 1. The attacker learns or guesses an address in `whitelist.json`. 2. The attacker sends an email with a crafted `From` header whose display name or mailbox contains that whitelist entry as a substring. 3. The script extracts the header and evaluates `w in sender_email or w in sender`. 4. The substring expression evaluates to true even though the actual sender is not the whitelisted mailbox. 5. The script reads the subject and body and submits them to the OpenClaw summarization agent. 6. The resulting content is forwarded to the configured QQ recipient. 7. The attack ...[truncated 601 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Parse the sender with Python's standard email utilities: ```python from email.utils import parseaddr _, parsed_address = parseaddr(msg.get("From", "")) sender_email = parsed_address.strip().casefold() ``` 2. Normalize and validate each whitelist entry when it is loaded. 3. Require exact equality rather than substring containment: ```python whitelist = {entry.strip().casefold() for entry in load_whitelist()} is_whitelisted = sender_email in whitelist ``` 4. Reject malformed headers, empty parsed addresses, and whitelist entries that are not syntactically valid mailbox addresses. 5. Where reliable authentication metadata is available, require successful SPF/DKIM/DMARC results from headers added by a trusted mail server. Do not trust authentication headers supplied directly by an external sender. 6. Add regression tests for malicious display names, suffix addresses, mixed case, comments, encoded headers, multiple addresses, and malformed angle brackets. 7. Treat sender whitelisting as only one security layer; continue to isolate and constrain all downstream processing of email content. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • 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 (15)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The documented behavior does not fully disclose that the implementation uses sensitive mailbox credentials, accesses a specific QQ mailbox, and sends notifications to a fixed QQ target. This mismatch can conceal credential handling and data-routing behavior from users, which is dangerous because email contents and authentication material are highly sensitive and may be exposed or redirected without informed consent.

Missing User Warnings

High
Confidence
97% confidence
Finding
Email content is transmitted for AI summarization without any explicit warning, confirmation, or consent flow, exposing potentially sensitive personal or business information. In an email-watching skill, mailbox contents are especially sensitive, so silent onward transfer to another processor is more dangerous than in less sensitive domains.

Env Variable Harvesting

High
Category
Data Exfiltration
Content
"--thinking", "off"
            ],
            capture_output=True, text=True, timeout=30,
            env={**os.environ, "OPENCLAW_SESSION_ID": "email-summarizer"}
        )
        if result.returncode == 0 and result.stdout.strip():
            return result.stdout.strip()
Confidence
60% confidence
Finding
Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Missing User Warnings

High
Confidence
95% confidence
Finding
The skill forwards derived email content, including subject, sender, and preview text, to a QQ target without explicit disclosure in the code path or any consent guard. This can leak sensitive information from incoming emails into another messaging channel, expanding the exposure surface beyond the mailbox itself.

Lp3

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding
The skill advertises a capability that inherently uses filesystem access, network access, environment/secrets, and shell execution, but the manifest does not declare any tool scope or permissions. This weakens transparency and policy enforcement, making it easier for a user or platform to underestimate what the skill can access and increasing the blast radius if the skill is misused or modified.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
Continuous mailbox polling and forwarding notifications into QQ exposes sensitive email metadata and potentially message content into an additional communication channel, but the description does not warn users about this propagation. That omission matters because users may assume monitoring is local-only, while in reality subjects, senders, summaries, and codes could appear in QQ messages and logs.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The skill states that it performs AI summarization of incoming emails but does not warn users that email content may be transmitted to an external AI service. Because emails can contain verification codes, financial details, links, and personal data, undisclosed third-party transmission creates a significant privacy and confidentiality risk.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The guide instructs users to place a long-lived IMAP authorization code directly into a Python script, which encourages credential hardcoding in source files. This increases the chance of accidental disclosure through backups, logs, screenshots, version control, or file sharing, and the skill context is particularly sensitive because the credential grants ongoing access to a personal mailbox.

Missing User Warnings

Medium
Confidence
82% confidence
Finding
The instructions tell the user to launch the watcher as a background process, but they do not clearly warn that it will maintain continuous network access to the mailbox and persist state in local files. In an email-monitoring skill, this matters because users may not understand the ongoing collection, retention, and notification behavior, which can create privacy and operational risk if the process keeps running unexpectedly.

Context-Inappropriate Capability

Medium
Confidence
93% confidence
Finding
The script sends email subject and body content to an external AI subprocess for summarization, which creates a confidentiality risk because potentially sensitive mailbox data leaves the core watcher flow. In this skill context, the feature is optional enhancement rather than essential monitoring, so transmitting private email content to another processing component materially increases exposure.

Intent-Code Divergence

Medium
Confidence
95% confidence
Finding
The docstring claims isolation, but the code uses a fixed shared session identifier 'email-summarizer', which can cause cross-run or cross-context data mixing depending on how the downstream tool handles sessions. Misrepresenting isolation increases the chance that sensitive email-derived prompts or outputs are retained or become accessible in an unintended shared context.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
4. 50字以内
"""
    try:
        result = subprocess.run(
            [
                "openclaw", "agent",
                "--session-id", "email-summarizer",
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
"--message", msg
    ]
    try:
        result = subprocess.run(cmd, capture_output=True, text=True, timeout=15)
        if result.returncode == 0:
            return True
        else:
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Natural-Language Policy Violations

Low
Confidence
76% confidence
Finding
All user-facing instructions in this file are presented exclusively in Chinese. Under the policy, forcing a specific language without user opt-in can be a natural-language policy violation unless the locale restriction is explicit and justified.

Natural-Language Policy Violations

Low
Confidence
78% confidence
Finding
The file's user-facing natural-language strings and operational descriptions are in Chinese, including startup and error messages, with no indication that the language is configurable or intentionally limited to a Chinese-only audience. This can violate language/locale policy when a skill forces a specific language without user opt-in.

Static analysis

No suspicious patterns detected.