Back to skill

Security audit

A safer e-mail assistant

Security checks for vulnerabilities and agentic risk

Overview

The skill matches its email-assistant purpose, but it needs Review because it can expose sensitive mailbox contents through helper output and does not guard bearer-token HTTP gateway use tightly enough.

Install only if you trust the configured email gateway and are comfortable granting it access to the selected mailbox accounts. Use HTTPS for any non-local gateway, prefer narrowly scoped and revocable API keys, avoid running the helper where stdout is captured into shared logs, and restrict the state file location and permissions.

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

Warning
Location
scripts/check_new_messages.py:92
Finding

Bearer API Credential Can Be Transmitted over Unencrypted HTTP

Content
View full analysis

Vulnerability Details

File Location: scripts/check_new_messages.py:55-56 and scripts/check_new_messages.py:92-105
Vulnerability Type: Unrestricted destination and insecure transport for sensitive authentication data
Risk Level: Medium

Vulnerable Code

python
base_url = env_required("GATEWAY_BASE_URL").rstrip("/")
api_key = env_required("GATEWAY_API_KEY")
python
def api_request(cfg: Config, method: str, path: str, payload: dict[str, Any] | None = None) -> dict[str, Any]:
    url = f"{cfg.base_url}{path}"
    body = None
    headers = {
        "Authorization": f"Bearer {cfg.api_key}",
        "Content-Type": "application/json",
    }
    if payload is not None:
        body = json.dumps(payload).encode("utf-8")
    req = request.Request(url=url, method=method, data=body, headers=headers)
    try:
        with request.urlopen(req, timeout=30) as resp:

The documentation explicitly presents a cleartext URL as the configuration example:

markdown
- `GATEWAY_BASE_URL` (example: `http://localhost:8000`)

Technical Analysis

The helper reads GATEWAY_BASE_URL directly from the environment and attaches the bearer API key to every request without validating the URL scheme or destination. Although plain HTTP can be acceptable for a gateway strictly bound to a loopback interface, the implementation also accepts remote HTTP destinations.

When a remote cleartext destination is supplied, the bearer credential, account identifiers, synchronization parameters, draft contents, and retrieved mailbox information can traverse the network without encryption. The configured server receives the bearer token by design, so an erroneous or attacker-influenced environment configuration can also disclose it to an unintended endpoint.

No hard-coded exfiltration destination was found. Exploitation requires control over configuration, DNS or network traffic, or the configured gatew ...[truncated 1410 chars]

Remediation
View remediation

Remediation Suggestions

  1. Parse GATEWAY_BASE_URL with urllib.parse.urlsplit before making requests.
  2. Require https for every non-loopback destination.
  3. Permit plain HTTP only when the resolved destination is explicitly limited to localhost, 127.0.0.0/8, or ::1.
  4. Reject unsupported schemes, URLs containing embedded credentials, fragments, and malformed hostnames.
  5. Consider a configurable allowlist of trusted gateway hostnames and ports.
  6. Prevent HTTPS-to-HTTP redirects, particularly because authorization headers may be exposed or requests may be downgraded.
  7. Use valid certificate verification and avoid adding options that disable TLS validation.
  8. Issue narrowly scoped, revocable credentials per installation or account rather than one broadly privileged token.
  9. Replace the generic HTTP example in SKILL.md and api-reference.md with an HTTPS example. Clearly state that HTTP is allowed only for a loopback-only deployment.
  10. Rotate the API key immediately if it may previously have been used with a remote HTTP endpoint.

T09 · Insecure Skill Coding Practices

Note
Location
scripts/check_new_messages.py:199
Finding

Complete Email Message Records Are Written to Standard Output

Content
View full analysis

Vulnerability Details

File Location: scripts/check_new_messages.py:199-216 and scripts/check_new_messages.py:239-242
Vulnerability Type: Excessive disclosure of sensitive mailbox content through process output
Risk Level: Low

Vulnerable Code

