Back to skill

Security audit

Imap Mail

Security checks for vulnerabilities and agentic risk

Overview

This email skill is mostly coherent, but it exposes powerful mailbox actions through an unauthenticated local API and documents a root-running system service.

Install only if you are comfortable granting a local service broad control over the configured mailbox. Run it under a dedicated unprivileged account, add authentication or a protected socket before enabling the API, keep the webhook unset unless it points to a trusted endpoint, avoid saving attachments from untrusted mail until filenames are sanitized, and pin dependencies for reproducible installs.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (4)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/mail-api.py:488
Finding

Unauthenticated Local API Grants Full Mailbox Control

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/check_inbox.py:75
Finding

Untrusted Attachment Filenames Permit Path Traversal and Arbitrary File Overwrite

Content
View full analysis
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Error
Location
references/systemd.md:19
Finding

Documented System Service Runs the Mail API as Root by Default

Content
View full analysis
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
SKILL.md:1
Finding

Runtime Dependencies Are Installed Without Version or Integrity Pinning

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (84)

Tainted flow: 'req' from os.getenv (line 333, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
96% confidence
Finding

The webhook URL is taken from environment configuration and used to POST full message data, including message bodies and metadata, to whatever endpoint is configured. In this skill context, that creates a direct exfiltration path for sensitive email contents and can also be abused as SSRF if an attacker can influence environment configuration or deployment settings.

Content

Scanner excerpt · scripts/mail-api.py (reported line 337)May include surrounding context.

python
IDLE_WEBHOOK, data=data,
            headers={"Content-Type": "application/json"},
        )
        urllib.request.urlopen(req, timeout=10)
    except Exception as e:
        _idle_status["error"] = f"webhook: {e}"

Tainted flow: 'req' from os.getenv (line 42, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

The script sends contact and note data to a network endpoint whose base URL is taken directly from the IMAP_MAIL_API environment variable without validation or transport guarantees. If that variable is tampered with, the tool can exfiltrate sensitive CRM data to an attacker-controlled service, and the default/plain HTTP transport also weakens confidentiality and integrity.

Content

Scanner excerpt · scripts/manage_contacts.py (reported line 47)May include surrounding context.

python
headers={"Content-Type": "application/json"} if data else {},
    )
    try:
        resp = urllib.request.urlopen(req, timeout=10)
        return json.loads(resp.read().decode())
    except urllib.error.HTTPError as e:
        body = e.read().decode()

