T09 · Insecure Skill Coding Practices
- Location
scripts/generate_image.py:13- Finding
Hardcoded Cloudflare API Credential in Source Code
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
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.
scripts/generate_image.py:13Hardcoded Cloudflare API Credential in Source Code
scripts/generate_image.py:23Arbitrary Shell Command Injection Through the Image Prompt
scripts/generate_image.py:23Predictable Shared Temporary File Enables Symlink and Race Attacks
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.
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.
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.
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.
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.
-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)
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.
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.
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.
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'''
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.
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'''
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.
-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)
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.
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.