python
list_payload = {
    "since": since_iso,
    "until": now_iso,
    "direction": "incoming",
    "limit": cfg.list_limit,
    "offset": 0,
    "include_body": True,
}
listed = api_request(cfg, "POST", f"/v1/accounts/{account_id}/messages:list", list_payload)
messages = listed.get("messages", [])
seen_ids = set(account_state.get("seen_ids", []))
unseen = [m for m in messages if m.get("id") not in seen_ids]
output: dict[str, Any] = {
    "account_id": account_id,
    "new_message_count": len(unseen),
    "messages": unseen,
}
python
if len(results) == 1:
    print(json.dumps(results[0], indent=2))
else:
    print(json.dumps({"account_count": len(results), "accounts": results}, indent=2))

Technical Analysis

The polling helper unconditionally requests body content by setting include_body to True. It then places each complete unseen-message object returned by the gateway into the output structure and serializes that structure to standard output.

Message bodies can be necessary for importance classification, but exposing complete records through stdout is not the minimum privilege or data exposure required for routine polling. Output from scheduled jobs and Agent tools is commonly retained in cron mail, service journals, CI logs, terminal history, monitoring systems, or Agent conversation transcripts. Those destinations may have broader access controls and longer retention periods than the mailbox gateway.

The script does not explicitly transmit stdout to a third party, and raw body retrieval is not enabled. Exploitation therefore depends on another user or system being able to access retained process output. ...[truncated 1368 chars]

Remediation
View remediation

Remediation Suggestions

  1. Change the default request to "include_body": False.
  2. Add an explicit opt-in environment variable or command-line option for retrieving and printing message bodies.
  3. Emit only fields required for polling, such as canonical ID, sender, subject, timestamp, safety status, and importance result.
  4. Separate machine-readable summary output from a protected body-processing path.
  5. Redact or omit recipient lists, body text, attachment metadata, and other unnecessary response fields.
  6. Add a safe-output mode that reports only counts and message identifiers.
  7. Warn users that body-enabled output must not be sent to shared logs or monitoring collectors.
  8. Configure scheduler and service logs with restrictive permissions, short retention periods, and encryption where available.
  9. If body content is required for classification, process it in memory and output only the classification and a short rationale rather than the original content.
  10. Review existing Agent transcripts and scheduler logs for prior mailbox disclosure and remove or restrict them as appropriate.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • 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
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (6)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The skill behavior and description are inconsistent: the metadata advertises email triage, history questions, and draft replies, while the static finding indicates undeclared persistent state tracking and incomplete declaration of actual behaviors. Description-behavior mismatches are dangerous because they undermine informed consent and make it easier for a skill to retain mailbox-derived metadata locally without the user's clear awareness.

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 allowed-tools despite clearly requiring environment access, local file read/write, and network connectivity. This weakens least-privilege controls and can cause the runtime to grant broader capabilities than users expect, which is especially sensitive for a mailbox-oriented skill handling email content and API credentials.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
86% confidence
Finding

The documented messages:list and messages:get endpoints allow access to cached messages for an account, but the markdown provides no warning about privacy, data handling, or sensitivity of mailbox contents. Because this behavior can affect user data and confidentiality, the skill description should disclose it clearly.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

This markdown file documents filters such as include_raw_body and include_body, which enable access to full email content, but it does not warn users that these operations may expose sensitive personal or confidential data. For a skill handling email data, the description should explicitly disclose privacy-impacting behavior when body content can be retrieved.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script explicitly requests include_body: True and then prints the resulting unseen messages as JSON, which can expose full email contents to logs, terminal scrollback, downstream agents, or other observers. In an email-assistant skill, mailbox contents are highly sensitive by default, so dumping full bodies without minimization or redaction creates a real confidentiality risk even if the functionality is intended.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
82% confidence
Finding

The script performs multiple HTTP API calls to trigger sync jobs and list messages for configured accounts, sending time ranges, folder selections, and account identifiers to a remote gateway. While network access is central to the script's purpose, the file lacks an explicit warning that it contacts an external service and processes mailbox data remotely.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.