Back to skill

Security audit

Cloudflare Mail Address Creator

Security checks for vulnerabilities and agentic risk

Overview

The skill does what it says, but it handles admin and mailbox credentials in ways that are too broadly scoped and easy to expose.

Install only if you trust the environment and the admin API endpoint. Before use, avoid setting CLOUDFLARE_MAIL_API_URL unless you intentionally control that endpoint, treat CLOUDFLARE_MAIL_ADMIN_AUTH, JWTs, and passwords as secrets, and avoid returning or exporting full raw output where transcripts, logs, shared terminals, or CSV/JSON files could expose mailbox access credentials.

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/create_address.py:54
Finding
Administrative credentials can be transmitted to an arbitrary network endpoint<![CDATA[ ## Vulnerability Details **File Location**: `scripts/create_address.py:23`, `scripts/create_address.py:54-56`, `scripts/create_address.py:212-237`, and `scripts/create_address.py:256-259` **Vulnerability Type**: Unrestricted credential destination and sensitive-header disclosure **Risk Level**: High ### Vulnerable Code ```python ENV_API_URL = "CLOUDFLARE_MAIL_API_URL" ``` ```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}.", ) ``` ```python def build_headers(args: argparse.Namespace) -> tuple[Optional[dict], 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 = { "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() headers["Authorization"] = token if token.lower().startswith("bearer ") else f"Bearer {token}" 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: headers["x-user-token"] = user_token return headers, None ``` ```python req = request.Request(api_url, data=body, headers=headers, method="POST") try: with request.urlopen(req, timeout=timeout) as response: ``` ### Technical Analysis The script permits the destination URL to be controlled through either the `--api-url` command-line argument or the `CLOUDFLARE_MAIL_API_URL` environment variable. It does not validate the URL scheme, hostname, port, path, or final redirect destination before attaching sensit ...[truncated 2147 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove `--api-url` and `CLOUDFLARE_MAIL_API_URL` if support for alternate servers is not operationally required. 2. If endpoint configuration is necessary, parse the URL and enforce an explicit allowlist: - Scheme must be `https` - Hostname must be `mail-api.suilong.online` - Port must be the expected HTTPS port - Path must be `/admin/new_address` - User information and fragments must be rejected 3. Disable automatic redirects for authenticated requests, or validate every redirect destination before forwarding any sensitive header. 4. Never forward authentication headers across origins. 5. Separate optional credentials so that only headers explicitly required by the selected trusted endpoint are transmitted. 6. Display the validated destination and require explicit confirmation when any nondefault endpoint is used. 7. Add automated tests proving that HTTP URLs, unexpected domains, deceptive subdomains, alternate ports, and cross-origin redirects are rejected. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/create_address.py:158
Finding
Mailbox JWTs and passwords are exposed through standard output and plaintext exports<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:17`, `scripts/create_address.py:158-164`, `scripts/create_address.py:342-385`, and `scripts/create_address.py:394-400` **Vulnerability Type**: Plaintext sensitive-data exposure **Risk Level**: Medium ### Vulnerable Code The Skill explicitly instructs the Agent to return the complete script output: ```markdown 6. Return the script's JSON output directly unless the user asks for a reformatted summary. ``` The response-normalization logic retains mailbox credentials: ```python def success_result(data: dict, fallback_address: str, name: Optional[str] = None) -> dict: payload = { "status": "created", "address": data.get("address") or fallback_address, "jwt": data.get("jwt"), "password": data.get("password"), "error": None, } if name is not None: payload["name"] = name return payload ``` CSV output also includes both sensitive fields: ```python fieldnames = [ "row_type", "requested", "created", "already_exists", "failed", "name", "status", "address", "jwt", "password", "error", ] ``` ```python writer.writerow( { "row_type": "result", "name": item.get("name") or "", "status": item.get("status") or "", "address": item.get("address") or "", "jwt": item.get("jwt") or "", "password": item.get("password") or "", "error": item.get("error") or "", } ) ``` The rendered credentials are written to a regular file and always printed: ```python def emit_output(payload: dict, output_format: str, output_file: Optional[str]) -> None: rendered = json_text(payload) if output_format == "json" else csv_text(payload) if output_file: path = Path(output_file) if path.parent and not path.parent.exists(): path.parent.mkdir(parents=True, exist_ok=True) path.write_text(rendered, encoding="utf-8", newline="") ...[truncated 2266 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Redact `jwt` and `password` from default JSON and CSV output. 2. Add an explicit option such as `--show-secrets` for workflows that genuinely require credential delivery. 3. Update `SKILL.md` so the Agent summarizes status and address by default rather than reproducing authentication secrets. 4. If a secret must be returned, present it once through an approved secret-delivery channel rather than ordinary chat or logs. 5. Avoid printing secrets to standard output when `--output-file` is used. 6. Create secret-bearing files atomically with owner-only permissions, such as mode `0600` on supported systems. 7. Refuse to overwrite existing files unless the user explicitly opts in. 8. Warn users that CSV and JSON exports may contain credentials and should not be committed, uploaded, or shared. 9. Consider returning an opaque credential reference rather than the credential itself. 10. Add tests confirming that default output, error messages, and logs do not contain JWTs or passwords. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • 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 256, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Content
req = request.Request(api_url, data=body, headers=headers, method="POST")

    try:
        with request.urlopen(req, timeout=timeout) as response:
            raw_bytes = response.read()
            payload = load_json_bytes(raw_bytes)
            if payload is None:
Confidence
95% confidence
Finding
The API URL is configurable from an environment variable or CLI argument, while the request includes sensitive admin and bearer credentials in headers. If an attacker can influence that URL, the script will send privileged credentials and mailbox-creation requests to an arbitrary endpoint, enabling secret exfiltration and misuse of admin capabilities. In this skill context, that is especially dangerous because the tool is explicitly built to call an admin API with high-value credentials.

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill uses capabilities that can access environment variables, read and write files, and make network requests, yet it declares no explicit tool scope or permission boundary. In a skill that performs authenticated admin API actions and can export results to disk, this increases the chance of unintended secret access, overbroad execution, or misuse beyond the user's expectations.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The skill description and workflow do not clearly warn that it will perform authenticated admin API calls that create mailboxes and may write export files. Because these are privileged, state-changing operations, a user or calling agent may invoke the skill without fully understanding that it will consume admin credentials, modify backend resources, and potentially persist sensitive operational data to disk.

Vague Triggers

Medium
Confidence
95% confidence
Finding
The skill enables implicit invocation without any visible narrowing conditions, so an agent may auto-select it for loosely related requests involving email creation or mailbox management. Because this skill calls an admin API that provisions mail addresses, overly broad activation increases the chance of unintended privileged actions, especially from ambiguous prompts or prompt-injection attempts that steer the agent toward backend mailbox creation.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The examples instruct users to place an admin authentication secret in an environment variable and also show success output containing a JWT, but they do not warn that these are sensitive credentials that must not be logged, shared, or exposed in transcripts and output files. In the context of an admin API that creates mailboxes, accidental disclosure could let an attacker create or manage addresses or reuse returned tokens for unauthorized access.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The script reads admin and bearer credentials from arguments or environment variables and sends them as HTTP headers to the configured API endpoint. There is no visible runtime warning, log, or explanatory comment disclosing that local credentials and request metadata will be transmitted over the network.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The script prints and optionally stores returned mailbox credentials such as jwt and password in cleartext. In multi-user systems, CI logs, agent transcripts, shell history capture, or world-readable files, those secrets can be exposed to unintended parties and allow takeover of the newly created mailboxes. Because this skill's purpose is account/mailbox provisioning, the returned secrets are operationally sensitive and should be handled as credentials.

Static analysis

No suspicious patterns detected.