Back to skill

Security audit

pick your

Security checks for vulnerabilities and agentic risk

Overview

The skill describes a food collage tool, but the package also ships an undeclared image-generation script with an exposed Cloudflare token and unsafe shell command handling.

Review before installing. The collage script itself is narrow local image processing, but the package should not include an unrelated Cloudflare generator with an embedded token and shell-injection risk. Ask the publisher to remove or rewrite generate_image.py, revoke the exposed token, document any external processing, and run only under least privilege if testing is necessary.

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 Credentials

Content
View full analysis

Vulnerability Details

File Location: scripts/generate_image.py, lines 13–15 and 24–29
Vulnerability Type: Hardcoded cloud credentials
Risk Level: High

Vulnerable Code:

python
# Credentials (Hardcoded as requested)
ACCOUNT_ID = "1e89d3ce76cbfef3b5c340e3984b7a52"
TOKEN = "aCTA2KaKa1n3ayFDL-LPmZ-JgUC0HHgA5Msy18Bk"
MODEL = "@cf/black-forest-labs/flux-1-schnell"

The credential is subsequently placed in an HTTP authorization header:

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'''

Technical Analysis

A Cloudflare account identifier and live-looking bearer token are embedded directly in distributable source code. Any user who can download, inspect, fork, archive, or otherwise access the skill package can retrieve the token without authentication.

Bearer tokens grant access based on possession. The source code imposes no additional access control, host binding, or caller verification. The actual scope of compromise depends on permissions assigned to the token in Cloudflare, but the code proves that it can at least be presented to the Workers AI endpoint for the identified account.

Attack Path

  1. An attacker obtains a copy of the skill package or views its source.
  2. The attacker reads ACCOUNT_ID and TOKEN from scripts/generate_image.py.
  3. The attacker submits independent API requests using the exposed bearer token.
  4. Requests are executed against the associated Cloudflare account within the token's configured permissions.
  5. The attacker may continue using the credential until it expires or is revoked.

Impact Assessment

The confirmed scope includes possible unauthorized use of Cloudflare Workers AI under the affected account. This can consume quot ...[truncated 409 chars]

Remediation
View remediation

Remediation Suggestions

  1. Revoke the exposed token immediately and issue a replacement; removing it from the current file does not invalidate copies in archives or version history.
  2. Store the replacement in a secret manager or protected environment variable, such as CLOUDFLARE_API_TOKEN.
  3. Fail safely when the required secret is absent rather than supplying a fallback credential.
  4. Create a dedicated token restricted to the minimum account, API, and operation scopes required for Workers AI.
  5. Configure expiration and rotation policies for the replacement token.
  6. Remove the credential from all repository history and published artifacts where feasible.
  7. Add automated secret scanning to development and release workflows.
  8. Review Cloudflare audit and billing logs for unauthorized activity involving the exposed token.

Example:

python
ACCOUNT_ID = os.environ["CLOUDFLARE_ACCOUNT_ID"]
TOKEN = os.environ["CLOUDFLARE_API_TOKEN"]

T09 · Insecure Skill Coding Practices

Error
Location
scripts/generate_image.py:19
Finding

Arbitrary Shell Command Injection Through the Image Prompt

Content
View full analysis

Vulnerability Details

File Location: scripts/generate_image.py, lines 19–32
Vulnerability Type: OS command injection
Risk Level: Critical

Vulnerable Code:

python
def generate_image(prompt, output_path=None):
    """Generate an image using Cloudflare Workers AI"""
    
    if output_path is None:
        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'''
    
    subprocess.run(cmd, shell=True)

The prompt is directly controllable through the command-line interface:

python
parser.add_argument('prompt', help='Image description/prompt')

Technical Analysis

The caller-controlled prompt is JSON-encoded and then interpolated into a shell command enclosed with single quotes. JSON encoding protects JSON syntax but does not safely quote data for a POSIX shell. In particular, a single quote in the prompt can terminate the shell's quoted -d argument. Shell control operators placed after that quote can then introduce additional commands.

