Back to skill

Security audit

AI Image & Video Generator | WIME

Security checks for vulnerabilities and agentic risk

Overview

The skill matches its WIME image-processing purpose, but its token handling and remote URL controls are loose enough that users should review it before installing.

Before installing, confirm you trust this publisher and WIME with the images and prompts you process. Use only the production WIME endpoint unless you fully control the target, do not run scripts/wime_auth.py with a real token unless it is fixed to redact secrets, avoid sensitive or unreleased images until public URL and retention behavior are clear, and prefer a version that validates redirects, limits downloads, and uses safe temporary files.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/wime_auth.py:14
Finding

WIME credentials and user images can be redirected to an arbitrary endpoint

Content
View full analysis

Vulnerability Details

File Location: scripts/wime_auth.py, lines 14-43
Vulnerability Type: Unvalidated authentication endpoint configuration
Risk Level: High

Vulnerable Code

python
BASE_URL = os.environ.get("WIME_BASE_URL", "https://wime-ai.com")
ACCESS_TOKEN = os.environ.get("WIME_ACCESS_TOKEN", "")


def get_auth(
    method: str = "POST",
    uri_path: str = "",
    body_dict: Optional[dict] = None,
    content_type: str = "application/json",
) -> dict:
    """Generate WIME access-token request configuration."""
    if not ACCESS_TOKEN:
        raise ValueError(
            "WIME_ACCESS_TOKEN is not configured."
        )

    headers = {"access-token": ACCESS_TOKEN}
    body_str = None

    if body_dict is not None:
        body_str = json.dumps(
            body_dict,
            separators=(",", ":"),
            sort_keys=True,
            ensure_ascii=False
        )
        headers["Content-Type"] = content_type

    return {
        "base_url": BASE_URL,
        "headers": headers,
        "body_str": body_str,
    }

The returned base_url and authentication headers are subsequently used together in documented API requests:

python
resp = requests.post(
    f"{auth['base_url']}/waic/core/creationDesk/draw",
    headers=auth["headers"],
    data=auth["body_str"].encode("utf-8")
)

Technical Analysis

WIME_BASE_URL is accepted directly from the process environment without scheme or hostname validation. The generated request configuration attaches the complete WIME access token to requests sent to that endpoint.

The Skill documentation also uses this configurable endpoint for multipart image uploads. Therefore, control over WIME_BASE_URL permits redirection of both authentication credentials and explicitly selected user images. The override also permits plaintext http:// endpoints, which would expose data to network i ...[truncated 1225 chars]

Remediation
View remediation

Remediation Suggestions

  • Remove WIME_BASE_URL configurability in production and use the fixed documented WIME endpoint.
  • If endpoint overrides are required, enforce https, reject embedded credentials, and restrict hosts to an explicit allowlist.
  • Separate development and production credentials so production tokens cannot be sent to test endpoints.
  • Resolve and validate the destination before sending credentials, rejecting loopback, private, link-local, reserved, and multicast addresses.
  • Disable automatic cross-origin redirects for authenticated requests. If redirects are necessary, validate every destination and strip credentials whenever the origin changes.
  • Fail closed when endpoint validation is unsuccessful.
  • Document and enforce narrow server-side token scopes, expiration, revocation, and rotation.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/wime_auth.py:54
Finding

The authentication helper prints the complete access token to standard output

Content
View full analysis

Vulnerability Details

File Location: scripts/wime_auth.py, lines 54-60
Vulnerability Type: Sensitive credential exposure through logs
Risk Level: High

Vulnerable Code

python
if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="WIME OpenAPI authentication utility")
    parser.add_argument("--method", default="POST")
    parser.add_argument("--path", default="/waic/core/creationDesk/draw")
    parser.add_argument("--body", default="{}", help="JSON body string")
    args = parser.parse_args()

    body_dict = json.loads(args.body)
    result = get_auth(method=args.method, uri_path=args.path, body_dict=body_dict)
    print(json.dumps(result, indent=2, ensure_ascii=False))

get_auth() returns a structure whose headers member contains the complete credential:

python
headers = {"access-token": ACCESS_TOKEN}

return {
    "base_url": BASE_URL,
    "headers": headers,
    "body_str": body_str,
}

Technical Analysis

When the helper is executed directly, it serializes the entire result of get_auth() to standard output. Because that result includes the unredacted access-token header, the credential becomes visible in terminals, shell transcripts, CI output, agent tool output, and centralized logging systems.

Credentials should not be rendered merely to demonstrate or inspect authentication configuration. This disclosure is not required for the Skill's image-processing functionality.

