Back to skill

Security audit

hf-sdxl-image

Security checks for vulnerabilities and agentic risk

Overview

This skill does what it claims: it sends an image prompt to Hugging Face, saves the result locally, and relies on the caller to deliver and clean up the file.

Install only if you are comfortable sending image prompts to Hugging Face using your HUGGINGFACE_TOKEN. Use a low-privilege token, avoid sensitive prompt text, keep output paths in a private temporary directory, and delete generated files after delivery unless you intentionally want to keep them.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/generate_hf_sdxl.py:86
Finding

Predictable Temporary-File Write Allows Symlink-Based File Overwrite

Content
View full analysis

Vulnerability Details

File Location: scripts/generate_hf_sdxl.py, lines 86–97
Vulnerability Type: Unsafe temporary-file creation and symlink following
Risk Level: Medium

Vulnerable Code

python
output = args.output
if output.endswith("/") or os.path.isdir(output) or os.path.splitext(output)[1] == "":
    os.makedirs(output, exist_ok=True)
    filename = f"hf-sdxl-{time.strftime('%Y%m%d-%H%M%S')}{infer_extension(content_type)}"
    output = os.path.join(output, filename)
else:
    os.makedirs(os.path.dirname(os.path.abspath(output)), exist_ok=True)

with open(output, "wb") as f:
    f.write(body)

print(output)

Technical Analysis

When the output argument identifies a directory, the script constructs a filename using a timestamp with one-second resolution. The documented workflow recommends a path under /tmp/openclaw/. If that directory is accessible to another local user or process, the generated filename can be predicted.

The subsequent open(output, "wb") operation does not request exclusive creation and follows symbolic links. It therefore truncates an existing destination or follows a pre-created symlink. The code does not use a cryptographically random filename, verify destination ownership, reject symlinks, or atomically ensure that it created a new file.

This is a time-of-check/time-of-use and unsafe temporary-file weakness. Exploitation requires local access to the selected output directory and the ability to predict the generation time and likely response extension.

Attack Path

  1. A local attacker determines that the Skill will generate an image in a shared or attacker-writable directory such as /tmp/openclaw/.
  2. The attacker predicts the timestamp used in the filename, for example hf-sdxl-20260915-120000.png.
  3. Before the write occurs, the attacker creates that path as a symbolic link to another file.
  4. The Hugging Face API returns the generated image. ...[truncated 951 chars]
Remediation
View remediation

Remediation Suggestions

  • Create generated files atomically with tempfile.mkstemp() or tempfile.NamedTemporaryFile(delete=False, dir=output_directory, suffix=extension). These APIs provide unpredictable names and exclusive creation.
  • Use a private temporary directory owned by the Skill process with permissions set to 0700, rather than relying on a shared writable directory.
  • If manually creating files, use os.open() with O_CREAT | O_EXCL and, where supported, O_NOFOLLOW, then write through the returned descriptor.
  • Never reopen the generated pathname after validating it, because doing so can reintroduce a race condition.
  • Reject existing destinations unless the caller explicitly requests overwrite behavior.
  • If caller-selected output files must be supported, use lstat()-based validation and platform-specific no-follow semantics, while recognizing that validation alone does not replace atomic creation.
  • Preserve the documented cleanup behavior by deleting the securely created temporary file after confirmed delivery.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (8)

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding

The skill description promises a constrained model, temporary-file handling, delivery, and cleanup, but the documented behavior allows model override and omits actual delivery and deletion guarantees. Security-relevant mismatches like this can mislead users and orchestrators about what is executed, what data is retained, and where requests may be sent.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding

The skill requires access to environment variables and outbound network calls, but it does not declare any tool scope or permission boundary. That makes the capability set implicit rather than explicit, which weakens review and enforcement and can allow unintended secret access or network use if the runtime grants broad defaults.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The manifest description says to use the skill when the user asks to "generate, draw, create, make, or render an image or illustration from text," which includes very broad verbs like "create" and "make." Although examples later in the file are stronger, this top-level activation text could still cause unintended invocation on ordinary conversational requests about making or creating images.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The manifest claims the skill uses a fixed SDXL model, but the implementation allows model substitution through HF_IMAGE_MODEL. That creates a trust-boundary mismatch: an operator or compromised environment can silently redirect requests to a different Hugging Face model with different safety properties, retention behavior, or output types than users were told to expect.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The script transmits the full user prompt to a third-party Hugging Face endpoint using a bearer-authenticated request, but there is no explicit disclosure or consent mechanism in the code path. In the skill context, prompts may contain sensitive or proprietary text, so undisclosed off-host transmission increases privacy and data-governance risk.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The skill description promises temporary-file handling and deletion after delivery, but this script always leaves a persistent local copy unless some external component cleans it up. That mismatch can expose generated images containing sensitive prompts or private content to later local access, backup, or forensic recovery.

Content

No source excerpt is available for this finding.

Tainted flow: 'output' from os.getenv (line 92, credential/environment) → open (file write)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · scripts/generate_hf_sdxl.py (reported line 96)May include surrounding context.

python
else:
        os.makedirs(os.path.dirname(os.path.abspath(output)), exist_ok=True)

    with open(output, "wb") as f:
        f.write(body)

    print(output)

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
76% confidence
Finding

The code creates directories and writes binary output to the provided path, affecting the local filesystem. Although this is part of the script's purpose, there is no user-facing warning in code comments, help text, or runtime output before the write occurs describing that files and directories may be created.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.