Back to skill

Security audit

krea

Security checks for vulnerabilities and agentic risk

Overview

This Krea.ai media skill is coherent and purpose-aligned, but it sends prompts and media to Krea and writes generated outputs locally.

Install only if you are comfortable sending prompts, image/video inputs, local files you reference, and training image URLs to Krea.ai using your Krea API token. Avoid sensitive or internal URLs, do not use --skip-validation unless the inputs are trusted, and choose output directories intentionally because the scripts save generated files and some state/cache files locally.

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

Warning
Location
scripts/train_style.py:32
Finding

Unrestricted Training URL Validation Enables Server-Side Request Forgery

Content
View full analysis

Vulnerability Details

File Location: scripts/train_style.py:22-48 and scripts/train_style.py:83-94
Vulnerability Type: Server-Side Request Forgery (SSRF)
Risk Level: Medium

Vulnerable Code

python
def load_urls(args):
    """Collect training image URLs from --urls and/or --urls-file."""
    urls = list(args.urls or [])
    if args.urls_file:
        with open(args.urls_file) as f:
            for line in f:
                line = line.strip()
                if line and not line.startswith("#"):
                    urls.append(line)
    return urls


def validate_urls(urls):
    """HEAD-check every URL to catch 404s before wasting CU on training."""
    print(f"Validating {len(urls)} image URLs...", file=sys.stderr)
    bad = []
    for i, url in enumerate(urls):
        try:
            r = requests.head(url, timeout=10, allow_redirects=True)
            if r.status_code >= 400:
                bad.append((url, r.status_code))
                print(f"  [{i+1}/{len(urls)}] FAIL {r.status_code}: {url[:80]}", file=sys.stderr)
            else:
                print(f"  [{i+1}/{len(urls)}] OK: {url[:80]}", file=sys.stderr)
        except requests.RequestException as e:
            bad.append((url, str(e)))
            print(f"  [{i+1}/{len(urls)}] FAIL: {url[:80]} ({e})", file=sys.stderr)
    return bad
python
# Resolve local files to hosted URLs
resolved_urls = []
for url in urls:
    resolved_urls.append(ensure_image_url(url, api_key))

# Validate URLs are reachable
if not args.skip_validation:
    bad = validate_urls(resolved_urls)
    if bad:
        print(f"\nError: {len(bad)} URLs failed validation. Fix them or use --skip-validation.", file=sys.stderr)
        for url, reason in bad:
            print(f"  {reason}: {url[:100]}", file=sys.stderr)
        sys.exit(1)

Technical Analysis