Attack Path

  1. A valid WIME_ACCESS_TOKEN is configured in the environment.
  2. A user, automation process, diagnostic command, or CI job runs scripts/wime_auth.py.
  3. The script calls get_auth(), which places the complete token in result["headers"].
  4. json.dumps() serializes the token and print() writes it to standard output.
  5. Terminal history, job logs, agent transcripts, or log aggregation retain the credential.
  6. A person or servi ...[truncated 404 chars]
Remediation
View remediation

Remediation Suggestions

  • Never print the returned authentication headers.
  • Remove the direct-execution diagnostic path if it is unnecessary.
  • If diagnostic output is required, construct a separate sanitized object and replace the token with a constant such as "[REDACTED]".
  • Avoid logging request headers globally when they may contain access-token.
  • Add automated tests that assert secrets are absent from stdout, stderr, exceptions, and structured logs.
  • Rotate the WIME token if the current helper has been executed in any logged environment.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/crop_alpha.py:82
Finding

Remote image validation can be bypassed through redirects and DNS rebinding

Content
View full analysis

Vulnerability Details

File Location: scripts/crop_alpha.py, lines 82-85
Vulnerability Type: Server-side request forgery through incomplete URL validation
Risk Level: High

Vulnerable Code

python
tmp_download = None
if input_path_or_url.startswith(("http://", "https://")):
    _validate_remote_url(input_path_or_url)
    resp = req.get(input_path_or_url, timeout=30)
    resp.raise_for_status()
    tmp_download = tempfile.NamedTemporaryFile(suffix=".png", delete=False)
    tmp_download.write(resp.content)
    tmp_download.close()
    local_path = tmp_download.name

The initial validation rejects private addresses:

python
def _validate_remote_url(input_url: str) -> None:
    parsed = urlparse(input_url)
    if parsed.scheme not in {"http", "https"}:
        raise ValueError("Only http/https URLs are allowed")
    if not parsed.hostname:
        raise ValueError("URL hostname is missing")
    if _is_private_host(parsed.hostname):
        raise ValueError(f"Refusing private or localhost URL: {parsed.hostname}")

Technical Analysis

The code validates only the original URL and then calls requests.get(). The Requests library follows HTTP redirects by default. A public URL that passes _validate_remote_url() can consequently redirect to a loopback, private, link-local, or cloud-metadata address without any validation of the redirect destination.

There is also a time-of-check/time-of-use DNS gap: _is_private_host() resolves the hostname during validation, while the later HTTP connection may perform a separate resolution. An attacker controlling DNS can return a public address during validation and a private address during connection.

The request has a time limit but no response-size limit, and it buffers the complete body in resp.content. This amplifies denial-of-service risk from a permitted remote endpoint.

Attack Path

  1. An attacker provides an image ...[truncated 1244 chars]
Remediation
View remediation

Remediation Suggestions

  • Set allow_redirects=False and reject redirects, or process redirects manually while validating every target before connecting.
  • Require HTTPS unless plain HTTP is explicitly necessary.
  • Resolve the hostname once, validate all returned addresses, and connect only to an approved resolved address while preserving correct TLS hostname verification.
  • Revalidate after every redirect and reject loopback, private, link-local, reserved, unspecified, and multicast destinations for both IPv4 and IPv6.
  • Defend against DNS rebinding by preventing an independent unvalidated DNS resolution between validation and connection.
  • Stream responses with a strict maximum byte count instead of reading unrestricted resp.content.
  • Verify Content-Type, actual image format, dimensions, and decompressed pixel limits before processing.
  • Consider restricting downloads to known WIME-controlled image hosts if that satisfies the declared workflow.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/crop_alpha.py:105
Finding

Predictable temporary output paths permit symlink-based file overwrite

Content
View full analysis

Vulnerability Details

File Location: scripts/crop_alpha.py, lines 105 and 128
Vulnerability Type: Insecure temporary file creation
Risk Level: Medium

Vulnerable Code

The all-transparent-image branch generates an output name using mktemp():

python
if not rows.any() or not cols.any():
    # Fully transparent image; return it unchanged
    if output_path is None:
        output_path = tempfile.mktemp(
            suffix=".png",
            dir="/tmp",
            prefix="cropped_"
        )
    img.save(output_path, "PNG")
    return output_path, (img.width, img.height)

The normal cropping branch repeats the same pattern:

python
cropped = img.crop((cmin, rmin, cmax + 1, rmax + 1))

if output_path is None:
    output_path = tempfile.mktemp(
        suffix=".png",
        dir="/tmp",
        prefix="cropped_"
    )
