Back to skill

Security audit

Infographic creator socials

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly coherent for making infographics, but one CLI path can read an arbitrary prompt file and send its contents to OpenAI, so it needs review before install.

Install only if you are comfortable with prompts, logos, screenshots, and avatars being uploaded to OpenAI. Use a project-scoped API key with spending limits, keep sensitive files out of prompt paths and assets, prefer prompts under the intended infographics/prompts directory, and pin dependencies before operational use.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/generate.py:130
Finding

Unrestricted Prompt File Read Can Disclose Local Files to OpenAI

Content
View full analysis

Vulnerability Details

File Location: scripts/generate.py:85-97, 130-131
Vulnerability Type: Arbitrary local file disclosure through an unrestricted CLI path
Risk Level: Medium

Vulnerable Code

python
if reference_images:
    files = []
    assets_root = assets_dir.resolve()
    for fname in reference_images:
        candidate = Path(fname)
        if candidate.is_absolute() or ".." in candidate.parts or candidate.name != fname:
            raise ValueError(
                f"Invalid reference image {fname!r}: must be a bare filename inside assets_dir."
            )
        p = (assets_dir / fname).resolve()
        if assets_root not in p.parents and p != assets_root:
            raise ValueError(
                f"Reference image {fname!r} resolves outside assets_dir ({assets_root})."
            )
        if not p.exists():
            raise FileNotFoundError(f"Reference image not found: {p}")
        files.append(open(p, "rb"))
    try:
        result = client.images.edit(
            model=model,
            image=files,
            prompt=prompt,
            size=api_size,
            quality=quality,
        )
python
else:
    result = client.images.generate(
        model=model,
        prompt=prompt,
        size=api_size,
        quality=quality,
    )
python
prompt = Path(args.prompt_file).read_text()
render(
    prompt=prompt,
    out_name=args.out_name,
    size=args.size,
    reference_images=args.reference_images or None,
    out_dir=args.out_dir,
    assets_dir=args.assets_dir,
    model=args.model,
    quality=args.quality,
)

Technical Analysis

The prompt_file CLI argument is converted directly into a Path and read without validating where it resolves. The implementation does not reject absolute paths, parent-directory traversal, or symbolic links that resolve outside the intended in ...[truncated 1816 chars]

Remediation
View remediation

Remediation Suggestions

  • Define a trusted prompt root, such as infographics/prompts, and resolve both the root and requested file before reading.
  • Reject absolute paths, .. components, non-regular files, and resolved paths outside the trusted root.
  • Restrict accepted extensions to the formats the workflow requires, such as .txt or .md.
  • Explicitly address symbolic links by rejecting them or verifying that the final resolved target remains under the trusted root.
  • Prefer receiving prompt content through a controlled API parameter or standard input rather than accepting an arbitrary filesystem path.
  • Apply a reasonable prompt size limit before reading or transmitting the file.
  • Preserve the existing user warning as defense in depth, but do not rely on documentation as the primary control.

Example hardening pattern:

python
prompts_root = Path("infographics/prompts").resolve()
candidate = Path(args.prompt_file)

if candidate.is_absolute() or ".." in candidate.parts:
    raise ValueError("Prompt file must be inside infographics/prompts")

prompt_path = (prompts_root / candidate).resolve()

if prompts_root not in prompt_path.parents:
    raise ValueError("Prompt file resolves outside the permitted directory")
if not prompt_path.is_file() or prompt_path.suffix not in {".txt", ".md"}:
    raise ValueError("Prompt file must be a regular .txt or .md file")

prompt = prompt_path.read_text(encoding="utf-8")

T08 · Insecure Dependencies

Note
Location
SKILL.md:111
Finding

Unpinned Python Dependencies Create Supply-Chain and Reproducibility Risk

Content
View full analysis

Vulnerability Details

File Location: SKILL.md:19-23, 111-115
Vulnerability Type: Unpinned third-party dependency installation
Risk Level: Low

Vulnerable Code

yaml
metadata:
  requires:
    env:
      - OPENAI_API_KEY
    bins:
      - python3
      - curl
    pip:
      - openai
      - cairosvg
bash
python3 -m venv .venv && source .venv/bin/activate
pip install --quiet "openai>=1.0" "cairosvg>=2.7"
python3 -c "import cairosvg; cairosvg.svg2png(url='in.svg', write_to='out.png', output_width=512)"

