Back to skill

Security audit

Cloudflare Image Generation

Security checks for vulnerabilities and agentic risk

Overview

The skill is a real Cloudflare image generator, but it exposes a Cloudflare token and lets crafted prompts reach shell execution, so it needs review before installation.

Review before installing. The publisher should remove and rotate the exposed Cloudflare token, load credentials from user-controlled secret storage, replace shell-based curl with a native HTTPS client or shell=False argument list, avoid fixed temp files, and document exactly where images are saved and what data is sent to Cloudflare.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/generate_image.py:11
Finding
Hardcoded Cloudflare API Credentials<![CDATA[ ## Vulnerability Details **File Location**: `scripts/generate_image.py`, lines 11-13; the same credentials are also disclosed in `SKILL.md`, lines 9-12 **Vulnerability Type**: Hardcoded secret and plaintext credential exposure **Risk Level**: High ### Vulnerable Code ```python ACCOUNT_ID = "1e89d3ce76cbfef3b5c340e3984b7a52" TOKEN = "aCTA2KaKa1n3ayFDL-LPmZ-JgUC0HHgA5Msy18Bk" MODEL = "@cf/black-forest-labs/flux-1-schnell" ``` The same credential is documented in plaintext: ```markdown ## Credentials - Account ID: `1e89d3ce76cbfef3b5c340e3984b7a52` - Token: `aCTA2KaKa1n3ayFDL-LPmZ-JgUC0HHgA5Msy18Bk` - Model: `@cf/black-forest-labs/flux-1-schnell` ``` ### Technical Analysis A live-looking Cloudflare bearer token and its associated account identifier are embedded directly in the source code and documentation. Anyone who can download, inspect, clone, or otherwise access the Skill package can recover the credential without executing the Skill. Hardcoded secrets cannot be independently protected or rotated without changing the distributed package. They may also remain recoverable from repository history, archives, caches, logs, and previously distributed copies after being removed from the current files. ### Attack Path 1. An attacker obtains or inspects the Skill package. 2. The attacker reads `scripts/generate_image.py` or `SKILL.md`. 3. The attacker extracts the account ID and bearer token. 4. The attacker submits requests directly to Cloudflare using the stolen token. 5. The attacker exercises every permission granted to the token until it is revoked or expires. ### Impact Assessment Successful exploitation allows unauthorized access within the permissions assigned to the exposed token. The likely effects include unauthorized Workers AI requests, quota consumption, service disruption through resource exhaustion, and billing abuse. If the token has broader Cloudflare permissions than required for image generation, resources under the associated ...[truncated 181 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Revoke and rotate the exposed token immediately; treating it as compromised is necessary because it has already been distributed in plaintext. 2. Remove the token from both source code and documentation, including repository history and published artifacts where feasible. 3. Retrieve the token at runtime from a protected environment variable or secret-management service. 4. Fail safely with a clear error if the credential is unavailable; do not provide a default secret. 5. Create a replacement token restricted to only the Cloudflare account, API operation, and resources required for image generation. 6. Apply short expiration periods and usage monitoring where supported. 7. Add secret scanning to development and release pipelines to prevent credentials from being committed again. 8. Review Cloudflare audit and usage records for unauthorized activity involving the disclosed token. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/generate_image.py:22
Finding
Arbitrary Shell Command Injection Through the Image Prompt<![CDATA[ ## Vulnerability Details **File Location**: `scripts/generate_image.py`, lines 22-28 **Vulnerability Type**: OS command injection **Risk Level**: Critical ### Vulnerable Code ```python cmd = f'''curl -s -X POST "https://api.cloudflare.com/client/v4/accounts/{ACCOUNT_ID}/ai/run/{MODEL}" \ -H "Authorization: Bearer {TOKEN}" \ -H "Content-Type: application/json" \ -d '{json.dumps({"prompt": prompt})}' > /tmp/cf_response.json''' subprocess.run(cmd, shell=True) ``` ### Technical Analysis The caller-controlled `prompt` is serialized as JSON and then interpolated into a command string executed with `shell=True`. JSON serialization escapes JSON syntax but does not make content safe for inclusion in a POSIX shell command. The JSON document is placed inside a single-quoted shell argument. A single quote supplied in the prompt can terminate that shell quoting context. Subsequent shell metacharacters can introduce additional commands, pipelines, redirections, or substitutions. The shell then executes the injected content with the same operating-system identity and permissions as the Skill process. The program does not need a shell for this API request. Constructing a shell command therefore creates an avoidable code-execution boundary. ### Attack Path 1. An attacker supplies an image-generation prompt containing a single quote followed by shell syntax. 2. `json.dumps()` produces valid JSON, but the attacker-controlled single quote remains significant to the shell. 3. The prompt is interpolated into the single-quoted `curl -d` argument. 4. The injected single quote terminates the intended shell argument. 5. Attacker-controlled shell operators cause an additional command to execute. 6. `subprocess.run(..., shell=True)` launches the shell and executes both the intended command fragment and the injected command. 7. The injected process inherits the Skill process's user privileges and accessible environment. ### Impact Assessment An attacker who can co ...[truncated 655 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove `shell=True` and do not construct commands through string interpolation. 2. Prefer an in-process HTTPS client such as `urllib.request`, `requests`, or `httpx`. 3. Serialize the request body separately and pass it directly to the HTTP client. 4. If `curl` must be retained, invoke it with an argument array rather than a shell string: ```python payload = json.dumps({"prompt": prompt}) result = subprocess.run( [ "curl", "-sS", "--fail-with-body", "-X", "POST", api_url, "-H", f"Authorization: Bearer {token}", "-H", "Content-Type: application/json", "--data-binary", payload, ], check=True, capture_output=True, text=True, ) data = json.loads(result.stdout) ``` 5. Do not attempt to repair the current implementation only by manually escaping selected metacharacters; eliminating the shell boundary is the reliable mitigation. 6. Run the Skill under a minimally privileged account with restricted filesystem and network access as defense in depth. 7. Add security tests using prompts containing quotes, semicolons, substitutions, redirections, and newlines to confirm that input is treated strictly as data. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/generate_image.py:22
Finding
Predictable Shared Temporary File Enables Symlink Clobbering and Response Races<![CDATA[ ## Vulnerability Details **File Location**: `scripts/generate_image.py`, lines 22-31 **Vulnerability Type**: Insecure temporary file usage **Risk Level**: High ### Vulnerable Code ```python cmd = f'''curl -s -X POST "https://api.cloudflare.com/client/v4/accounts/{ACCOUNT_ID}/ai/run/{MODEL}" \ -H "Authorization: Bearer {TOKEN}" \ -H "Content-Type: application/json" \ -d '{json.dumps({"prompt": prompt})}' > /tmp/cf_response.json''' subprocess.run(cmd, shell=True) with open('/tmp/cf_response.json', 'r') as f: data = json.load(f) ``` ### Technical Analysis Every invocation writes its response to the fixed path `/tmp/cf_response.json`. Shared temporary directories are commonly writable by multiple local users or processes. Shell redirection opens the destination before `curl` runs and follows symbolic links. A local attacker can pre-create `/tmp/cf_response.json` as a symbolic link to another file writable by the Skill's operating-system account. The shell redirection may then truncate and overwrite that target. The predictable name also introduces a time-of-check/time-of-use race: an attacker or concurrent invocation can replace or rewrite the response before the program reads it. Concurrent legitimate invocations use the same file as well, allowing one request to consume another request's response. The file is not removed after use, so API response data also remains in a globally predictable location. ### Attack Path **Symlink clobbering:** 1. A local attacker creates `/tmp/cf_response.json` as a symbolic link to a chosen file. 2. The attacker causes or waits for the Skill to generate an image. 3. Shell redirection follows the symbolic link and opens the target for truncation. 4. The Cloudflare response is written into the target using the Skill process's filesystem privileges. 5. The selected file is corrupted or replaced with response data. **Response substitution or race:** 1. The attacker monitors or repeatedly replaces the pred ...[truncated 841 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Avoid temporary files entirely by capturing the HTTP response in memory and parsing it directly. 2. If temporary storage is unavoidable, create it atomically with Python's `tempfile.NamedTemporaryFile` or `TemporaryFile`. 3. Ensure temporary files have restrictive permissions and are not opened by following an attacker-selected path. 4. Keep the file handle under the process's control rather than closing it and reopening it by pathname. 5. Delete temporary data reliably in a `finally` block or use a context manager that performs automatic cleanup. 6. Give each invocation an independent response object or securely generated temporary file to prevent concurrency collisions. 7. Apply an appropriate response-size limit before reading or decoding untrusted API output. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/generate_image.py:22
Finding
Bearer Token Disclosed Through Spawned Process Command Lines<![CDATA[ ## Vulnerability Details **File Location**: `scripts/generate_image.py`, lines 22-28 **Vulnerability Type**: Secret exposure through process arguments **Risk Level**: Medium ### Vulnerable Code ```python cmd = f'''curl -s -X POST "https://api.cloudflare.com/client/v4/accounts/{ACCOUNT_ID}/ai/run/{MODEL}" \ -H "Authorization: Bearer {TOKEN}" \ -H "Content-Type: application/json" \ -d '{json.dumps({"prompt": prompt})}' > /tmp/cf_response.json''' subprocess.run(cmd, shell=True) ``` ### Technical Analysis The bearer token is embedded in a shell command and then passed to a spawned process. The command is exposed as part of the shell invocation, and the authorization header is subsequently passed as a command-line argument to `curl`. Depending on operating-system process visibility, container isolation, diagnostic tooling, monitoring agents, crash collection, and logging configuration, other users or services may be able to inspect process command lines. This exposes the bearer token beyond the Python process that legitimately needs it. This finding is distinct from hardcoding: even after moving the token to an environment variable or secret manager, inserting it into this command string would continue to expose it through process metadata. ### Attack Path 1. An attacker obtains local process-inspection access or access to process telemetry. 2. The attacker monitors processes while image generation is running. 3. The attacker captures the shell or `curl` command line containing the `Authorization: Bearer ...` header. 4. The attacker extracts the token. 5. The attacker replays the token directly against Cloudflare APIs until it expires or is revoked. ### Impact Assessment The attacker obtains the same Cloudflare API permissions granted to the stolen token. Likely effects include unauthorized AI requests, quota consumption, billing abuse, and service disruption. Broader effects depend on the token's unknown server-side scopes. Exploitability ...[truncated 202 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace the external `curl` process with an in-process HTTPS client. 2. Load the token from protected secret storage only when needed. 3. Set the authorization header through the HTTP client's internal request API rather than a command-line argument. 4. Ensure application errors and debug logs redact authorization headers and token values. 5. Restrict access to process telemetry, diagnostics, crash dumps, and monitoring data. 6. Rotate the currently exposed token and review Cloudflare activity for signs of replay or unauthorized use. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (12)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The skill claims to only generate images, but the content also exposes a hardcoded Cloudflare API token and account ID, writes files locally, and references direct script execution. This mismatch is dangerous because reviewers or automated policy systems may trust the benign description while overlooking sensitive credential exposure and broader execution behavior.

Missing User Warnings

High
Confidence
100% confidence
Finding
The markdown directly includes a live-looking API token and account identifier without any masking or secure-handling guidance. Exposed credentials can be immediately reused by anyone with access to the skill, enabling unauthorized API calls, abuse of the Cloudflare account, cost incurrence, and possible downstream compromise of connected resources.

Context-Inappropriate Capability

High
Confidence
98% confidence
Finding
An image-generation skill only needs to make an HTTP request, but this implementation adds general shell execution capability through `curl` and `shell=True`. In this context, that is unnecessarily dangerous because it expands the skill from simple network use into arbitrary command execution if the prompt or command construction is abused.

Missing User Warnings

High
Confidence
99% confidence
Finding
A live API bearer token is hardcoded directly in the script and used for outbound requests, which exposes a secret to anyone with code access and makes accidental leakage or misuse highly likely. If reused elsewhere or committed to a repository, an attacker could abuse the Cloudflare account, incur cost, or access associated services.

Missing User Warnings

High
Confidence
98% confidence
Finding
The script constructs and executes a shell command from user input without adequate safeguards or disclosure, creating a direct path to command injection. In a skill context, prompts are expected to be attacker-controlled, so treating them as safe command-string content is especially dangerous.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
-H "Content-Type: application/json" \
      -d '{json.dumps({"prompt": prompt})}' > /tmp/cf_response.json'''
    
    subprocess.run(cmd, shell=True)
    
    with open('/tmp/cf_response.json', 'r') as f:
        data = json.load(f)
Confidence
98% confidence
Finding
This is a concrete tool-parameter abuse issue: attacker-controlled prompt data is funneled into a shell-executed command, allowing the tool boundary to be crossed from 'generate an image' into 'run arbitrary OS commands'. In agent skills, this context makes the issue more dangerous because natural-language inputs are routinely untrusted and can be adversarially crafted.

Lp3

Medium
Category
MCP Least Privilege
Confidence
84% confidence
Finding
The skill declares no explicit tool scope even though its documented usage clearly implies shell execution and file access. In an agent environment, missing scope declarations weaken sandboxing and review controls, making it easier for the skill to use capabilities beyond what operators expect.

Description-Behavior Mismatch

Medium
Confidence
81% confidence
Finding
The skill writes API responses to a fixed temporary file and saves generated images to a local workspace path by default, creating local persistence not clearly implied by the stated behavior. This increases exposure because sensitive prompts, generated content, or API responses may remain on disk, and the fixed `/tmp/cf_response.json` path is susceptible to collisions or tampering in shared environments.

Missing User Warnings

Medium
Confidence
87% confidence
Finding
The function derives a default filesystem path and writes the generated image there, but the code provides no prior disclosure that it will create a file in the workspace by default. The save location is only printed after completion, which does not warn the user before the write occurs.

External Transmission

Medium
Category
Data Exfiltration
Content
output_path = f"/home/ubuntu/.openclaw/workspace/{prompt.replace(' ', '_')[:30]}.png"
    
    # Call Cloudflare API
    cmd = f'''curl -s -X POST "https://api.cloudflare.com/client/v4/accounts/{ACCOUNT_ID}/ai/run/{MODEL}" \
      -H "Authorization: Bearer {TOKEN}" \
      -H "Content-Type: application/json" \
      -d '{json.dumps({"prompt": prompt})}' > /tmp/cf_response.json'''
Confidence
70% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
output_path = f"/home/ubuntu/.openclaw/workspace/{prompt.replace(' ', '_')[:30]}.png"
    
    # Call Cloudflare API
    cmd = f'''curl -s -X POST "https://api.cloudflare.com/client/v4/accounts/{ACCOUNT_ID}/ai/run/{MODEL}" \
      -H "Authorization: Bearer {TOKEN}" \
      -H "Content-Type: application/json" \
      -d '{json.dumps({"prompt": prompt})}' > /tmp/cf_response.json'''
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
-H "Content-Type: application/json" \
      -d '{json.dumps({"prompt": prompt})}' > /tmp/cf_response.json'''
    
    subprocess.run(cmd, shell=True)
    
    with open('/tmp/cf_response.json', 'r') as f:
        data = json.load(f)
Confidence
98% confidence
Finding
The script builds a shell command containing user-controlled input (`prompt`) and executes it with `shell=True`, which creates a command-injection path. Even though `json.dumps` escapes JSON syntax, it does not make shell interpolation safe; a crafted prompt containing shell-significant characters can break quoting and execute arbitrary commands on the host.

Static analysis

No suspicious patterns detected.