Back to skill

Security audit

design pick2

Security checks for vulnerabilities and agentic risk

Overview

This skill should go to Review because it claims to make food collages but also ships an undeclared Cloudflare image-generation script with embedded credentials and unsafe shell execution.

Do not install this version without review and remediation. The collage script itself is a straightforward local image compositor, but the package should remove or fully disclose the Cloudflare image-generation script, revoke and replace the exposed token, avoid shell=True with prompt input, and handle API responses without a shared /tmp file.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/generate_image.py:13
Finding
Hardcoded Cloudflare API Credential in Source Code<![CDATA[ ## Vulnerability Details **File Location**: `scripts/generate_image.py`, lines 13-14 **Vulnerability Type**: Hardcoded bearer token and account identifier **Risk Level**: High ### Vulnerable Code ```python ACCOUNT_ID = "1e89d3ce76cbfef3b5c340e3984b7a52" TOKEN = "aCTA2KaKa1n3ayFDL-LPmZ-JgUC0HHgA5Msy18Bk" ``` ### Technical Analysis The script embeds a Cloudflare account identifier and bearer token directly in its source code. Any person or process capable of reading the skill package can recover and reuse the credential independently of the script. Source-controlled credentials are difficult to contain because they may remain in repository history, build artifacts, caches, backups, logs, or previously distributed copies even after being removed from the current version. The token's validity and exact permissions were not verified during this static audit, but an active token can authorize every operation included in its assigned Cloudflare scopes. ### Attack Path 1. An attacker obtains read access to the skill package, repository, archive, or a copied build artifact. 2. The attacker reads `scripts/generate_image.py` and extracts `ACCOUNT_ID` and `TOKEN`. 3. The attacker submits authenticated requests to Cloudflare using the exposed bearer token. 4. Cloudflare processes any request permitted by the token's configured scopes. 5. The attacker may continue using the token until it expires or is revoked. ### Impact Assessment If the token remains active, an attacker can consume Cloudflare Workers AI resources under the exposed account and potentially incur service costs, exhaust quotas, or disrupt legitimate usage. If the token has broader permissions than the image-generation operation requires, additional Cloudflare account resources within those scopes may also be exposed. This issue does not directly grant local operating-system privileges. Its external impact is bounded by the bearer token's effective Cloudflare permissions. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions 1. Revoke and rotate the exposed token immediately; deleting it from the current file is insufficient once it has been distributed. 2. Review Cloudflare audit logs for unauthorized requests made with the credential. 3. Store the replacement credential in an environment variable or dedicated secret manager: ```python ACCOUNT_ID = os.environ["CLOUDFLARE_ACCOUNT_ID"] TOKEN = os.environ["CLOUDFLARE_API_TOKEN"] ``` 4. Fail securely with a clear configuration error when either variable is absent. 5. Grant the replacement token only the minimum permissions needed to invoke the required Workers AI model. 6. Add secret scanning to version-control and CI workflows, and purge the credential from repository history and distributed artifacts where feasible. 7. Avoid printing credentials or including them in exceptions, command lines, or logs. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/generate_image.py:23
Finding
Arbitrary Shell Command Injection Through the Image Prompt<![CDATA[ ## Vulnerability Details **File Location**: `scripts/generate_image.py`, lines 23-29 **Vulnerability Type**: OS command injection through unsafe shell interpolation **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 user-controlled `prompt` is serialized as JSON and then inserted inside a shell command delimited by single quotes. JSON serialization escapes JSON metacharacters, but it does not make a value safe for inclusion in POSIX shell syntax. In particular, a single quote contained in the prompt can terminate the shell's quoted `-d` argument. Shell operators appended after that quote can then be interpreted as commands. The call to `subprocess.run(..., shell=True)` causes the constructed string to be parsed by a command shell. Therefore, shell metacharacters introduced through the prompt can alter the command structure rather than remaining inert request data. The prompt is accepted directly from the positional command-line argument: ```python parser.add_argument('prompt', help='Image description/prompt') ``` Consequently, any caller able to influence the prompt can potentially execute arbitrary commands with the privileges of the process running this skill. ### Attack Path 1. An attacker supplies a prompt containing a single quote that terminates the shell-quoted JSON body. 2. The attacker appends shell syntax and an operating-system command, followed by suitable syntax to neutralize the remainder of the generated command. 3. `json.dumps` produces valid JSON but does not neutralize the shell quote. 4. The script interpolates the serialized value into `cmd`. 5. `subprocess.run(cmd, shell=True)` asks the shell to parse the atta ...[truncated 1226 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Remove shell interpretation entirely. Prefer a Python HTTP client and pass the request body as structured JSON. For example: ```python import requests response = requests.post( f"https://api.cloudflare.com/client/v4/accounts/{ACCOUNT_ID}/ai/run/{MODEL}", headers={ "Authorization": f"Bearer {TOKEN}", "Content-Type": "application/json", }, json={"prompt": prompt}, timeout=60, ) response.raise_for_status() data = response.json() ``` If `curl` must be retained, invoke it with an argument array and without `shell=True`: ```python result = subprocess.run( [ "curl", "-sS", "-X", "POST", api_url, "-H", f"Authorization: Bearer {TOKEN}", "-H", "Content-Type: application/json", "-d", json.dumps({"prompt": prompt}), ], check=True, capture_output=True, text=True, ) data = json.loads(result.stdout) ``` Additional hardening should include: 1. Set a request timeout. 2. Use `check=True` or explicit return-code validation. 3. Validate response size and content type before decoding it. 4. Keep credentials out of process command-line arguments where local process listings may expose them; a Python HTTP client is preferable. 5. Add regression tests containing quotes, command separators, substitutions, newlines, and other shell metacharacters. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/generate_image.py:23
Finding
Predictable Shared Temporary File Enables Symlink and Race Attacks<![CDATA[ ## Vulnerability Details **File Location**: `scripts/generate_image.py`, lines 23-32 **Vulnerability Type**: Insecure fixed temporary file and time-of-check/time-of-use race condition **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) with open('/tmp/cf_response.json', 'r') as f: data = json.load(f) ``` ### Technical Analysis Every invocation writes its response to the same predictable path, `/tmp/cf_response.json`. The file is created through shell redirection and is later reopened by path. No secure exclusive creation, ownership verification, file-type verification, permission restriction, locking, or cleanup is performed. In a shared environment, an attacker may create that path as a symbolic link before execution. Shell redirection follows symbolic links, allowing the running process to truncate and overwrite another file that it is authorized to write. The attacker does not inherit additional permissions, but the write occurs with the victim process's permissions. Concurrent legitimate invocations can also overwrite each other's responses between the network request and JSON parsing. An attacker capable of modifying the temporary path may replace its contents with attacker-controlled JSON, causing incorrect processing or controlled error behavior. ### Attack Path A symlink attack can proceed as follows: 1. The attacker predicts the fixed path `/tmp/cf_response.json`. 2. Before the skill runs, the attacker creates that path as a symbolic link to a target file writable by the skill process. 3. The skill executes the shell redirection. 4. The shell follows the link and truncates or overwrites the target with the Cloudflare response. 5. The skill subsequentl ...[truncated 1198 chars]
Remediation
<![CDATA[ ## Remediation Suggestions The preferred fix is to avoid the temporary file and consume the HTTP response directly in memory. A Python HTTP client eliminates both shell redirection and the shared path. If temporary storage is necessary: 1. Create it with Python's `tempfile` module, which uses an unpredictable filename and secure creation semantics. 2. Restrict permissions to the current user. 3. Keep the file descriptor open rather than closing and reopening it by path. 4. Delete the file reliably in a `finally` block. 5. Do not place sensitive responses in a world-readable location. 6. Add locking or isolate files per invocation if concurrent execution is supported. Example: ```python import tempfile with tempfile.NamedTemporaryFile( mode="w+b", prefix="cf_response_", suffix=".json", delete=True, ) as response_file: # Write and read through response_file without using shell redirection. pass ``` Direct in-memory response handling remains safer and simpler than temporary-file management. ]]>
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 stated purpose is a narrowly scoped food-collage generator, but the analyzed behavior reportedly includes generic image generation, missing promised collage/layout logic, undeclared external network access, and hardcoded credentials for a Cloudflare Workers AI API. That combination is dangerous because it conceals materially different behavior from users and reviewers while embedding secrets and enabling undisclosed outbound communications, which can be used for abuse, data exfiltration, or unauthorized third-party API usage.

Context-Inappropriate Capability

High
Confidence
99% confidence
Finding
The file contains hardcoded Cloudflare account credentials and bearer token, which are highly sensitive secrets. If exposed through source control, logs, packaging, or reuse, they enable unauthorized API access, billing abuse, and possible compromise of the associated account resources.

Missing User Warnings

High
Confidence
96% confidence
Finding
Sensitive credentials are embedded and then transmitted to an external service without any user-facing disclosure or consent flow. In the context of a food-collage skill, undisclosed third-party transmission and secret use is more dangerous because it exceeds reasonable user expectations and masks data egress behind an innocuous description.

Description-Behavior Mismatch

High
Confidence
97% confidence
Finding
The implementation is a generic external image-generation client, not a collage generator matching the declared food-collage skill. This mismatch is dangerous because users and reviewers may grant the skill permissions or trust assumptions based on the stated purpose, while the code actually performs broader prompt transmission to a third-party AI service.

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 tool-parameter abuse issue because untrusted prompt data is incorporated into a shell command that invokes an external tool. An attacker can supply crafted input to alter the curl command or execute arbitrary shell commands, leading to code execution, data theft, or filesystem tampering.

Lp3

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding
The skill advertises executable behavior via a Python script and appears to require shell and file-read capabilities, but it does not declare any tool scope or permissions. This creates a least-privilege and review gap: downstream systems or reviewers cannot accurately assess what the skill is allowed to do, increasing the chance of unintended file access or command execution in a broader environment.

Intent-Code Divergence

Medium
Confidence
83% confidence
Finding
The module docstring says this script is a general 'Cloudflare Workers AI Image Generation Script' that 'Generates images' with a model, which conflicts with the skill's documented purpose of generating curated multi-themed food collages. This is an active documentation/code-intent mismatch rather than a mere omission, because the file self-describes a broader generic image generator.

External Transmission

Medium
Category
Data Exfiltration
Content
output_path = f"{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
86% confidence
Finding
The presence of a hardcoded third-party endpoint confirms outbound network capability to a remote service. In this skill context, that increases risk because a seemingly local content-generation skill actually sends content off-platform, which may expose user inputs and expand the attack surface.

External Transmission

Medium
Category
Data Exfiltration
Content
output_path = f"{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
86% confidence
Finding
The presence of a hardcoded third-party endpoint confirms outbound network capability to a remote service. In this skill context, that increases risk because a seemingly local content-generation skill actually sends content off-platform, which may expose user inputs and expand the attack surface.

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 constructs a shell command using attacker-controlled input derived from the prompt and executes it with shell=True. Although json.dumps escapes double quotes for JSON, the payload is embedded inside single quotes in the shell command, so a prompt containing a single quote can break out of the quoted context and trigger command injection.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The script writes API output to /tmp/cf_response.json and writes the generated image to an output file path, but it only informs the user after completion. There is no prior warning or confirmation that local files will be created or overwritten as part of execution.

Intent-Code Divergence

Low
Confidence
94% confidence
Finding
The comment on L82 states the key label is drawn outside the top-left of the image. However, the actual coordinates on L83 use (x - 40, y - 40) while the image occupies a 300x300 area, so the text begins 40 pixels above and left of the image origin and extends into the image region rather than clearly outside it; this contradicts the stated intent of the comment.

Static analysis

No suspicious patterns detected.