Technical Analysis

The Skill declares openai and cairosvg without exact versions and separately instructs installation using open-ended minimum-version constraints. No lockfile or package hashes are provided.

Consequently, each installation can resolve to different future package versions and transitive dependency graphs. Python package installation may execute package build or installation logic locally. If a permitted future release or transitive dependency is compromised, or if the configured package index is untrusted, malicious code could execute with the privileges of the user running the installation.

The packages named in the project are legitimate and there is no evidence in the audited files that they are currently malicious. This finding concerns the absence of version and integrity controls rather than a confirmed malicious dependency.

Attack Path

  1. The Skill is initialized in a new virtual environment.
  2. pip resolves the newest releases satisfying openai>=1.0 and cairosvg>=2.7, including their transitive dependencies.
  3. A compromised or unexpectedly changed permitted release is downloaded from the configured package index.
  4. Package build or installation code executes locally, or compromised runtime code executes when openai or cairosvg is imported.
  5. Such code runs with the permissions and environment available to the Skill p ...[truncated 657 chars]
Remediation
View remediation

Remediation Suggestions

  • Pin reviewed, exact versions of all direct dependencies instead of using bare names or open-ended minimum versions.
  • Generate and commit a lockfile that also fixes transitive dependency versions.
  • Use hash-verified installation, such as a requirements file containing --hash entries and installation with pip install --require-hashes.
  • Keep installation inside a dedicated virtual environment and retain the existing prohibition on unapproved system-wide installation.
  • Explicitly use the trusted official package index and prevent fallback to uncontrolled indexes where the execution environment permits it.
  • Review and update pinned versions through a controlled dependency-update process with security scanning and tests.
  • Ensure the dependency metadata and documented installation command use the same exact versions so the declared and actual environments cannot drift.
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Memory PoisoningPersistent Context Injection, Context Window Stuffing, Memory Manipulation
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (6)

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

python
for fname in reference_images:
            # Reject anything that isn't a plain filename inside assets_dir.
            # pathlib's `/` operator silently resets on an absolute operand
            # (`Path("assets") / "/etc/passwd"` -> `/etc/passwd`), so without
            # this guard a prompt-injected caller could exfiltrate arbitrary
            # files via the OpenAI images.edit upload.
            candidate = Path(fname)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding

The skill performs file reads and writes, persists state, and directs use of local reference files and outputs, but it declares no explicit tool/permission scope. In agent environments, missing scope boundaries can let the skill be invoked with broader filesystem access than intended, increasing the chance of unintended local file exposure or modification through prompt-driven behavior.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The trigger conditions are broad enough to capture many generic image-design requests, which can cause the skill to activate unexpectedly and begin reading/writing project files or fetching external assets without the user intending to use this workflow. In an agent ecosystem, overly broad invocation increases the chance of inappropriate tool use and accidental data handling in contexts outside the narrow infographic task.

Content

No source excerpt is available for this finding.

Context Window Stuffing

Medium
Category
Memory Poisoning
Confidence
85% confidence
Finding

Skill attempts to fill the context window with filler content, displacing legitimate instructions and safety constraints. This can degrade agent performance or bypass safety boundaries.

Content

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

md
### Step 4 — Copywriting (ask the user)

The visual quality is bounded by the copy quality. Ask 3–5 targeted questions to fill the prompt. Tailor them to the chosen layout. Examples:

- **Title** (≤6 words, declarative or metaphorical) — what's the punch?
- **Subtitle** (handwritten line, one conversational sentence)

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

L102 says to ask targeted questions to 'fill the prompt,' which is consistent with collecting user-provided text, but L110 explicitly says 'Do NOT generate copy yourself. Wait for the user.' That directly conflicts with the manifest claim that the skill owns 'copywriting refinement,' and with the earlier workflow wording if interpreted as the skill producing copy rather than only eliciting it.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

The manifest says the skill owns the full pipeline including 'copywriting refinement through targeted questions,' which implies an active role in shaping wording. However, the workflow later instructs 'Do NOT generate copy yourself. Wait for the user' (L110), meaning the skill is limited to elicitation rather than actual copywriting or refinement in code/documented behavior.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.