cropped.save(output_path, "PNG")
return output_path, (cropped.width, cropped.height)

Technical Analysis

tempfile.mktemp() returns a path without atomically creating the file. A race exists between path generation and the later img.save() call. On a shared system, another local process may create that path or substitute a symbolic link before the image is written.

The code correctly uses NamedTemporaryFile for downloaded input, but not for generated output. The unsafe output-path behavior is unnecessary because Python provides atomic temporary-file creation functions.

Attack Path

  1. The Skill processes an image without an explicitly supplied output_path.
  2. tempfile.mktemp() selects a currently unused path under the shared /tmp directory.
  3. A local attacker predicts, observes, or races the generated filename.
  4. Before img.save() opens the path, the attacker creates a symbolic link at that location pointing to another file writable by the Skill process.
  5. img.save() follows the substituted path and writes PNG c ...[truncated 513 chars]
Remediation
View remediation

Remediation Suggestions

  • Replace tempfile.mktemp() with tempfile.NamedTemporaryFile(delete=False, suffix=".png", prefix="cropped_") or tempfile.mkstemp().
  • Create the output file atomically with restrictive permissions before writing any content.
  • Write through the securely opened file descriptor where supported rather than closing it and reopening by pathname.
  • If Pillow requires a pathname, use a private temporary directory created with tempfile.TemporaryDirectory() and restrictive permissions.
  • Ensure generated files are removed in a finally block after upload or use.
  • Validate caller-supplied output paths separately and avoid following symbolic links when the platform provides safe no-follow options.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • 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
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (11)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description promises two high-level capabilities: 1) removing backgrounds from source images and returning a transparent-background result, and 2) generating multiple AI 商拍图/product marketing images. The actual code does neither. It assumes the input image already has transparency, then finds the bounding box of non-transparent pixels and crops the image accordingly. This is a post-processing utility for transparent PNGs, not a background-removal system and not an AI image-generation workflow. The URL fetching and SSRF-style private host blocking are implementation details consistent with accepting remote image inputs, but the main functional behavior is materially narrower and different from the declared purpose.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding

The skill requires access to environment secrets (WIME_ACCESS_TOKEN) and makes outbound network requests, but it does not explicitly declare tool scope or permissions. This weakens least-privilege controls and can cause the agent runtime to grant broader capabilities than users or reviewers expect, especially because the skill also handles user-supplied local paths and remote URLs.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The entire skill documentation is written in Chinese and does not offer any language choice or indicate that the skill is intentionally limited to a Chinese-speaking or region-specific context. Under the policy, forcing a specific language without opt-in is a natural-language policy violation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

This markdown file presents all user-facing instructions in Chinese and does not indicate that the skill is region-specific or provide any user opt-in for language preference. Under the policy, forcing a specific language without user choice is a natural-language policy violation.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

Line L07 says the interface directly returns the cutout result as a synchronous API, while L32 states the new cutout API is asynchronous and only returns taskItemIds that must be polled later. This is an active contradiction in the file's own documentation about what the endpoint actually does.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The documentation describes sending image URLs, original image URLs, prompts, and related metadata to a remote API, but it does not warn users that potentially sensitive product images and text inputs will be transmitted to an external service. In this skill context, that omission matters because image assets can contain proprietary product data, unreleased marketing materials, or customer-related content, making accidental external disclosure more likely.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The documentation states that uploaded images are returned as directly accessible public URLs, but it does not warn users that uploaded content may become publicly reachable or persist outside their control. In an image-processing skill handling potentially sensitive product, personal, or proprietary images, this creates a real privacy and data-exposure risk because users may upload confidential images assuming they are only used transiently for processing.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

This code includes user-facing natural-language documentation and usage guidance exclusively in Chinese, including the module docstring and function docstring context. That imposes a specific language on users without offering a language choice or documenting a justified locale restriction, which matches the language/locale policy violation criteria.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The script prints the full result of get_auth(), which includes the access-token header value. This exposes the secret token to stdout, where it may be captured by shell history, logs, CI job output, terminal recording, or other monitoring systems. In an auth helper for an API integration, leaking the bearer-equivalent token can directly enable unauthorized API use.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

The entire document is written only in Chinese, including headings and error descriptions, with no indication that the skill is region-specific or that users may choose another language. Under the stated policy, forcing a specific language without opt-in is a natural-language policy violation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
81% confidence
Finding

The file's natural-language instructions and parameter descriptions are presented only in Chinese, which can impose a language constraint on users without any opt-in or justification. Under the policy, forced language or locale without user choice or documented rationale is a natural-language policy concern.

Content

No source excerpt is available for this finding.