Back to skill

Security audit

Cheapest Image

Security checks for vulnerabilities and agentic risk

Overview

This is a coherent EvoLink image-generation skill, but it needs Review because it downloads API-returned URLs without destination or size limits.

Install only if you are comfortable sending image prompts to EvoLink with your API key and saving generated files locally. Avoid sensitive prompts, protect the EVOLINK_API_KEY value, and be aware that the current download logic trusts the provider-returned result URL and may download large or unexpected content.

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

Warning
Location
scripts/generate.py:41
Finding
Unvalidated API-Supplied Image URL in Python Implementation<![CDATA[ ## Vulnerability Details **File Location**: `scripts/generate.py`, lines 41-49 and 127-131 **Vulnerability Type**: Server-Side Request Forgery and Unbounded Response Download **Risk Level**: Medium ### Vulnerable Code ```python def _download(url: str, out_file: str, timeout_s: int = 120): req = urllib.request.Request(url, method="GET", headers={"User-Agent": _UA}) try: with urllib.request.urlopen(req, timeout=timeout_s) as resp: content = resp.read() except Exception as e: raise RuntimeError(f"Failed to download result: {e}") from None with open(out_file, "wb") as f: f.write(content) ``` The API-provided URL is passed directly to the download function: ```python url = results[0] ext = _ext_from_url(url) if not args.out: out_file = os.path.abspath(_default_out_file(ext)) _download(url, out_file=out_file) ``` ### Technical Analysis The image result URL is obtained from the Evolink task response and passed directly to `urllib.request.urlopen` without validating its scheme, hostname, port, resolved address, or redirect destination. Although the initial API endpoint is fixed to `https://api.evolink.ai/v1`, the API response controls the destination of the subsequent request. If the service, account, or response channel is compromised, a crafted result URL could cause the process to request an internal service, loopback address, link-local endpoint, or another destination accessible from the host. Python's URL handler may also follow redirects. Validating only the initial URL would therefore be insufficient unless every redirect target is independently checked. The response is read in full through `resp.read()` before being written. No `Content-Length`, content type, image signature, or maximum-byte limit is enforced. A large or endless response could cause excessive memory consumption, followed by disk consumption when saved. ### Attack Path 1. A user invokes the Skill to generate an image. ...[truncated 1146 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Accept only `https` result URLs. 2. Maintain an explicit allowlist of documented Evolink image CDN hostnames. 3. Reject URLs containing embedded credentials, unexpected ports, malformed hostnames, or unsupported schemes. 4. Resolve the hostname and reject loopback, private, link-local, multicast, reserved, and unspecified addresses for both IPv4 and IPv6. 5. Disable automatic redirects or validate the scheme, hostname, port, and resolved address of every redirect target. 6. Stream the response in bounded chunks instead of calling `resp.read()` without a limit. 7. Enforce a strict maximum image size and reject responses whose declared or observed size exceeds it. 8. Require an approved image content type and validate the downloaded file's image signature before retaining it. 9. Delete partial output files when validation or downloading fails. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
references/powershell.md:102
Finding
Unvalidated API-Supplied Image URL in PowerShell Fallback<![CDATA[ ## Vulnerability Details **File Location**: `references/powershell.md`, lines 102-116 **Vulnerability Type**: Server-Side Request Forgery and Unbounded File Download **Risk Level**: Medium ### Vulnerable Code ```powershell $url = $results[0] # Infer extension from URL if (-not $Out) { $urlPath = ([System.Uri]$url).AbsolutePath $ext = [System.IO.Path]::GetExtension($urlPath).ToLower() if ($ext -notin ".png", ".jpg", ".jpeg", ".webp") { $ext = ".webp" } $ts = Get-Date -Format "yyyyMMdd-HHmmss-fff" $Out = [System.IO.Path]::GetFullPath("evolink-$ts$ext") } try { Invoke-WebRequest -Uri $url -OutFile $Out -TimeoutSec 120 -UserAgent "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" } ``` ### Technical Analysis The PowerShell fallback trusts the first URL returned by the task API and supplies it directly to `Invoke-WebRequest`. Parsing the path to select a filename extension does not validate the URL's scheme, destination host, resolved IP address, port, or redirect chain. Consequently, control of the task response can be converted into a request from the Windows host to an attacker-selected endpoint. The request inherits the host's network reachability and may reach loopback or private-network services. The command writes the response to disk without enforcing an application-level maximum byte count or validating that the content is actually an image. `TimeoutSec` limits elapsed request time but does not provide a reliable response-size limit. ### Attack Path 1. The PowerShell fallback submits an image-generation request and polls the task endpoint. 2. A compromised or malformed task response supplies an attacker-controlled value in `$results[0]`. 3. The value is assigned to `$url` without destination validation. 4. `Invoke-WebRequest` requests the URL from the local Windows host and may follow redirects. 5. The response is written to disk regardless of its actual type or size. ### Impact Assessment The flaw c ...[truncated 490 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Parse the result with `System.Uri` and require an absolute `https` URI. 2. Enforce an allowlist of documented Evolink image CDN hostnames and approved ports. 3. Resolve the hostname and reject private, loopback, link-local, multicast, reserved, and unspecified addresses. 4. Prevent redirects or validate every redirect destination against the same restrictions. 5. Check `Content-Type` and permit only expected image media types. 6. Stream the download while tracking total bytes and abort when a conservative maximum image size is exceeded. 7. Validate the final file's image signature rather than relying on the URL extension. 8. Remove incomplete files if the download or validation fails. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
references/curl_heredoc.md:43
Finding
Unvalidated API-Supplied Image URL in curl Fallback<![CDATA[ ## Vulnerability Details **File Location**: `references/curl_heredoc.md`, lines 43-44 **Vulnerability Type**: Server-Side Request Forgery and Unbounded File Download **Risk Level**: Medium ### Vulnerable Code ```bash URL=$(echo "$TASK" | grep -o '"results":\["[^"]*"\]' | grep -o 'https://[^"]*') curl -s -o "$OUT_FILE" "$URL" ``` ### Technical Analysis The shell fallback extracts an HTTPS-looking string from the API response and supplies it directly to `curl`. The textual `https://` match restricts the apparent scheme but does not validate the hostname, port, resolved address, or ownership of the destination. If the task response can be controlled, the URL may refer to an HTTPS service on a loopback, private, link-local, or otherwise sensitive address reachable by the host. The code also does not enforce a maximum response size or validate that the returned content is an image. This specific command does not use `-L`, so it ordinarily does not follow redirects in the shown download path. Nevertheless, the initial destination remains entirely controlled by the task response. ### Attack Path 1. The fallback submits an image request and polls the Evolink task endpoint. 2. A compromised or defective response includes an attacker-selected HTTPS URL in the `results` array. 3. The `grep` pipeline extracts the URL without validating its destination. 4. `curl` requests the destination using the host's network reachability. 5. Any returned body is written to `$OUT_FILE` without a content or size check. ### Impact Assessment An attacker controlling the result could induce blind HTTPS requests to reachable internal services. The usefulness of this behavior depends on whether a target internal service supports HTTPS and whether the attacker can infer effects through timing or state changes. A large response could consume local disk space and cause denial of service. The Evolink authorization header is not attached to this download request, and the fetche ...[truncated 100 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Parse the URL with a reliable URL parser instead of regular expressions. 2. Require HTTPS and enforce an explicit allowlist of documented image CDN hostnames and ports. 3. Resolve and reject loopback, private, link-local, reserved, multicast, and unspecified addresses. 4. Keep redirects disabled unless every redirect destination is validated. 5. Configure a strict download-size limit, such as curl's `--max-filesize`, while also verifying the actual downloaded byte count. 6. Inspect response headers and require an approved image content type. 7. Validate the downloaded file's image signature and delete invalid or partial output files. 8. Use `curl --fail-with-body` or equivalent error handling so HTTP failures are not retained as image files. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (7)

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill requires both environment access to read EVOLINK_API_KEY and network access to call the EvoLink API, but it does not explicitly declare a tool scope such as permissions or allowed-tools. That omission weakens least-privilege controls and makes it harder for a host agent or reviewer to understand and constrain what the skill is allowed to access before execution.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The example instructs users to send their API key and prompt content to a third-party service and later write the returned image to disk, but it does not clearly warn about those privacy and data-handling consequences. In a skill context, omission of this disclosure can cause users to unknowingly transmit sensitive prompts or credentials and persist generated content locally.

External Transmission

Medium
Category
Data Exfiltration
Content
API_KEY="<API_KEY>"
OUT_FILE="<OUTPUT_FILE>"

RESP=$(curl -s -X POST "https://api.evolink.ai/v1/images/generations" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d @- <<'EVOLINK_END'
Confidence
60% 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
from urllib.parse import urlparse


API_BASE = "https://api.evolink.ai/v1"
_UA = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36"
Confidence
60% 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
from urllib.parse import urlparse


API_BASE = "https://api.evolink.ai/v1"
_UA = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36"
Confidence
60% 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
from urllib.parse import urlparse


API_BASE = "https://api.evolink.ai/v1"
_UA = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36"
Confidence
60% 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
from urllib.parse import urlparse


API_BASE = "https://api.evolink.ai/v1"
_UA = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36"
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Static analysis

No suspicious patterns detected.