Back to skill

Security audit

Ellya--Your Virtual Companion

Security checks for vulnerabilities and agentic risk

Overview

This skill largely does what it claims, but it handles personal photos and derived body details with weak boundaries and has a file-path flaw that could expose local Markdown files.

Review this before installing. Only use it with photos you have permission to process, assume uploaded/reference images and detailed derived prompts may be sent to Google Gemini and saved locally, avoid sensitive or intimate images, and fix the style-name path traversal plus add clear consent and cleanup controls before broader use.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/genai_media.py:264
Finding

Path Traversal in Style Loading Enables Unauthorized Local Markdown File Disclosure

Content
View full analysis
str: style_file = STYLES_DIR / f"{style_name}.md" if not style_file.exists(): print(f"Style not found, skip: {style_name}") return "" with open(style_file, "r", encoding="utf-8") as f: content = f.read().strip() if not content: print(f"Style is empty, skip: {style_name}") return content ``` The attacker-controlled style name reaches this function through the following code: ```python def resolve_final_prompt(prompt: str | None, styles: list[str] | None, api_key: str) -> str: if styles: selected = styles[:3] loaded = [load_style_prompt(name) for name in selected] loaded = [s for s in loaded if s] if loaded: fused = fuse_style_prompts(loaded, api_key).strip() return fused or DEFAULT_PROMPT print("No valid style content found. Falling back to default prompt.") return DEFAULT_PROMPT return (prompt or "").strip() or DEFAULT_PROMPT ``` ### Technical Analysis The `style_name` argument originates from the repeatable `-s` command-line option and is incorporated directly into a filesystem path: ```python STYLES_DIR / f"{style_name}.md" ``` Although `sanitize_style_name()` exists elsewhere in the script, it is only used when creating style names and is not applied when loading them. The loader does not reject absolute paths, directory separators, or `..` traversal components. It also does not resolve the resulting path and verify that it remains beneath `STYLES_DIR`. Consequently, a value such as `../../private/notes` resolves to a path outside the intended style directory while retaining the automatically a ...[truncated 1988 chars]
Remediation
View remediation
str: normalized = sanitize_style_name(style_name) if not normalized or normalized != style_name: raise ValueError("Invalid style name") style_file = (STYLES_DIR / f"{normalized}.md").resolve() styles_root = STYLES_DIR.resolve() try: style_file.relative_to(styles_root) except ValueError: raise ValueError("Style path escapes the styles directory") if not style_file.is_file(): print(f"Style not found, skip: {normalized}") return "" return style_file.read_text(encoding="utf-8").strip() ``` 2. Reject names containing `/`, `\`, `..`, absolute path syntax, null bytes, or any character outside a narrow allowlist such as `[a-z0-9_]`. 3. Resolve and validate the final path with `Path.resolve()` and `Path.relative_to()` before checking or opening it. 4. Use `is_file()` rather than only `exists()` to ensure the target is a regular file. 5. If symbolic links may exist in `styles/`, reject symlinks or ensure the resolved target remains under the resolved style directory. 6. Add tests covering relative traversal, absolute paths, encoded separators, symlinks, empty names, and valid normalized style names. 7. Avoid forwarding file-derived content to an external model unless the file is confirmed to be an authorized style record. ]]>

other

Warning
Location
ANALYSIS_PROMPT.md:6
Finding

Style Analysis Collects and Persists Excessive Sensitive Physical Details

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (17)

Hidden Instructions

High
Category
Prompt Injection
Confidence
60% confidence
Finding

Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Content

Scanner excerpt · README.md (reported line 1)May include surrounding context.

md
---
name: Ellya
description: OpenClaw virtual companion skill. Use it to bootstrap runtime files (SOUL and base image), guide user personalization, learn and store style prompts from uploaded photos, generate selfies from user prompts or autonomous style strategy, and generate a multi-pose photo series from a selected image.
---

Hidden Instructions

High
Category
Prompt Injection
Confidence
60% confidence
Finding

Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Content

Scanner excerpt · SKILL.md (reported line 1)May include surrounding context.

md
---
name: Ellya
description: OpenClaw virtual companion skill. Use it to bootstrap runtime files (SOUL and base image), guide user personalization, learn and store style prompts from uploaded photos, generate selfies from user prompts or autonomous style strategy, and generate a multi-pose photo series from a selected image.
---

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/genai_media.py (reported line 24)May include surrounding context.

python
from dotenv import load_dotenv

load_dotenv()  # Load .env from project root (or any parent dir)

from google import genai
from google.genai import types

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The prompt explicitly instructs the model to perform highly granular analysis of intimate body regions and physiological details, including chest, buttocks, skin marks, veins, and body proportions, without any stated business need or safety boundary. That materially increases the risk of sexualized body analysis, invasive biometric inference, and misuse on images of private individuals or potentially minors.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The file includes a hard requirement to 'Use English' as part of the output instructions. This is a natural-language locale policy constraint and the prompt does not offer the user any language choice or explain a justified region-specific need.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The README explicitly instructs the skill to save user-provided photos, learned style data, and generated images to local paths such as assets/, styles/, and output/ without any notice about retention, access controls, or cleanup. In a companion-image skill handling personal photos, silent local persistence can expose sensitive biometric or intimate media to other local users, backups, logs, or later unintended reuse.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The README tells operators to transmit generated images to users via the OpenClaw messaging command, but does not mention that media will leave the local generation context and be sent through an external messaging channel. For user photos and AI-generated likenesses, lack of transmission disclosure can cause privacy violations, accidental sharing to the wrong recipient, or non-consensual dissemination of sensitive content.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill explicitly instructs saving uploaded appearance photos and modifying personalization files like SOUL.md, but it does not require clear user notice, consent, or retention boundaries before persisting that data. In a companion/image-generation context, uploaded photos are sensitive personal data, so silent storage and profile modification can create privacy, consent, and data-governance risks.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The series-generation flow allows a selected user image to be analyzed, transformed into multiple derivative images, stored in an output directory, and then transmitted back, without an explicit privacy warning or confirmation step. Because this expands one uploaded image into a larger derived dataset, the absence of consent and storage/transmission disclosure increases privacy exposure.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/genai_media.py (reported line 174)May include surrounding context.

python
cmd += ["--message", message]

    try:
        subprocess.run(cmd, check=True)
        print("Sent via OpenClaw.")
    except FileNotFoundError:
        print("Warning: openclaw command not found. Skipping send.")

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This code uploads user-provided image content to an external generative AI service during scene/character extraction without an explicit runtime disclosure or consent check. In a skill context, users may reasonably expect local processing, so silent third-party transmission can expose sensitive personal or biometric information.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The code sends scene and character descriptions derived from a user's image to an external model for classification and variation generation, again without an explicit warning at the point of use. Derived descriptions may still reveal sensitive attributes about a person, location, or activity, creating privacy and compliance risk.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

Series generation transmits the reference image and prompts to an external image model without an explicit user-facing disclosure in the execution path. Because this workflow is built around identity-preserving portrait generation, the privacy sensitivity is elevated: face images and descriptive prompts can contain personal data.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The generate command uploads local reference images and prompts to a remote AI provider with no explicit inline disclosure or confirmation. This can unintentionally leak private images, proprietary artwork, or sensitive prompt contents to a third-party service.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The analyze command sends a user-supplied image to an external AI service and stores the resulting style analysis locally, but does not clearly warn the user that third-party processing occurs. This is especially sensitive when images may include faces, private settings, or copyrighted material.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The template sets language: en-US as a fixed user-overridable setting, and nowhere in the file does it indicate that the user can choose another language or must opt into this locale. This is a natural-language policy concern because it imposes a specific language/locale by default rather than offering explicit choice.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The docstring states this function is kept only for backward compatibility and should not be called directly, implying it is effectively non-operational. In reality, it constructs an OpenClaw command and invokes subprocess.run to send media or messages, so the documentation understates the function's active side effects.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.