Back to skill

Security audit

Free Image Generation Skill

Security checks for vulnerabilities and agentic risk

Overview

The skill appears to do the advertised image generation work, but it can overwrite arbitrary user-writable files and installs an unpinned dependency into the user Python environment.

Review before installing. Use this only if you are comfortable sending prompts to Perchance's unofficial image-generation service, and run it with a dedicated output directory you control. Avoid letting untrusted users or automated workflows choose --out paths. Prefer installing dependencies in a virtual environment with pinned versions rather than running the provided user-level pip install as-is.

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 (2)

T08 · Insecure Dependencies

Warning
Location
scripts/requirements.txt:1
Finding
Unpinned Third-Party Dependency Installed into the User Environment<![CDATA[ ## Vulnerability Details **File Location**: `scripts/requirements.txt:1` and `scripts/setup_env.sh:1-4` **Vulnerability Type**: Unpinned dependency and non-reproducible installation **Risk Level**: Medium ### Vulnerable Code `scripts/requirements.txt:1`: ```text requests>=2.31.0 ``` `scripts/setup_env.sh:1-4`: ```bash #!/usr/bin/env bash set -euo pipefail python3 -m pip install --user -r "$(dirname "$0")/requirements.txt" echo "[ok] Dependencies installed" ``` ### Technical Analysis The requirement uses an open-ended version constraint rather than an exact, audited version and does not provide package integrity hashes. Consequently, every fresh installation can resolve to a different future release of `requests` and its transitive dependencies. The setup script also uses `pip install --user`, which modifies the user's persistent Python package environment instead of creating an isolated virtual environment. This can introduce dependency conflicts and makes the installed code available to other Python programs executed by the same user. This is a supply-chain hardening weakness rather than evidence that the currently named package is malicious. Exploitation would require compromise of an allowed package release, its distribution channel, or one of its dependencies. ### Attack Path 1. An attacker compromises an allowed future release of `requests`, one of its transitive dependencies, or the relevant package-distribution channel. 2. The malicious release still satisfies the constraint `requests>=2.31.0`. 3. A user runs `bash scripts/setup_env.sh`. 4. `pip` resolves and downloads the compromised version without checking a repository-provided hash. 5. Package installation or subsequent import executes attacker-controlled code with the privileges of the user running the setup or generation script. ### Impact Assessment Successful exploitation could execute arbitrary code with the current user's privileges. This could expose files, environment va ...[truncated 226 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin each direct and transitive dependency to an audited exact version. 2. Generate a lock file containing cryptographic hashes and install with `pip --require-hashes`. 3. Install dependencies into a project-specific virtual environment rather than the persistent user package directory. 4. Review and update the lock file through a controlled dependency-update process. 5. Add automated vulnerability and provenance checks for locked dependencies. For example: ```text requests==<audited-version> --hash=sha256:<verified-hash> ``` Then install from an isolated environment using hash enforcement: ```bash python3 -m venv .venv .venv/bin/python -m pip install --require-hashes -r scripts/requirements.txt ``` ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/perchance_generate.py:107
Finding
Unrestricted Output Path Allows Overwriting Arbitrary User-Writable Files<![CDATA[ ## Vulnerability Details **File Location**: `scripts/perchance_generate.py:107-108`; input resolution occurs at `scripts/perchance_generate.py:136` **Vulnerability Type**: Unrestricted file write and unsafe overwrite **Risk Level**: Medium ### Vulnerable Code `scripts/perchance_generate.py:107-108`: ```python out_path.parent.mkdir(parents=True, exist_ok=True) out_path.write_bytes(dl.content) ``` The caller-controlled path is resolved without enforcing an approved output root at `scripts/perchance_generate.py:136`: ```python out = Path(args.out).expanduser().resolve() ``` ### Technical Analysis The `--out` argument is accepted as an arbitrary filesystem path. Calling `resolve()` canonicalizes the path but does not verify that it remains inside an approved media directory. The code then creates missing parent directories and uses `Path.write_bytes()`, which truncates and overwrites an existing file. The bytes written to the selected path come from a remote HTTP response. Although `raise_for_status()` verifies the HTTP status, the script does not validate the response `Content-Type`, confirm that the body is a valid image, impose a response-size limit, or ensure that the extension matches the image format. The weakness is exploitable when an untrusted user or upstream agent can influence `--out`. It does not bypass operating-system permissions: only paths writable by the process account can be affected. ### Attack Path 1. An attacker supplies or influences an image-generation request that controls the `--out` value. 2. The attacker selects an existing sensitive file or a new path outside the intended media directory. 3. `Path.resolve()` converts the value to an absolute path but performs no containment check. 4. `mkdir(parents=True, exist_ok=True)` creates missing writable directories. 5. `write_bytes(dl.content)` truncates an existing target and replaces it with the provider response, or creates a new file. 6. Depen ...[truncated 614 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Define a dedicated output directory and require every resolved destination to remain within it. 2. Generate server-side filenames where possible instead of accepting arbitrary paths. 3. Reject existing targets by default, using exclusive file creation unless overwrite is explicitly authorized. 4. Reject symlinks and re-check containment immediately before the final write to reduce link-based race risks. 5. Stream downloads with a strict maximum byte limit. 6. Require an expected image media type and decode the response with an image parser before saving it. 7. Write first to a securely created temporary file in the approved directory, then atomically rename it to the final destination. 8. Run the skill under an account with minimal filesystem permissions. A containment check should follow this pattern: ```python output_root = Path("./media").resolve() candidate = (output_root / requested_name).resolve() if candidate != output_root and output_root not in candidate.parents: raise ValueError("Output path is outside the approved directory") if candidate.exists(): raise FileExistsError("Refusing to overwrite an existing file") ``` ]]>
Vulnerability Patterns
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (4)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The skill metadata and instructions claim image generation, retry/backoff, and local output behavior, but the analyzed file mostly describes setup and invocation without demonstrating those security-relevant behaviors. This mismatch is dangerous because reviewers and agents may trust the declared purpose while hidden or undeclared behavior in referenced scripts performs different actions, especially environment installation or network activity that deserves separate scrutiny.

Lp3

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding
The skill advertises commands that install dependencies, invoke a Python script, write output files, and likely access external services, but it does not declare any explicit tool scope or permissions. In an agent environment, missing scope boundaries can cause the skill to run with broader-than-necessary filesystem and network access, increasing the chance of unintended writes, unreviewed outbound requests, or misuse by downstream automation.

Unpinned Dependencies

Low
Category
Supply Chain
Content
requests>=2.31.0
Confidence
95% confidence
Finding
The dependency is specified as `requests>=2.31.0`, which allows future major or minor releases to be installed without review. This reduces build reproducibility and can unintentionally introduce vulnerable, incompatible, or malicious upstream versions into the skill at install time.

Unverifiable Dependency: requests has 16 known advisory(ies) (CVE-2014-1830 (Exposure of Sensitive Information to an Unauthorized Actor in Requests); CVE-2024-47081 (Requests vulnerable to .netrc credentials leak via malicious URLs); CVE-2024-35195 (Requests `Session` object does not verify requests after making first request wi) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
90% confidence
Finding
Because `requests` is unpinned, it is not possible to verify whether the installed version includes fixes for known advisories affecting older releases. In a skill that performs outbound network access for image generation, using an affected `requests` version could expose credentials, TLS verification behavior, or other request-handling security properties depending on runtime usage.

Static analysis

No suspicious patterns detected.