Tainted flow: 'url' from os.getenv (line 35, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/check_inbox.py (reported line 37)May include surrounding context.

python
def api_get(path):
    url = API.rstrip("/") + path
    try:
        resp = urllib.request.urlopen(urllib.request.Request(url), timeout=10)
        return json.loads(resp.read().decode())
    except urllib.error.HTTPError as e:
        print(f"HTTP {e.code}: {e.read().decode()}", file=sys.stderr)

Tainted flow: 'url' from os.getenv (line 35, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/scripts/check_inbox.py (reported line 37)May include surrounding context.

python
def api_get(path):
    url = API.rstrip("/") + path
    try:
        resp = urllib.request.urlopen(urllib.request.Request(url), timeout=10)
        return json.loads(resp.read().decode())
    except urllib.error.HTTPError as e:
        print(f"HTTP {e.code}: {e.read().decode()}", file=sys.stderr)

Tainted flow: 'url' from os.getenv (line 70, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/group_inbox.py (reported line 59)May include surrounding context.

python
def api_get(path):
    url = API.rstrip("/") + path
    try:
        resp = urllib.request.urlopen(urllib.request.Request(url), timeout=20)
        return json.loads(resp.read().decode())
    except urllib.error.HTTPError as e:
        print(f"HTTP {e.code}: {e.read().decode()}", file=sys.stderr)

Tainted flow: 'url' from os.getenv (line 70, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/scripts/group_inbox.py (reported line 59)May include surrounding context.

python
def api_get(path):
    url = API.rstrip("/") + path
    try:
        resp = urllib.request.urlopen(urllib.request.Request(url), timeout=20)
        return json.loads(resp.read().decode())
    except urllib.error.HTTPError as e:
        print(f"HTTP {e.code}: {e.read().decode()}", file=sys.stderr)

Tainted flow: 'req' from os.getenv (line 74, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/group_inbox.py (reported line 79)May include surrounding context.

python
headers={"Content-Type": "application/json"},
    )
    try:
        resp = urllib.request.urlopen(req, timeout=30)
        return json.loads(resp.read().decode())
    except urllib.error.HTTPError as e:
        print(f"HTTP {e.code}: {e.read().decode()}", file=sys.stderr)

Tainted flow: 'req' from os.getenv (line 74, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/scripts/group_inbox.py (reported line 79)May include surrounding context.

python
headers={"Content-Type": "application/json"},
    )
    try:
        resp = urllib.request.urlopen(req, timeout=30)
        return json.loads(resp.read().decode())
    except urllib.error.HTTPError as e:
        print(f"HTTP {e.code}: {e.read().decode()}", file=sys.stderr)

Tainted flow: 'req' from os.getenv (line 333, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
96% confidence
Finding

The webhook URL is taken from environment configuration and the code posts full message data to it, including message bodies and metadata. If an attacker can influence configuration or if the webhook points to an unintended host, this becomes an exfiltration channel for sensitive email contents; the optional unverified TLS mode further increases the risk of interception or redirection.

Content

Scanner excerpt · scripts/scripts/mail-api.py (reported line 337)May include surrounding context.

python
IDLE_WEBHOOK, data=data,
            headers={"Content-Type": "application/json"},
        )
        urllib.request.urlopen(req, timeout=10)
    except Exception as e:
        _idle_status["error"] = f"webhook: {e}"

Tainted flow: 'req' from os.getenv (line 42, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/scripts/manage_contacts.py (reported line 47)May include surrounding context.

python
headers={"Content-Type": "application/json"} if data else {},
    )
    try:
        resp = urllib.request.urlopen(req, timeout=10)
        return json.loads(resp.read().decode())
    except urllib.error.HTTPError as e:
        body = e.read().decode()

Tainted flow: 'url' from os.getenv (line 69, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/manage_folders.py (reported line 38)May include surrounding context.

python
def api_get(path):
    url = API.rstrip("/") + path
    try:
        resp = urllib.request.urlopen(urllib.request.Request(url), timeout=10)
        return json.loads(resp.read().decode())
    except urllib.error.HTTPError as e:
        print(f"HTTP {e.code}: {e.read().decode()}", file=sys.stderr)

Tainted flow: 'url' from os.getenv (line 69, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/scripts/manage_folders.py (reported line 38)May include surrounding context.

python
def api_get(path):
    url = API.rstrip("/") + path
    try:
        resp = urllib.request.urlopen(urllib.request.Request(url), timeout=10)
        return json.loads(resp.read().decode())
    except urllib.error.HTTPError as e:
        print(f"HTTP {e.code}: {e.read().decode()}", file=sys.stderr)

Tainted flow: 'req' from os.getenv (line 70, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/manage_folders.py (reported line 58)May include surrounding context.

python
method="POST",
    )
    try:
        resp = urllib.request.urlopen(req, timeout=10)
        return json.loads(resp.read().decode())
    except urllib.error.HTTPError as e:
        print(f"HTTP {e.code}: {e.read().decode()}", file=sys.stderr)

Tainted flow: 'req' from os.getenv (line 70, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/manage_folders.py (reported line 72)May include surrounding context.

python
method="POST",
    )
    try:
        resp = urllib.request.urlopen(req, timeout=10)
        return json.loads(resp.read().decode())
    except urllib.error.HTTPError as e:
        print(f"HTTP {e.code}: {e.read().decode()}", file=sys.stderr)

Tainted flow: 'req' from os.getenv (line 70, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/scripts/manage_folders.py (reported line 58)May include surrounding context.

python
method="POST",
    )
    try:
        resp = urllib.request.urlopen(req, timeout=10)
        return json.loads(resp.read().decode())
    except urllib.error.HTTPError as e:
        print(f"HTTP {e.code}: {e.read().decode()}", file=sys.stderr)

Tainted flow: 'req' from os.getenv (line 70, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/scripts/manage_folders.py (reported line 72)May include surrounding context.

python
method="POST",
    )
    try:
        resp = urllib.request.urlopen(req, timeout=10)
        return json.loads(resp.read().decode())
    except urllib.error.HTTPError as e:
        print(f"HTTP {e.code}: {e.read().decode()}", file=sys.stderr)

Tainted flow: 'req' from os.getenv (line 48, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/manage_rules.py (reported line 53)May include surrounding context.

python
headers={"Content-Type": "application/json"} if data else {},
    )
    try:
        resp = urllib.request.urlopen(req, timeout=10)
        return json.loads(resp.read().decode())
    except urllib.error.HTTPError as e:
        print(f"HTTP {e.code}: {e.read().decode()}", file=sys.stderr)

Tainted flow: 'req' from os.getenv (line 48, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/scripts/manage_rules.py (reported line 53)May include surrounding context.

python
headers={"Content-Type": "application/json"} if data else {},
    )
    try:
        resp = urllib.request.urlopen(req, timeout=10)
        return json.loads(resp.read().decode())
    except urllib.error.HTTPError as e:
        print(f"HTTP {e.code}: {e.read().decode()}", file=sys.stderr)

Tainted flow: 'url' from os.getenv (line 34, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/scripts/search.py (reported line 36)May include surrounding context.

python
def api_get(path):
    url = API.rstrip("/") + path
    try:
        resp = urllib.request.urlopen(urllib.request.Request(url), timeout=15)
        return json.loads(resp.read().decode())
    except urllib.error.HTTPError as e:
        print(f"HTTP {e.code}: {e.read().decode()}", file=sys.stderr)

Tainted flow: 'url' from os.getenv (line 34, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/search.py (reported line 36)May include surrounding context.

python
def api_get(path):
    url = API.rstrip("/") + path
    try:
        resp = urllib.request.urlopen(urllib.request.Request(url), timeout=15)
        return json.loads(resp.read().decode())
    except urllib.error.HTTPError as e:
        print(f"HTTP {e.code}: {e.read().decode()}", file=sys.stderr)

Tainted flow: 'req' from os.getenv (line 29, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/scripts/send_email.py (reported line 35)May include surrounding context.

python
method="POST",
    )
    try:
        resp = urllib.request.urlopen(req, timeout=15)
        return json.loads(resp.read().decode())
    except urllib.error.HTTPError as e:
        print(f"HTTP {e.code}: {e.read().decode()}", file=sys.stderr)

Tainted flow: 'req' from os.getenv (line 29, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/send_email.py (reported line 35)May include surrounding context.

python
method="POST",
    )
    try:
        resp = urllib.request.urlopen(req, timeout=15)
        return json.loads(resp.read().decode())
    except urllib.error.HTTPError as e:
        print(f"HTTP {e.code}: {e.read().decode()}", file=sys.stderr)

Tainted flow: 'req' from os.getenv (line 45, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/scripts/sort_inbox.py (reported line 48)May include surrounding context.

python
req = urllib.request.Request(url, data=b"", method="POST",
                                 headers={"Content-Type": "application/json"})
    try:
        resp = urllib.request.urlopen(req, timeout=30)
        return json.loads(resp.read().decode())
    except urllib.error.HTTPError as e:
        print(f"HTTP {e.code}: {e.read().decode()}", file=sys.stderr)

Tainted flow: 'req' from os.getenv (line 45, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/sort_inbox.py (reported line 48)May include surrounding context.

python
req = urllib.request.Request(url, data=b"", method="POST",
                                 headers={"Content-Type": "application/json"})
    try:
        resp = urllib.request.urlopen(req, timeout=30)
        return json.loads(resp.read().decode())
    except urllib.error.HTTPError as e:
        print(f"HTTP {e.code}: {e.read().decode()}", file=sys.stderr)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The description promises a broad email skill for standard IMAP/SMTP-based personal email management, including sending mail, checking inboxes, searching, mailbox listing, attachment saving, scheduling emails, and push notifications. The supplied code instead implements a narrow inbox-grouping utility. It analyzes messages via HTTP endpoints, suggests recurring sender/subject groups, applies moves into subfolders, and manages auto-grouping state. While moving messages between folders is loosely related to email management, the primary behavior is materially different from the declared general email functionality, and several prominent declared capabilities are absent from this code chunk. Therefore the description does not accurately represent what this code actually does.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.