Back to skill

Security audit

Cloudflare Mail Reader

Security checks for vulnerabilities and agentic risk

Overview

This skill has a legitimate mailbox-reading purpose, but it can send admin mail credentials to a user-selected API URL and exposes sensitive email contents and verification codes.

Install only if you trust the mail backend and operators who can invoke it. Use a narrowly scoped, rotatable admin credential, do not set `--api-url` or `CLOUDFLARE_MAIL_MAILS_API_URL` to untrusted hosts, and treat outputs, transcripts, and CSV exports as sensitive because they may contain private emails, OTPs, or account-recovery data.

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 (1)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/read_mails.py:61
Finding
Credential Exfiltration Through an Unrestricted API Destination<![CDATA[ ## Vulnerability Details **File Location**: `scripts/read_mails.py:61-65`, `scripts/read_mails.py:329-365`, and `scripts/read_mails.py:573-584` **Vulnerability Type**: Unrestricted credential-bearing outbound request **Risk Level**: High The script allows its API destination to be overridden through either the `--api-url` command-line argument or the `CLOUDFLARE_MAIL_MAILS_API_URL` environment variable. It then attaches the administrative credential and every configured optional authentication header to that destination without validating the URL's scheme, hostname, port, or path. Relevant configuration code: ```python parser.add_argument( "--api-url", default=os.getenv(ENV_API_URL, DEFAULT_API_URL), help=f"Admin API URL. Defaults to {DEFAULT_API_URL}.", ) ``` Authentication headers are assembled independently of the selected destination: ```python def build_headers(args: argparse.Namespace) -> tuple[Optional[dict[str, str]], Optional[str]]: admin_auth = args.admin_auth or os.getenv(ENV_ADMIN_AUTH) if not admin_auth: return None, f"missing admin credential: provide --admin-auth or {ENV_ADMIN_AUTH}" headers = { "Accept": "application/json", "Content-Type": "application/json", "x-admin-auth": admin_auth, } bearer_token = args.bearer_token or os.getenv(ENV_BEARER_TOKEN) if bearer_token: token = bearer_token.strip() if token: headers["Authorization"] = token if token.lower().startswith("bearer ") else f"Bearer {token}" custom_auth = args.custom_auth or os.getenv(ENV_CUSTOM_AUTH) if custom_auth: headers["x-custom-auth"] = custom_auth fingerprint = args.fingerprint or os.getenv(ENV_FINGERPRINT) if fingerprint: headers["x-fingerprint"] = fingerprint lang = args.lang or os.getenv(ENV_LANG) if lang: headers["x-lang"] = lang user_token = args.user_token or os.getenv(ENV_USER_TOKEN) if user_token: ...[truncated 3688 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. **Pin credentials to an approved origin** - Parse the URL with `urllib.parse.urlsplit`. - Require `https`. - Permit only an explicit allowlist of hostnames and ports. - Require the expected `/admin/mails` path. - Reject embedded user information, fragments, malformed ports, and ambiguous hostnames. 2. **Remove unrestricted endpoint overrides** - If custom deployments are unnecessary, remove `--api-url` and `CLOUDFLARE_MAIL_MAILS_API_URL`. - If they are necessary, require the origin to be added to trusted configuration separately from user-controlled invocation arguments. - Require explicit interactive confirmation before sending credentials to a non-default approved origin. 3. **Constrain redirects** - Disable automatic redirects for authenticated requests, or implement a redirect handler that revalidates every destination. - Never forward authentication headers when the scheme, hostname, or port changes. - Prefer failing closed and requiring a separately authenticated request to the new destination. 4. **Bind credentials to destinations** - Maintain separate credentials for each approved deployment. - Do not reuse the production administrative credential with development or user-supplied endpoints. - Use short-lived, mailbox-scoped tokens instead of a deployment-wide administrative secret where the backend supports them. 5. **Strengthen secret handling** - Prefer environment variables, protected secret stores, or standard input over command-line credential flags because command-line values may be exposed through process listings and shell history. - Redact authentication values from errors and diagnostic output. - Rotate all credentials if they may already have been used with an untrusted URL. 6. **Add regression tests** - Verify rejection of HTTP URLs, unapproved hosts, alternate ports, unexpected paths, user-information components, and cross-origin redirects. - ...[truncated 80 chars]
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (7)

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

Critical
Category
Data Flow
Content
req = request.Request(url, headers=headers, method="GET")

    try:
        with request.urlopen(req, timeout=timeout) as response:
            raw_bytes = response.read()
            payload = load_json_bytes(raw_bytes)
            if payload is None:
Confidence
90% confidence
Finding
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill can access environment variables, write files, and make network requests to an admin mail API, but it declares no explicit tool scope or permission boundaries. That creates unnecessary ambiguity about what the skill is allowed to do and increases the risk of over-broad execution, secret exposure, and mailbox data access beyond user expectations.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The skill is designed to read mailbox contents through an admin API, including potentially sensitive emails and extracted verification codes, but it does not clearly warn users about that sensitivity in the skill description. In this context, the admin endpoint and normalized extraction behavior make the omission more dangerous because users may invoke it without understanding that privileged backend access can expose private message contents.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The examples explicitly instruct reading mailbox contents and exporting emails, but provide no warning that these actions expose sensitive personal data and should only be performed with proper authorization. In the context of an admin mail-reading skill, normalizing unrestricted mailbox access increases the risk of privacy violations, insider misuse, and accidental over-collection of email content.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The script examples show use of an admin authentication secret and mailbox export functionality without any caution about credential handling, least-privilege usage, or risks of writing sensitive email data to local files. Because this skill interfaces with an admin API, readers may copy these examples into unsafe environments, leading to credential leakage or creation of unsecured local email dumps.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
This script prints full mail contents and extracted verification codes to stdout and can also write them to a user-specified file. In an agent/tooling context, stdout, logs, transcripts, and workspace files are often retained or exposed to other components, so this can leak sensitive emails, OTPs, and account-recovery data beyond the immediate intended use.

Natural-Language Policy Violations

Low
Confidence
84% confidence
Finding
The example hard-codes `CLOUDFLARE_MAIL_LANG = "zh"`, which imposes a specific language setting in the documented usage. There is no indication that this is optional, user-selected, or required for a region-specific workflow.

Static analysis

No suspicious patterns detected.