Back to skill

Security audit

TensorLab Image

Security checks for vulnerabilities and agentic risk

Overview

This image-generation skill mostly matches its stated purpose, but it needs review because it uploads user images to TensorsLab, gives unsafe watermark and face-replacement workflows, and has downloader validation flaws.

Install only if you are comfortable sending prompts and any source images to TensorsLab. Avoid using it on confidential or personal images unless you have approval, and do not use the watermark-removal or face-replacement workflows except for clearly authorized, consensual cases. The bundled downloader should be hardened before routine use in sensitive environments by validating task IDs, restricting download hosts, disabling unsafe redirects, and limiting download size.

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/tensorslab_image.py:169
Finding
API-Controlled Task Identifier Allows Output Path Traversal<![CDATA[ ## Vulnerability Details **File Location**: `scripts/tensorslab_image.py`, lines 169-173 and 278-280 **Vulnerability Type**: Path traversal through an untrusted filename component **Risk Level**: High ### Vulnerable Code ```python if result.get("code") == 1000: task_id = result.get("data", {}).get("taskid") logger.info(f"✅ Task created successfully! Task ID: {task_id}") return task_id ``` ```python for i, url in enumerate(urls): filename = f"{task_id}_{i}" output_path = output_dir / filename ``` The derived path is subsequently passed to `download_image()`, where the response is written to disk: ```python final_path = output_path.with_suffix(ext) with open(final_path, 'wb') as f: f.write(response.content) ``` ### Technical Analysis The task identifier is obtained directly from the remote API response and used as part of a local filesystem path without validation or normalization. Python's `pathlib` permits traversal components such as `../` in joined paths. An absolute path component can also supersede the preceding output directory. Consequently, a malicious or compromised API could return a task identifier containing traversal or absolute-path syntax. The resulting destination could escape the configured output directory. The application opens the destination in `wb` mode, which creates a new file or truncates an existing file. The `_0` index and remotely influenced extension constrain the exact resulting filename, but they do not guarantee that it remains inside the intended directory. ### Attack Path 1. A user invokes the image-generation client. 2. The client authenticates to the remote API and submits a generation request. 3. A compromised or malicious API response returns a task ID containing traversal components or an absolute path. 4. The client accepts the task ID without validation. 5. The client polls until the API reports that the task is complete. 6. It constructs `output_dir / f"{task_id}_{i}"`. 7. Th ...[truncated 696 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Validate task IDs using a strict allowlist, such as `^[A-Za-z0-9_-]{1,128}$`. - Do not use remotely supplied identifiers directly as local filenames. Generate a local UUID or random filename and retain the task ID only as metadata. - Resolve both the output directory and destination, then verify containment before writing: ```python base = output_dir.resolve() destination = (base / safe_filename).resolve() if destination.parent != base: raise TensorsLabAPIError("Unsafe output path") ``` - If nested output directories are intentionally supported, use `destination.is_relative_to(base)` on supported Python versions. - Open newly created files with exclusive creation where overwriting is unnecessary. - Add tests covering `../`, absolute paths, Windows drive paths, path separators, empty IDs, and excessively long IDs. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/tensorslab_image.py:75
Finding
Unvalidated API-Controlled Download URLs Enable Server-Side Request Forgery from the Client Host<![CDATA[ ## Vulnerability Details **File Location**: `scripts/tensorslab_image.py`, lines 75-78 and 271-285 **Vulnerability Type**: SSRF through unvalidated remote download URLs **Risk Level**: Medium ### Vulnerable Code ```python def download_image(url: str, output_path: Path) -> Path: """Download an image from URL to local path.""" try: response = _SESSION.get(url, timeout=30) response.raise_for_status() ``` ```python if status == 3: # Completed logger.info(f"\n✅ Task completed!") urls = task_data.get("url", []) if not urls: logger.warning("⚠️ No images returned") return downloaded_files for i, url in enumerate(urls): filename = f"{task_id}_{i}" output_path = output_dir / filename logger.info(f"📥 Downloading image {i+1}/{len(urls)}") final_path = download_image(url, output_path) if final_path: downloaded_files.append(str(final_path)) ``` ### Technical Analysis The status API controls the contents of the `url` array. Each supplied URL is passed directly to `requests.Session.get()` without validating: - The URL scheme - The destination hostname - The resolved IP address - The destination port - Embedded credentials - Redirect destinations The `requests` library follows redirects by default. Therefore, validating only an initial URL in a future partial fix would remain insufficient unless each redirect target is also checked. A malicious or compromised API could direct the client to loopback, private-network, link-local, or cloud metadata addresses. The request would originate from the host running the skill, potentially giving it network access unavailable to an external attacker. ### Attack Path 1. A user creates an image-generation task. 2. The client repeatedly queries the task-status endpoint. 3. A compromised API returns status `3` and places an internal-service URL in the `url` array. 4. Alternatively, it provides a public URL that ...[truncated 841 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Permit downloads only from an explicit allowlist of HTTPS hosts operated by TensorsLab or its designated image CDN. - Reject non-HTTPS schemes, embedded credentials, unexpected ports, malformed URLs, and IP-literal hosts unless explicitly required. - Resolve the hostname before connecting and reject loopback, private, link-local, multicast, reserved, and unspecified IP ranges for both IPv4 and IPv6. - Disable automatic redirects with `allow_redirects=False`, or validate every redirect target before following it. - Account for DNS rebinding by ensuring the validated address is the address actually used for the connection. - Apply outbound firewall or network-policy restrictions so the process cannot reach metadata, management, or internal service ranges. - Consider requiring cryptographically signed download URLs with an expected host and short expiration period. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/tensorslab_image.py:75
Finding
Unbounded and Unverified Image Downloads Permit Memory and Disk Exhaustion<![CDATA[ ## Vulnerability Details **File Location**: `scripts/tensorslab_image.py`, lines 75-93 **Vulnerability Type**: Unrestricted resource consumption and missing content validation **Risk Level**: Medium ### Vulnerable Code ```python response = _SESSION.get(url, timeout=30) response.raise_for_status() content_type = response.headers.get('content-type', '').split(';')[0].strip() ext = mimetypes.guess_extension(content_type) if ext == '.jpe': ext = '.jpg' if not ext: ext = Path(urlparse(url).path).suffix if not ext or len(ext) > 6: ext = '.png' final_path = output_path.with_suffix(ext) with open(final_path, 'wb') as f: f.write(response.content) return final_path ``` ### Technical Analysis The application accesses `response.content`, causing the complete response body to be buffered in memory before it is written. It imposes no maximum response size and does not stream the body in bounded chunks. The code also derives the file extension from the server-provided `Content-Type` header or URL path but never verifies that the response is a valid image. A server can therefore return arbitrary bytes while declaring an image media type. The 30-second timeout does not provide an effective size limit because a sufficiently fast endpoint can transfer a very large response within that period. ### Attack Path 1. The image-status response supplies an attacker-controlled or compromised download URL. 2. The client requests the URL without imposing a response-size limit. 3. The endpoint returns a very large body or arbitrary non-image content. 4. `requests` buffers the full body through `response.content`, consuming process memory. 5. The application writes the complete body to disk without a storage quota or image validation. 6. Repeated URLs or repeated executions amplify memory and disk consumption. ### Impact Assessment A malicious download endpoint could cause high memory consumption, process termination, system instability, or exhaustion o ...[truncated 402 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Use streaming requests: ```python with _SESSION.get(url, stream=True, timeout=(5, 30)) as response: response.raise_for_status() ``` - Reject responses whose declared `Content-Length` exceeds a defined image-size limit. - Track the actual bytes received and abort if the limit is exceeded, because `Content-Length` can be absent or false. - Write bounded chunks to a temporary file rather than buffering the full response in memory. - Require an allowlisted image media type, such as `image/png`, `image/jpeg`, or `image/webp`. - Verify the downloaded structure using a maintained image-decoding library before moving it to the final destination. - Delete partial files after timeouts, validation failures, and size-limit violations. - Enforce per-file, per-task, and output-directory storage quotas. - Generate the final extension from successfully detected image content rather than trusting the response header or URL suffix. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (16)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The skill description overstates implemented functionality, including sensitive editing use cases like watermark removal and face replacement, while the actual behavior apparently does not fully implement them and only partially supports prompt enhancement. This mismatch is dangerous because users and orchestrators may trust the skill to perform controlled, documented actions when actual behavior is incomplete or different, undermining informed consent, policy enforcement, and safe routing decisions.

Ssd 4

High
Confidence
97% confidence
Finding
This scenario incrementally guides the agent through creating an undetectable face swap under the guise of normal image editing, including blending, lighting, and realism instructions that directly optimize deception. In context, this is a substantive safety vulnerability because the workflow lowers the barrier to producing convincing manipulated identity content.

Credential Access

High
Category
Privilege Escalation
Content
def get_api_key() -> str:
    """Get API key from environment variable."""
    api_key = os.environ.get("TENSORSLAB_API_KEY")
    if not api_key:
        raise TensorsLabAPIError(
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Lp3

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding
The skill documents capabilities that require environment-variable access, shell execution, and outbound network use, but it does not declare any tool scope or permissions. This creates an authorization and transparency gap: a host agent may expose broader capabilities than users expect, increasing the chance of unintended command execution, secret access, or data transfer during image-processing workflows.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The file includes mandated Chinese-language setup and completion/error messages, and example user requests are also presented in Chinese, but there is no indication that the skill is region-specific or that users may choose another language. This creates a locale policy issue because the skill appears to impose a specific language without opt-in.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
The skill instructs users to provide local image files and prompts for processing by TensorsLab, but it does not warn that this content may be uploaded to an external third-party API. This is a real privacy and data-handling issue because users may unknowingly send sensitive images, metadata, or confidential prompts off-device, which is especially risky in an image-editing context involving personal photos.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
This markdown file describes a Delete Task endpoint that removes tasks, but it provides no warning about the destructive nature of the operation or its impact on user data. Under the markdown-specific missing-warning criteria, destructive behavior that could affect user data or system integrity should be disclosed to users.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The watermark-removal scenario explicitly instructs the agent to remove ownership indicators and preserve seamless realism, which facilitates copyright evasion, provenance stripping, and deceptive reuse of images. In this skill context, the danger is elevated because the document provides operational prompts and commands, not merely abstract discussion, and it lacks any policy guardrails or lawful-use limitations.

Ssd 4

Medium
Confidence
95% confidence
Finding
The watermark-removal section provides a procedural workflow and optimized prompt for stripping ownership/provenance markers while preserving realism, which can help users conceal attribution and redistribute content deceptively. The risk is heightened by the concrete command example and absence of guardrails limiting use to authorized restoration scenarios.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The face-replacement scenario provides detailed instructions for identity manipulation while emphasizing natural, undetectable results, which can enable impersonation, harassment, fraud, and non-consensual deepfake creation. The skill context makes this more dangerous because it operationalizes multi-image face swapping with target selection guidance and no consent, privacy, or anti-deception safeguards.

Description-Behavior Mismatch

Medium
Confidence
97% confidence
Finding
The manifest claims support for advanced editing such as avatar generation, watermark removal, object erasure, face replacement, and general image editing. In this file, the documented and implemented functionality is limited to text-to-image and image-to-image submission, task polling, and downloading results, with no code paths for those specialized editing operations.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The script uploads local image files or a provided image URL to a third-party remote API, but it gives no explicit user-facing warning at the point of use about external transmission. In a skill context, this can cause inadvertent disclosure of sensitive local images, especially if users assume processing is local or do not realize source content leaves their environment.

Natural-Language Policy Violations

Low
Confidence
96% confidence
Finding
The documented user message is written only in Chinese, which imposes a specific language on users without offering a language choice or explaining a region-specific requirement. This is a natural-language policy issue because the file presents a fixed locale-specific message without opt-in.

Natural-Language Policy Violations

Low
Confidence
76% confidence
Finding
The file uses Chinese trigger examples and Chinese keyword/style extraction guidance as part of the invocation logic, but it does not state that language selection is optional or that the skill is intentionally limited to Chinese users. This can be a natural-language policy issue when a skill appears to force or assume a specific language without opt-in.

Missing User Warnings

Low
Confidence
76% confidence
Finding
The script creates an output directory and later saves downloaded images to disk. Although output paths are configurable and implied by the tool's behavior, there is no prominent warning or disclosure in the main description that files will be created locally, which this rule treats as a missing warning for file writes.

Description-Behavior Mismatch

Low
Confidence
84% confidence
Finding
The manifest presents automatic prompt enhancement as a feature of the skill, but this script only sets `prompt_extend` when `model == "zimage"`. For the default `seedreamv4` and `seedreamv45` paths, no prompt-enhancement behavior is implemented, so the advertised capability is not generally reflected in code.

Static analysis

No suspicious patterns detected.