Back to skill

Security audit

Tensorslab Image

Security checks for vulnerabilities and agentic risk

Overview

This image-generation skill is mostly coherent, but it needs review because it uploads user images/prompts to an external service and has local download/write safety gaps.

Install only if you are comfortable sending prompts and any selected images to TensorsLab for processing. Avoid confidential, regulated, copyrighted, or identity-sensitive images unless you have reviewed the provider terms and have permission to edit them. Treat watermark removal and face replacement requests carefully, and prefer running the script in a limited working directory until filename and download validation are improved.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (3)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/tensorslab_image.py:76
Finding
Unvalidated API-Provided URLs Permit Arbitrary Network Requests and Unbounded Downloads<![CDATA[ ## Vulnerability Details **File Location**: `scripts/tensorslab_image.py:76-99` and `scripts/tensorslab_image.py:267-275` **Vulnerability Type**: Unvalidated remote URL retrieval / client-side SSRF **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() 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 except Exception as e: logger.warning(f"Warning: Failed to download image from {url}: {e}") return None ``` The URL is obtained from API-controlled task data and passed directly to the download function: ```python 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 application trusts image URLs returned by the remote task-status API. It does not validate: - The URL scheme. - The destination hostname or resolved IP address. - Whether the destination belongs to an approved image-storage domain. - Redirect destinations. - Whether the resolved address is loopback, private, link-local, or otherwise internal. - The response body size. - Whether the response is actually a valid image. The `Content-Type` header is used only to determine the output extension. I ...[truncated 1637 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Permit only `https` URLs. 2. Maintain an explicit allowlist of documented image-storage hostnames. 3. Resolve the hostname before connecting and reject loopback, private, link-local, multicast, reserved, and unspecified addresses. 4. Disable automatic redirects or validate the scheme, hostname, and resolved address of every redirect target. 5. Download with `stream=True` and enforce a strict maximum response size. 6. Require an expected image MIME type and verify the downloaded bytes with an image parser or file-signature check. 7. Apply connection and read timeouts separately. 8. Delete partial files when validation or download fails. Example defensive structure: ```python response = _SESSION.get( validated_url, stream=True, allow_redirects=False, timeout=(5, 30), ) response.raise_for_status() if response.headers.get("Content-Type", "").split(";")[0] not in ALLOWED_IMAGE_TYPES: raise TensorsLabAPIError("Unexpected download content type") total = 0 with open(final_path, "xb") as output: for chunk in response.iter_content(chunk_size=64 * 1024): total += len(chunk) if total > MAX_IMAGE_BYTES: raise TensorsLabAPIError("Downloaded image exceeds size limit") output.write(chunk) ``` ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/tensorslab_image.py:178
Finding
API-Controlled Task Identifier Is Used in an Output Path Without Sanitization<![CDATA[ ## Vulnerability Details **File Location**: `scripts/tensorslab_image.py:178-181`, `scripts/tensorslab_image.py:267-275`, and `scripts/tensorslab_image.py:90-95` **Vulnerability Type**: Path traversal / arbitrary file write **Risk Level**: Medium ### Vulnerable Code The task identifier is accepted directly from the remote API: ```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 ``` It is then incorporated into a filesystem path without validation: ```python 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)) ``` The resulting path is opened for writing: ```python final_path = output_path.with_suffix(ext) with open(final_path, 'wb') as f: f.write(response.content) ``` ### Technical Analysis `task_id` crosses a remote trust boundary but is treated as a safe filename component. Python's `pathlib` join operation does not prevent path separators or `..` components from escaping the intended output directory. For example, a malicious identifier containing traversal components can cause `output_dir / filename` to resolve outside `output_dir`. The subsequent `with_suffix()` call changes the suffix but does not remove traversal components. No canonicalization or containment check is performed before opening the destination in write mode. Exploitation depends on a malicious or compromised TensorsLab API returning a crafted task identifier. A successful write also requires the destination parent directory to exist and the current user to possess write permission. ### Attack Path 1. The user invokes image generation. 2. The generation endpoint returns a successful response containing a crafted `tas ...[truncated 1079 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not derive local filenames directly from remote task identifiers. 2. Generate local names with `uuid.uuid4()` or another locally controlled random identifier. 3. If the task identifier must remain visible, restrict it to a conservative allowlist such as `[A-Za-z0-9_-]+`. 4. Reject empty identifiers, path separators, dot components, control characters, and identifiers exceeding a short maximum length. 5. Resolve the final destination and verify that it remains under the resolved output directory. 6. Use exclusive creation mode (`xb`) when overwriting existing files is unnecessary. 7. Consider setting restrictive file permissions for downloaded content. Example containment validation: ```python import re import uuid if not isinstance(task_id, str) or not re.fullmatch(r"[A-Za-z0-9_-]{1,128}", task_id): safe_name = uuid.uuid4().hex else: safe_name = task_id base = output_dir.resolve() destination = (base / f"{safe_name}_{i}{ext}").resolve() if base not in destination.parents: raise TensorsLabAPIError("Unsafe output path") ``` The extension must also come from a small explicit allowlist rather than directly from an untrusted URL. ]]>

T08 · Insecure Dependencies

Note
Location
SKILL.md:116
Finding
Dependency Installation Instructions Use an Unpinned Package<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:116-120` **Vulnerability Type**: Unpinned third-party dependency / supply-chain exposure **Risk Level**: Low ### Vulnerable Code ```bash # Text shown in the dependency setup section: pip install requests ``` ### Technical Analysis The documented setup command installs the latest version of `requests` selected by the user's configured Python package index at installation time. No exact version, lock file, package hash, or trusted-index requirement is specified. This creates a mutable and non-reproducible dependency installation process. The audited skill can therefore execute against dependency code that differs from the code available when the skill was reviewed. The package name is correctly spelled and refers to a widely used package, so there is no evidence of deliberate typosquatting or dependency confusion in the project. The risk arises from the absence of version and integrity controls rather than from a currently identified malicious package. ### Attack Path 1. A user follows the setup documentation and runs `pip install requests`. 2. `pip` resolves the package using the user's configured package index and mirror settings. 3. A compromised upstream release, compromised mirror, or maliciously configured index supplies untrusted package content. 4. Package installation or later import executes the supplied code with the privileges of the user running the command. ### Impact Assessment If the resolved package source is compromised, dependency code can execute with the full privileges of the current user. This could expose the TensorsLab API key, prompts, uploaded images, downloaded files, and other data accessible to that user. The practical likelihood is reduced because `requests` is a well-established dependency and no malicious version is identified in the audited files. The primary confirmed weakness is lack of reproducibility and integrity verification. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions 1. Add a dependency file containing an audited, exact version. 2. Record cryptographic hashes and install with hash verification. 3. Use an approved package index over HTTPS. 4. Review and update dependency pins through a controlled maintenance process. 5. Run dependency vulnerability scanning as part of release checks. 6. Prefer `python -m pip` so the package is installed into the intended interpreter environment. Example installation command: ```bash python -m pip install --require-hashes -r requirements.txt ``` Example requirement structure: ```text requests==<audited-version> \ --hash=sha256:<verified-distribution-hash> ``` All transitive dependencies should also be pinned and hash-verified in the lock or requirements file. ]]>
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 (12)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The description overstates the skill's functionality. The implemented code clearly supports generating images from text, optional image-to-image generation via local files or image URLs, polling for completion, and saving outputs locally. It also correctly relies on the TENSORSLAB_API_KEY environment variable. However, there is no code for dedicated avatar generation, watermark removal, object erasure, face replacement, or broader editing workflows. Those would require separate parameters, endpoints, or processing logic not present here. The only partial match to 'automatic prompt enhancement' is a model-specific prompt_extend flag for zimage, which does not justify the broad advanced-editing claims. This is a description-to-behavior mismatch due to significant declared capabilities not actually implemented.

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
90% confidence
Finding
The skill declares operational behavior that requires environment access, network access, and shell execution, but it does not define any tool scope or permission boundaries. This can cause an agent runtime to grant broader capabilities than users expect, increasing the chance of unintended secret access, external data transmission, or command execution.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The skill instructs users to provide prompts and local source images to an external API, but it does not clearly warn that this content leaves the local environment. Users may unknowingly upload sensitive images, personal data, or confidential prompts to a third-party service, creating privacy and data-governance risk.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
The file instructs the agent to display a fixed Chinese message when the API key is missing, and additional required user-facing text elsewhere is also Chinese. This imposes a specific language on users without opt-in or any stated region-specific justification, which matches the language/locale policy violation criteria.

Natural-Language Policy Violations

Medium
Confidence
93% confidence
Finding
The error-handling table and completion message specify fixed Chinese-language strings for user communication. Since the file does not offer language selection or explain a necessary locale constraint, these hardcoded templates violate the requirement not to force a specific language without user opt-in.

Missing User Warnings

Medium
Confidence
84% confidence
Finding
This markdown file documents authenticated API requests and later describes sending prompts, source images, and image URLs to a remote third-party service, but it does not warn users that their content and credentials are transmitted off-system. For markdown files, omission of warnings about behaviors affecting privacy or user data is in scope.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The markdown describes a delete endpoint that removes image tasks, but it provides no caution that the action is destructive or may be irreversible. For markdown files, destructive behaviors that can affect user data should be accompanied by an explicit warning.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The documented scenarios explicitly support watermark removal, object erasure, and face replacement without any warnings to verify ownership, consent, or legal authorization before editing images. In this skill context, those capabilities materially increase misuse risk because they can facilitate copyright circumvention, deceptive media creation, and unauthorized biometric/identity manipulation.

Missing User Warnings

Low
Confidence
86% confidence
Finding
The skill documents automatic local file saving but does not clearly warn users that generated outputs will be written to disk. This can create privacy, storage, and operational issues, especially in shared workspaces or environments handling sensitive generated content.

Natural-Language Policy Violations

Low
Confidence
96% confidence
Finding
The file specifies a user message entirely in Chinese for insufficient credits, which imposes a specific language in natural-language content. Because no opt-in, fallback, or justification for a Chinese-only locale is provided, this is a language-policy concern.

Natural-Language Policy Violations

Low
Confidence
80% confidence
Finding
The file presents user inputs, trigger keywords, and prompt guidance in both Chinese and English, but does not state that language is user-selectable or otherwise document a locale policy. Per the policy rule, language behavior should not be implicitly forced or assumed without opt-in or clear justification.

Static analysis

No suspicious patterns detected.