Back to skill

Security audit

email-triage

Security checks for vulnerabilities and agentic risk

Overview

The skill is a real email triage tool, but it needs review because it can send private email excerpts to a configurable Ollama endpoint and stores email excerpts locally without strong safeguards.

Review this skill before installing if the mailbox may contain sensitive personal, business, security, legal, or financial messages. Keep OLLAMA_URL on localhost unless you intentionally trust a remote service with email excerpts, place EMAIL_TRIAGE_STATE in a private directory, and consider removing stored previews or tightening file permissions before regular use.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/email-triage.py:153
Finding

Configurable Ollama Endpoint Can Exfiltrate Sensitive Email Content

Content
View full analysis
", "reason": ""}}""" payload = json.dumps({ "model": OLLAMA_MODEL, "prompt": prompt, "stream": False, "options": { "temperature": 0.1, "num_predict": 100, }, }).encode() try: req = urllib.request.Request( f"{OLLAMA_URL}/api/generate", data=payload, headers={"Content-Type": "application/json"}, ) with urllib.request.urlopen(req, timeout=CLASSIFICATION_TIMEOUT) as resp: result = json.loads(resp.read()) response_text = result.get("response", "").strip() ``` The destination is configured without restrictions: ```python OLLAMA_URL = os.environ.get("OLLAMA_URL", "http://127.0.0.1:11434") ``` ### Technical Analysis For every newly processed unread email, the script inserts the sender, subject, and up to 300 characters of the body preview into an Ollama prompt. It then sends that prompt to the endpoint specified by `OLLAMA_URL`. Although the default endpoint is loopback-only, the configuration accepts an arbitrary URL. The implementation does not: - Restrict the destination to loopback or another trusted allowlist. - Require explicit consent before using a remote endpoint. - Require HTTPS for non-local destinations. - Warn that mailbox content will be transmitted. - Redact sensitive values from the subject, sender, or preview. - Disable redirects to untrusted destinations. Consequently, a malicious or mistakenly supplied environment variable can cause private mailbox content to be sent to an external server. If plain HTTP is used remotely, intermediaries may also intercept or alter the request. The broad exception handler ...[truncated 1544 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/email-triage.py:123
Finding

Email Metadata and Body Previews Are Stored Without Restrictive File Permissions

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • 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 (8)

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

Critical
Category
Data Flow
Confidence
97% confidence
Finding

The script sends sender, subject, and body preview content from emails to a network endpoint whose base URL is fully controlled by the OLLAMA_URL environment variable. If that variable is changed to a remote or attacker-controlled host, sensitive inbox content is exfiltrated over the network, and the default uses plain HTTP rather than authenticated or pinned transport.

Content

Scanner excerpt · scripts/email-triage.py (reported line 194)May include surrounding context.

python
data=payload,
            headers={"Content-Type": "application/json"},
        )
        with urllib.request.urlopen(req, timeout=CLASSIFICATION_TIMEOUT) as resp:
            result = json.loads(resp.read())
            response_text = result.get("response", "").strip()

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The declared purpose understates important behaviors with security and privacy implications: the skill accesses a remote mailbox using credentials and stores triage state/email metadata locally. Even if this is functionally related to triage, incomplete disclosure can mislead users about the sensitivity of accessed data and the persistence of potentially confidential email information.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding

The skill declares no explicit tool scope or permissions even though its documented behavior requires reading environment secrets, making network connections to IMAP/Ollama, and writing a local state file. This creates an authorization transparency gap: operators may approve or run the skill without understanding that it can access mailbox contents and persist email-derived data.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The skill mentions Ollama for classification but does not clearly warn that email bodies, subjects, senders, or related metadata may be transmitted to the Ollama service endpoint for processing. Because emails often contain sensitive personal, legal, financial, or security information, insufficient disclosure can lead to unintentional exposure to another service, even if hosted locally by default.

Content

No source excerpt is available for this finding.

Tainted flow: 'STATE_FILE' from os.environ.get (line 51, credential/environment) → open (file write)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · scripts/email-triage.py (reported line 148)May include surrounding context.

python
"""Write triage state to disk."""
    STATE_FILE.parent.mkdir(parents=True, exist_ok=True)
    state["last_check"] = datetime.now(timezone.utc).isoformat()
    with open(STATE_FILE, "w") as f:
        json.dump(state, f, indent=2)

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

Email content is transmitted to the Ollama endpoint during classification, but the operation does not provide an explicit runtime disclosure or consent checkpoint. In a skill that processes potentially sensitive inbox data, silent forwarding of message previews increases privacy and data-handling risk, especially if operators assume processing is entirely local.

Content

No source excerpt is available for this finding.

Ssd 3

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The script persistently stores email subject, sender, date, and body preview in a JSON state file and later prints that content back in reports. This creates a durable local disclosure channel for potentially sensitive inbox data, and there are no access controls, redaction rules, retention safeguards beyond count-based pruning, or explicit file-permission hardening.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
79% confidence
Finding

The code accesses IMAP_USER and IMAP_PASS directly from environment variables to authenticate to the mail server. While this is common practice, there is no accompanying warning or guidance in code comments or runtime messaging about handling mailbox credentials securely or the implications of using them.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.