Training URLs supplied through `--url ...[truncated 2171 chars]

Remediation
View remediation

Remediation Suggestions

  1. Permit only https URLs and reject URLs containing embedded credentials.
  2. Resolve the hostname before connecting and reject every address that is loopback, private, link-local, multicast, unspecified, or reserved.
  3. Disable automatic redirects or validate the hostname and resolved IP address at every redirect hop.
  4. Apply an allowlist of trusted image-hosting domains when operationally feasible.
  5. Validate that the returned content type is an expected image media type.
  6. Use a controlled outbound proxy or network policy that blocks access to internal and metadata address ranges.
  7. Recheck the connected peer address to mitigate DNS rebinding and time-of-check/time-of-use discrepancies.
  8. Avoid printing unnecessary internal connection details in error output.

T09 · Insecure Skill Coding Practices

Note
Location
scripts/krea_helpers.py:475
Finding

Unbounded Remote Result Downloads Can Exhaust Local Resources

Content
View full analysis

Vulnerability Details

File Location: scripts/krea_helpers.py:475-483
Vulnerability Type: Unrestricted File Download / Resource Exhaustion
Risk Level: Low

Vulnerable Code

python
def download_file(url, filename):
    """Download a URL to a local file."""
    os.makedirs(os.path.dirname(filename), exist_ok=True) if os.path.dirname(filename) else None
    r = requests.get(url, stream=True)
    r.raise_for_status()
    with open(filename, "wb") as f:
        for chunk in r.iter_content(chunk_size=8192):
            f.write(chunk)
    return os.path.abspath(filename)

Technical Analysis

The shared download helper writes remote response data until the server closes the connection. It does not impose:

  • Connection or read timeouts.
  • A maximum response size.
  • A destination-host policy.
  • Content-type validation.
  • File-signature validation.
  • A minimum free-space requirement.

The URLs normally originate from Krea job responses, which lowers practical exploitability. Nevertheless, if the upstream service, job response, or returned storage URL is compromised or malformed, the downloader will trust the URL and write an unlimited amount of data to disk.

Attack Path

  1. A generation job returns a malicious, compromised, or unexpectedly large result URL.
  2. An image, video, enhancement, or pipeline script passes that URL to download_file().
  3. The helper opens the requested output path and streams the response without a byte limit.
  4. A server can send an extremely large or indefinite response, or stall during transfer.
  5. The process remains blocked or consumes available disk space until an external limit intervenes.

Impact Assessment

Successful exploitation could:

  • Exhaust storage available to the Agent or user.
  • Cause generated files, logs, or unrelated applications to fail.
  • Keep the process blocked indefinitely.
  • Store content that does not matc ...[truncated 221 chars]
Remediation
View remediation

Remediation Suggestions

  1. Set explicit connection and read timeouts, for example timeout=(5, 60).
  2. Enforce a maximum download size using both Content-Length and a running byte counter while streaming.
  3. Abort the transfer and remove the partial file when the configured limit is exceeded.
  4. Validate response content types against the expected image or video formats.
  5. Verify file signatures after download rather than trusting the filename extension or HTTP header alone.
  6. Restrict result URLs to approved HTTPS storage domains where the Krea API contract permits it.
  7. Write to a temporary file and atomically rename it only after successful validation.
  8. Check available disk space before downloading large video or enhancement results.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (24)

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

The code behavior is narrower than the declared description. This script only implements image generation and related options. It does not generate videos, upscale images, train LoRA styles, or orchestrate multi-step pipelines. It can apply an existing style ID during generation, but that is not the same as training a LoRA style. There is no evidence of unrelated or hidden resource access beyond Krea API usage and downloading generated images. Because the declared purpose presents the skill as a broad multi-capability toolkit while the actual supplied code chunk only covers one subset, this is a material description-to-behavior mismatch for the provided code chunk.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

This code chunk's purpose is narrowly focused on discovery/listing of Krea API models by downloading the OpenAPI spec and extracting POST endpoints under /generate/image/, /generate/video/, and /generate/enhance/. It outputs model metadata in text or JSON. There are no API calls to generation, enhancement, video creation, or LoRA training endpoints beyond reading the spec itself, and no orchestration logic for pipelines. Therefore, the declared description materially overstates and misrepresents the behavior of the supplied code chunk.

Content

No source excerpt is available for this finding.

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
90% confidence
Finding

Exposing a --skip-validation option for training image URLs weakens a safety check that is meant to vet remote inputs before submission. In an agent setting, this can enable processing of attacker-controlled or malformed URLs, increase SSRF-like risk through server-side fetch behavior, or cause unintended transmission of unverified resources to the external API.

Content

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

md
| `--max-train-steps` | Max training steps | 1000 |
| `--batch-size` | Training batch size | 1 |
| `--timeout` | Polling timeout in seconds | 3600 |
| `--skip-validation` | Skip URL HEAD-check validation | false |
| `--output-dir` | Directory to save training manifest | — |
| `--api-key` | Krea API token | — |

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
80% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · scripts/train_style.py (reported line 66)May include surrounding context.

python
parser.add_argument("--max-train-steps", type=int, default=1000, help="Max training steps (default: 1000)")
    parser.add_argument("--batch-size", type=int, default=1, help="Batch size (default: 1)")
    parser.add_argument("--timeout", type=int, default=3600, help="Polling timeout in seconds (default: 3600)")
    parser.add_argument("--skip-validation", action="store_true", help="Skip URL HEAD-check validation")
    parser.add_argument("--output-dir", help="Directory to save training manifest")
    parser.add_argument("--api-key", help="Krea API token")
    args = parser.parse_args()

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
80% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · scripts/train_style.py (reported line 93)May include surrounding context.

python
parser.add_argument("--max-train-steps", type=int, default=1000, help="Max training steps (default: 1000)")
    parser.add_argument("--batch-size", type=int, default=1, help="Batch size (default: 1)")
    parser.add_argument("--timeout", type=int, default=3600, help="Polling timeout in seconds (default: 3600)")
    parser.add_argument("--skip-validation", action="store_true", help="Skip URL HEAD-check validation")
    parser.add_argument("--output-dir", help="Directory to save training manifest")
    parser.add_argument("--api-key", help="Krea API token")
    args = parser.parse_args()

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding

The skill instructs the agent to use shell commands, network access, environment variables, and file writes, but it does not declare any explicit tool scope or allowed-tools constraints. That increases the chance the agent will execute broader capabilities than the user expects, especially when handling prompts, local file paths, API keys, and output files.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

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

md
---
name: krea-ai
description: "Generate images, videos, upscale/enhance images, and train LoRA styles using the Krea.ai API. Supports 20+ image models (Flux, Imagen, GPT Image, Ideogram, Seedream), 7 video models (Kling, Veo, Hailuo, Wan), and 3 upscalers (Topaz up to 22K). Use when the user wants to generate images, create videos, upscale images, train custom LoRA styles, or run multi-step creative pipelines."
license: MIT
---

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill tells users to send prompts, image URLs, local file paths, and training image sources to Krea.ai, but it does not clearly warn that this data leaves the local environment and is transmitted to a third-party API. This can cause unintended disclosure of sensitive prompts, private media, internal URLs, or local-path-derived content.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The script accepts --start-image and --end-image as either URLs or local file paths, then passes them through ensure_image_url() before sending the request to the Krea API. In this creative-generation skill, that means a user can unintentionally upload local images to a third-party service with no explicit consent prompt or clear warning that local files will leave the machine.

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/krea_helpers.py (reported line 418)May include surrounding context.

python
delays = [5, 15, 45]

    for attempt in range(max_retries + 1):
        r = requests.post(f"{API_BASE}{endpoint}", headers=headers, json=body)
        if r.ok:
            return r.json()
        if r.status_code == 429 and attempt < max_retries:

Tainted flow: 'url' from requests.post (line 529, network input) → requests.get (network output)

Medium
Category
Data Flow
Confidence
81% confidence
Finding

download_file fetches an arbitrary URL and writes the response to disk without validating scheme, host, size, or content type. In context, URLs may come from remote API responses, so a compromised service or attacker-controlled value could trigger SSRF-like outbound access or unexpected downloads of large/malicious content to the local filesystem.

Content

Scanner excerpt · scripts/krea_helpers.py (reported line 478)May include surrounding context.

python
def download_file(url, filename):
    """Download a URL to a local file."""
    os.makedirs(os.path.dirname(filename), exist_ok=True) if os.path.dirname(filename) else None
    r = requests.get(url, stream=True)
    r.raise_for_status()
    with open(filename, "wb") as f:
        for chunk in r.iter_content(chunk_size=8192):

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The helper reads a local file and sends its contents to the Krea assets API, which is a privacy-relevant network transmission. Although there are stderr status messages about uploading, there is no explicit warning or confirmation that a local file will be transmitted off-device when a path is supplied.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding

npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

send_notification uses platform-specific desktop notification mechanisms, including subprocess execution of notify-send and osascript. Local desktop notification and OS script invocation are not justified by the manifest's stated purpose of using the Krea API to generate or enhance media.

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/krea_helpers.py (reported line 592)May include surrounding context.

python
try:
        system = platform.system()
        if system == "Linux" and shutil.which("notify-send"):
            subprocess.run(["notify-send", title, message], timeout=5)
        elif system == "Darwin":
            script = f'display notification "{message}" with title "{title}"'
            subprocess.run(["osascript", "-e", script], timeout=5)

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

Subprocess execution is broader than needed for an API media helper and increases local attack surface. In this file, the real risk is concentrated in the osascript invocation, where script text is dynamically constructed from potentially untrusted input; that can turn a notification helper into a local execution primitive.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
88% confidence
Finding

The macOS notification path builds AppleScript by interpolating untrusted title/message data into a script string passed to osascript. If an attacker can influence those values, they may break out of the quoted string and inject additional AppleScript commands, leading to local command/script execution in the user's context.

Content

Scanner excerpt · scripts/krea_helpers.py (reported line 595)May include surrounding context.

python
subprocess.run(["notify-send", title, message], timeout=5)
        elif system == "Darwin":
            script = f'display notification "{message}" with title "{title}"'
            subprocess.run(["osascript", "-e", script], timeout=5)
        else:
            print("\a", end="", file=sys.stderr)
    except Exception:

Unsafe Defaults

Medium
Category
Tool Misuse
Confidence
80% confidence
Finding

Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.

Content

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

md
parser.add_argument("--max-train-steps", type=int, default=1000, help="Max training steps (default: 1000)")
    parser.add_argument("--batch-size", type=int, default=1, help="Batch size (default: 1)")
    parser.add_argument("--timeout", type=int, default=3600, help="Polling timeout in seconds (default: 3600)")
    parser.add_argument("--skip-validation", action="store_true", help="Skip URL HEAD-check validation")
    parser.add_argument("--output-dir", help="Directory to save training manifest")
    parser.add_argument("--api-key", help="Krea API token")
    args = parser.parse_args()

Unsafe Defaults

Medium
Category
Tool Misuse
Confidence
80% confidence
Finding

Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.

Content

Scanner excerpt · scripts/train_style.py (reported line 66)May include surrounding context.

python
parser.add_argument("--max-train-steps", type=int, default=1000, help="Max training steps (default: 1000)")
    parser.add_argument("--batch-size", type=int, default=1, help="Batch size (default: 1)")
    parser.add_argument("--timeout", type=int, default=3600, help="Polling timeout in seconds (default: 3600)")
    parser.add_argument("--skip-validation", action="store_true", help="Skip URL HEAD-check validation")
    parser.add_argument("--output-dir", help="Directory to save training manifest")
    parser.add_argument("--api-key", help="Krea API token")
    args = parser.parse_args()

Unsafe Defaults

Medium
Category
Tool Misuse
Confidence
80% confidence
Finding

Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.

Content

Scanner excerpt · scripts/train_style.py (reported line 93)May include surrounding context.

python
parser.add_argument("--max-train-steps", type=int, default=1000, help="Max training steps (default: 1000)")
    parser.add_argument("--batch-size", type=int, default=1, help="Batch size (default: 1)")
    parser.add_argument("--timeout", type=int, default=3600, help="Polling timeout in seconds (default: 3600)")
    parser.add_argument("--skip-validation", action="store_true", help="Skip URL HEAD-check validation")
    parser.add_argument("--output-dir", help="Directory to save training manifest")
    parser.add_argument("--api-key", help="Krea API token")
    args = parser.parse_args()

Unsafe Defaults

Medium
Category
Tool Misuse
Confidence
80% confidence
Finding

Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.

Content

Scanner excerpt · scripts/train_style.py (reported line 90)May include surrounding context.

python
resolved_urls.append(ensure_image_url(url, api_key))

    # Validate URLs are reachable
    if not args.skip_validation:
        bad = validate_urls(resolved_urls)
        if bad:
            print(f"\nError: {len(bad)} URLs failed validation. Fix them or use --skip-validation.", file=sys.stderr)

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
90% confidence
Finding

The markdown instructs running scripts from the user's working directory so outputs are saved there, and later notes that results are downloaded and saved locally. However, it frames this as operational guidance rather than a safety warning about local file writes, which can affect user data and workspace state.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

The manifest describes image/video generation, enhancement, and LoRA training via the Krea.ai API. But every OpenAPI model fetch also triggers check_for_updates(), which contacts raw.githubusercontent.com to look for package updates; that behavior is not part of the user-facing creative operations described in the manifest.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
89% confidence
Finding

This code creates and updates a .pipeline-state.json manifest and later downloads generated outputs to local files, but there is no user confirmation prompt or docstring/comment warning that running the script will persist data on disk. While file output is functionally expected for a pipeline runner, the resume-state file creation is less obvious and the CLI help does not clearly disclose that local state files will be written.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.