Back to skill

Security audit

Stability Ai

Security checks for vulnerabilities and agentic risk

Overview

This image-generation skill is mostly purpose-aligned, but it needs review because it can send API credentials to an arbitrary configured host and can automatically delete unrelated image files in a chosen output directory.

Install only if you are comfortable sending prompts to Stability AI or a configured API_HOST, and avoid setting API_HOST to anything untrusted or non-HTTPS. Use a dedicated empty output directory because the cleanup routine can delete older PNG, JPG, JPEG, WebP, and same-basename JSON files in that directory. Treat generated JSON metadata as potentially sensitive because it stores prompts and settings.

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

Error
Location
scripts/core/generate.py:14
Finding

Stability API Credential Disclosure Through an Unrestricted Custom API Host

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/core/generate.py:313
Finding

Automatic Cleanup Can Delete Unrelated User Images and Metadata

Content
View full analysis
None: try: extensions = ["png", "jpg", "jpeg", "webp"] files = [os.path.join(output_dir, f) for f in os.listdir(output_dir) if any(f.endswith(f".{ext}") for ext in extensions)] files.sort(key=os.path.getmtime) retention_limit = 20 if len(files) > retention_limit: removed = files[:len(files) - retention_limit] for f in removed: os.remove(f) json_file = f.replace(os.path.splitext(f)[1], ".json") if os.path.exists(json_file): os.remove(json_file) print(f"Auto-Clean: Removed old file {os.path.basename(f)}") except Exception as e: print(f"Cleanup warning: {e}") ``` The cleanup target is user-controlled: ```python parser.add_argument("--output", default="./assets/generated", help="Output directory") ``` ### Technical Analysis The cleanup routine treats every PNG, JPEG, or WebP file in `output_dir` as if it were owned by the Skill. It does not verify that a file was generated by this script, has the generated filename pattern, or is recorded in a Skill-maintained manifest. The `--output` argument permits the user or invoking automation to select an arbitrary writable directory. Once the directory contains more than 20 matching images, the function deletes the oldest matching files regardless of their origin. For each deleted image, it also deletes a same-basename JSON file if one exists, again without verifying ownership. Automatic retention is consistent with the documented functionality, but deleting unrelated files is not necessary to implement that feature and exceeds the minimum filesystem scope required ...[truncated 1408 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Note
Location
requirements.txt:1
Finding

Unpinned Third-Party Dependencies Create Supply-Chain and Reproducibility Risk

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
Findings (18)

Tainted flow: 'url' from os.getenv (line 195, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
91% confidence
Finding

The request target is derived from API_HOST, which comes from the environment and is not validated before the code sends the Stability API bearer token and user prompt to it. If an attacker can influence environment variables or the .env file, they can redirect requests to an attacker-controlled host and exfiltrate the API key and prompt data.

Content

Scanner excerpt · scripts/core/generate.py (reported line 118)May include surrounding context.

python
print(f"Style:      {style_preset}")

    try:
        response = requests.post(url, headers=headers, json=body, timeout=120)
        
        if response.status_code == 401:
            print("Error: Invalid API key. Check your STABILITY_API_KEY.")

Tainted flow: 'url' from os.getenv (line 195, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
91% confidence
Finding

The V2 request also uses a URL built from the environment-controlled API_HOST while attaching the Authorization bearer token. A modified environment can silently redirect traffic and leak secrets and user content to an attacker-controlled service.

Content

Scanner excerpt · scripts/core/generate.py (reported line 238)May include surrounding context.

python
print(f"Style:      {style_preset}")

    try:
        response = requests.post(url, headers=headers, files=files, data=data, timeout=120)
        
        if response.status_code == 401:
            print("Error: Invalid API key. Check your STABILITY_API_KEY.")

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/core/generate.py (reported line 21)May include surrounding context.

python
if not API_KEY:
    print("Error: STABILITY_API_KEY environment variable not set.")
    print("Tip: Check your .env file or export the variable.")
    sys.exit(1)

ASPECT_RATIO_MAP = {

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill documents behavior that clearly implies network access, environment-variable access, and local file writes, but it declares no explicit tool scope or permission boundaries. That makes the skill easier to invoke with broader-than-necessary capabilities and weakens reviewability, increasing the chance of unintended data access or misuse if integrated into an agent runtime.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The trigger phrases and description are broad enough to match many ordinary user requests like 'generate image' or 'draw this,' which can cause the skill to activate in contexts the user did not specifically intend. Over-broad routing increases the risk of accidental prompt transmission to an external API and unintended local artifact creation, especially in multi-skill agent environments.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The skill states that prompts, negative prompts, parameters, and timestamps are stored in local JSON metadata files, but it does not prominently warn users beforehand. Prompts can contain sensitive or proprietary information, so silent persistence creates a privacy and data-retention risk if those files are later accessed, synced, or exfiltrated.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/core/generate.py (reported line 118)May include surrounding context.

python
print(f"Style:      {style_preset}")

    try:
        response = requests.post(url, headers=headers, json=body, timeout=120)
        
        if response.status_code == 401:
            print("Error: Invalid API key. Check your STABILITY_API_KEY.")

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill persists prompt metadata and then performs lifecycle management of files, which exceeds a narrowly understood 'generate image' action. Because prompts may contain sensitive user data, storing them in JSON sidecar files increases privacy risk, especially without explicit user consent or retention controls.

Content

No source excerpt is available for this finding.

Tainted flow: 'data' from requests.post (line 137, network input) → requests.post (network output)

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/core/generate.py (reported line 238)May include surrounding context.

python
print(f"Style:      {style_preset}")

    try:
        response = requests.post(url, headers=headers, files=files, data=data, timeout=120)
        
        if response.status_code == 401:
            print("Error: Invalid API key. Check your STABILITY_API_KEY.")

Tainted flow: 'filepath' from requests.post (line 146, network input) → 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/core/generate.py (reported line 316)May include surrounding context.

python
img = Image.open(io.BytesIO(image_data))
        img.save(filepath, "WEBP", quality=95)
    else:
        with open(filepath, "wb") as f:
            f.write(image_data)
    
    return filepath

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

Automatic cleanup deletes files in the output directory based solely on extension and age ordering, which is broader than simple image generation. If the output directory contains other important images, this feature can remove user data unexpectedly and cause integrity/availability loss.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The script deletes older files automatically without prior warning or confirmation. In an agent-skill context, this is risky because users may reasonably expect generation only, not destructive file operations in the selected output directory.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
97% confidence
Finding

The dependency 'requests' is unpinned, so builds are not reproducible and may silently pull in a vulnerable or breaking release over time. In a network-facing skill that likely makes outbound API calls, this increases supply-chain risk and makes it impossible to verify whether known advisories affect the deployed version.

Content

Scanner excerpt · requirements.txt (reported line 1)May include surrounding context.

text
requests
python-dotenv
pillow

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
89% confidence
Finding

The manifest does not pin a version of 'requests', and the package has multiple known advisories across its release history. That means the deployment could resolve to an affected version without visibility, which is particularly relevant for a skill expected to perform HTTP requests to an external API.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
96% confidence
Finding

The dependency 'python-dotenv' is unpinned, which allows arbitrary future releases to be installed without review. Because this package influences environment-variable loading, an unsafe or compromised version could affect secret handling or local file interactions in ways that are hard to audit.

Content

Scanner excerpt · requirements.txt (reported line 2)May include surrounding context.

text
requests
python-dotenv
pillow

Unverifiable Dependency: python-dotenv has 2 known advisory(ies) (CVE-2026-28684 (python-dotenv: Symlink following in set_key allows arbitrary file overwrite via ); CVE-2026-28684 (python-dotenv reads key-value pairs from a .env file and can set them as environ)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
84% confidence
Finding

Because 'python-dotenv' is not version-pinned, there is no way to determine from this manifest whether the installed release includes known vulnerabilities. While the package is not the core image-processing component, it can influence configuration and secret-loading behavior, so leaving its version unspecified weakens deployment assurance.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
97% confidence
Finding

The dependency 'pillow' is unpinned, creating supply-chain and reproducibility risk for image-processing code. In an image-generation skill, image libraries are especially security-relevant because malformed image inputs or vulnerable decoders have historically led to denial of service and, in some versions, code-execution issues.

Content

Scanner excerpt · requirements.txt (reported line 3)May include surrounding context.

text
requests
python-dotenv
pillow

Unverifiable Dependency: pillow has 16 known advisory(ies) (CVE-2016-2533 (Pillow buffer overflow in ImagingPcdDecode); CVE-2023-50447 (Arbitrary Code Execution in Pillow); CVE-2021-27922 (Pillow Uncontrolled Resource Consumption) +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
93% confidence
Finding

The manifest leaves 'pillow' unpinned even though the library has a long history of security advisories, including memory-safety and resource-consumption issues. In the context of an image-generation skill, this is more dangerous than average because image handling is a primary function, making a vulnerable Pillow version more likely to be exercised.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.