The completed string is passed to subprocess.run with shell=True, causing the operating system shell to interpret all injected metacharacters. This creates a direct command-execution path rather than merely corrupting the API request.

This issue is reachable whenever an untrusted party can control or influence the prompt passed to generate_image.py or generate_image().

Attack Path

  1. An attacker supplies an image prompt containing a single quote that terminates the shell-quoted JSON payload.
  2. The prompt includes shell syntax that introduces an additional operating-system command.
  3. Python interpolates the prompt into `cmd ...[truncated 1119 chars]
Remediation
View remediation

Remediation Suggestions

  1. Eliminate shell=True; do not build shell commands through string interpolation.
  2. Prefer a maintained HTTP client library and submit the prompt through a structured JSON parameter.
  3. If curl must be used, pass each argument separately and provide the JSON body without invoking a shell.
  4. Enable check=True, capture standard output directly, and handle nonzero exit status and malformed responses.
  5. Apply reasonable prompt-size limits as defense in depth, but do not treat character filtering as the primary command-injection fix.
  6. Execute image generation under an unprivileged, sandboxed account with minimal filesystem and network access.

Example using an argument list:

python
payload = json.dumps({"prompt": prompt})

result = subprocess.run(
    [
        "curl",
        "-sS",
        "--fail-with-body",
        "-X", "POST",
        f"https://api.cloudflare.com/client/v4/accounts/{ACCOUNT_ID}/ai/run/{MODEL}",
        "-H", f"Authorization: Bearer {TOKEN}",
        "-H", "Content-Type: application/json",
        "--data-binary", payload,
    ],
    check=True,
    capture_output=True,
    text=True,
    shell=False,
)

data = json.loads(result.stdout)

An HTTP library is preferable because it avoids subprocess and shell parsing entirely.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/generate_image.py:24
Finding

Unsafe Predictable Temporary Response File

Content
View full analysis

Vulnerability Details

File Location: scripts/generate_image.py, lines 24–35
Vulnerability Type: Predictable temporary file and symlink race
Risk Level: Medium

Vulnerable Code:

python
# 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'''

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. The file is created or truncated through shell redirection rather than through a secure temporary-file API.

In a multi-user or otherwise untrusted local environment, an attacker may pre-create this path as a symbolic link to another file. When the skill executes, shell redirection follows that link and truncates or overwrites the target with the privileges of the skill process. Concurrent legitimate invocations can also overwrite each other's responses, producing corrupted results or failures.

The separate write and read operations additionally create a race window in which another local process can replace or modify the response before Python parses it.

Attack Path

  1. A local attacker predicts the constant path /tmp/cf_response.json.
  2. Before the skill runs, the attacker creates that path as a symbolic link to a file writable by the skill's operating-system identity.
  3. The skill invokes shell redirection using > /tmp/cf_response.json.
  4. The shell follows the symbolic link and truncates or overwrites the linked target with the API response.
  5. Alternatively, an attacker or concurrent invocation replaces the temporary response after curl writes it but before json.load reads it.
  6. The process may overwrite an u ...[truncated 713 chars]
Remediation
View remediation

Remediation Suggestions

  1. Remove the intermediate file and capture the HTTP response directly in memory.
  2. When using subprocess.run, use capture_output=True and parse stdout.
  3. If a temporary file is operationally necessary, create it with Python's tempfile.NamedTemporaryFile or TemporaryDirectory.
  4. Keep the temporary file descriptor under process control, use restrictive permissions, and delete the file in a finally block.
  5. Do not use predictable names in a shared temporary directory.
  6. Prevent cross-request state by giving every invocation an isolated response buffer.
  7. Run the process with least privilege to limit the files that could be affected by a local filesystem attack.

Capturing the response directly also resolves the race:

python
result = subprocess.run(
    curl_arguments,
    check=True,
    capture_output=True,
    text=True,
    shell=False,
)
data = json.loads(result.stdout)
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 (14)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The described behavior materially conflicts with the reported implementation: instead of a constrained food-collage generator, the skill reportedly performs arbitrary image generation and uses an external Cloudflare AI API with hardcoded credentials that are not disclosed in the skill metadata. This combination is dangerous because it can mislead users and reviewers about what will execute, enable unauthorized external data transfer, and expose embedded secrets for abuse.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The implementation does not perform the advertised food-collage assembly and instead exposes a general-purpose external image generation capability. This capability mismatch is dangerous because users or higher-level agents may trust the skill's narrow stated purpose, while the code can generate arbitrary content and send arbitrary prompts to a third-party model.

Content

No source excerpt is available for this finding.

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
98% confidence
Finding

This is a classic tool-parameter abuse path: attacker-controlled input flows into a shell command and is executed with shell=True. In an agent skill context, this is especially dangerous because prompts may be indirectly influenced by users or chained tools, enabling arbitrary OS command execution beyond the skill's stated purpose.

Content

Scanner excerpt · scripts/generate_image.py (reported line 30)May include surrounding context.

python
-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)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding

The skill advertises executable behavior via a shell command and implied file access, but it declares no explicit tool scope or permissions. That makes the skill's operational capabilities opaque to reviewers and policy enforcement, increasing the chance of unintended command execution or broader access than users expect.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The documentation points users to a wings-collage script that does not match the stated skill purpose, indicating possible copy-paste drift or substitution of unrelated code. In security terms, inconsistent references reduce trustworthiness and can hide execution of unexpected scripts or workflows that were not reviewed for the advertised function.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

The module documentation explicitly describes a Cloudflare AI image-generation script, conflicting with the skill metadata that promises themed food collages. This discrepancy is a security concern because deceptive or inconsistent documentation can hide broader capabilities from reviewers and users, reducing informed consent and oversight.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
99% confidence
Finding

The script contains hardcoded Cloudflare account credentials directly in source code. Hardcoded secrets are dangerous because anyone with code access can reuse the token for unauthorized API access, billing abuse, or lateral compromise of related services.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The skill exposes a broad external AI image-generation function that is unnecessary for the declared collage-making workflow. In context, that increases risk because the skill can be repurposed to create arbitrary content or process unrelated prompts under the guise of a narrowly scoped food-collage tool.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
90% confidence
Finding

The code transmits data to an external Cloudflare endpoint, including the user's prompt and an authorization token. External transmission is security-relevant here because the skill is presented as a narrow collage tool, so the undisclosed network egress and third-party processing expand the trust boundary unexpectedly.

Content

Scanner excerpt · scripts/generate_image.py (reported line 25)May include surrounding context.

python
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'''

External Transmission

Medium
Category
Data Exfiltration
Confidence
90% confidence
Finding

The code transmits data to an external Cloudflare endpoint, including the user's prompt and an authorization token. External transmission is security-relevant here because the skill is presented as a narrow collage tool, so the undisclosed network egress and third-party processing expand the trust boundary unexpectedly.

Content

Scanner excerpt · scripts/generate_image.py (reported line 25)May include surrounding context.

python
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'''

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

User-supplied prompts are transmitted to Cloudflare's API without any disclosure, consent, or indication of external processing. Prompts may contain sensitive or proprietary data, and the skill context makes this more dangerous because users would reasonably expect a local food-collage utility rather than third-party AI inference.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
98% confidence
Finding

The script builds a shell command using untrusted user input (prompt) and executes it with subprocess.run(..., shell=True). Although json.dumps escapes JSON content, it does not make shell interpolation safe; shell metacharacters embedded in the prompt can break quoting and lead to command injection, potentially allowing arbitrary command execution on the host.

Content

Scanner excerpt · scripts/generate_image.py (reported line 30)May include surrounding context.

python
-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)

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The implementation generates collages for burgers, pizzas, sushi, salads, and desserts, and builds image paths under theme-specific directories for those categories. This materially differs from the file's apparent purpose as a wings collage generator, indicating a mismatch between documented/intended purpose and actual behavior.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The code writes outputs such as PICK YOUR BURGER/PIZZA/SUSHI/SALAD/DESSERT while using names and paths containing 'wings'. That is not merely incomplete documentation; the naming actively suggests wing-focused behavior while the rendered results are for unrelated food categories.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.