Back to skill

Security audit

Prompt to Drawio

Security checks for vulnerabilities and agentic risk

Overview

This diagram skill is mostly coherent, but needs review because it can forward local or URL content to model providers and may automatically run an unpinned Docker image with writable folder access.

Review before installing. Use trusted, pinned install sources where possible; avoid global noninteractive installation; disable ambient dotenv loading with `--no-dotenv` or use a trusted `--dotenv-file`; do not pass secrets, regulated documents, or internal URLs unless your model provider policy permits it; and prefer a local draw.io CLI or `--no-docker-fallback` unless you have vetted the Docker image and mounted directories.

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/prompt_to_drawio.py:1093
Finding

Unrestricted URL ingestion permits SSRF and forwarding of retrieved data to an LLM provider

Content
View full analysis
str: req = request.Request(url, headers={"User-Agent": "drawio-skill/1.0"}) try: with request.urlopen(req, timeout=timeout) as resp: charset = resp.headers.get_content_charset() or "utf-8" html = resp.read().decode(charset, errors="ignore") except Exception as exc: raise SkillRuntimeError(f"Failed to fetch URL {url}: {exc}") from exc parser = SimpleHTMLTextExtractor() parser.feed(html) text = parser.text.strip() if not text: raise SkillRuntimeError(f"URL had no extractable text: {url}") return text ``` ```python for url in urls: page_text = fetch_url_text(url) texts.append(f"[URL: {url}]\n{page_text}") ``` ```python bundle = read_context_bundle(args.file, args.url, args.shape_library) style_note = "Use minimal black/white styling." if args.minimal_style else "Use professional readable styling." user_text = compose_user_text(prompt, bundle, extra_sections=[style_note]) messages = build_messages(GENERATION_SYSTEM_PROMPT, user_text, bundle.image_data_urls) raw_xml = call_chat_completion( messages=messages, model=generation_model, api_key=api_key, base_url=args.base_url, temperature=args.temperature, max_tokens=args.max_tokens, timeout=args.timeout, ) ``` ### Technical Analysis The `--url` option accepts an arbitrary URL and passes it directly to `urllib.request.urlopen`. The implementation does not validate the URL scheme, resolve and inspect the destination address, restrict ports, reject local or private networks, or revalidate redirect destinations. The fetched response is converted to text, incorporated into the model prompt, and ...[truncated 1939 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
README.md:16
Finding

Installation instructions execute an unpinned mutable npm package

Content
View full analysis
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
scripts/prompt_to_drawio.py:1384
Finding

Automatic Docker fallback executes an unpinned image with writable directory mounts

Content
View full analysis
Optional[str]: docker = shutil.which("docker") if not docker: return "Docker not found" in_dir = drawio_file.parent.resolve() out_dir = image_file.parent.resolve() cmd = [ docker, "run", "--rm", "-v", f"{in_dir}:/in", "-v", f"{out_dir}:/out", "jgraph/drawio", "-x", "-f", image_format, "-o", f"/out/{image_file.name}", f"/in/{drawio_file.name}", ] ok, info = run_command(cmd) if ok and image_file.exists(): return "" return info or "Docker drawio export failed" ``` ### Technical Analysis When a local draw.io CLI is unavailable, the runtime automatically executes `jgraph/drawio` without a version tag or immutable digest. Docker therefore resolves a mutable image reference whose effective contents can change independently of this Skill. The entire input and output parent directories are mounted into the container, and both mounts are writable. Rendering requires reading one diagram and writing one output image; granting write access to both complete directories exceeds that minimum requirement. The subprocess call itself uses an argument list rather than a shell, so the reviewed code does not expose a direct shell-injection vulnerability. The risk arises from executing an externally maintained mutable image and exposing broader filesystem paths than necessary. ### Attack Path 1. The referenced container image, registry account, image build pipeline, or mutable tag is compromised. 2. A user requests image export on a system where the local draw.io CLI is unavailable. 3. Unless `-- ...[truncated 825 chars]
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
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • System Prompt LeakageDirect Leakage, Indirect Extraction, Tool-Based Exfiltration
Findings (38)

Credential Access

High
Category
Privilege Escalation
Confidence
94% confidence
Finding

Reading arbitrary .env content is sensitive because .env files commonly contain API keys, tokens, and service endpoints, and this loader imports them automatically into runtime state. In this skill, those values can directly control outbound model destinations and credentials, creating a credential-ingestion and configuration-hijack risk in untrusted workspaces.

Content

Scanner excerpt · scripts/prompt_to_drawio.py (reported line 203)May include surrounding context.

python
try:
        content = path.read_text(encoding="utf-8", errors="ignore")
    except OSError as exc:
        raise SkillRuntimeError(f"Failed to read .env file {path}: {exc}") from exc

    for raw_line in content.splitlines():
        parsed = parse_dotenv_line(raw_line)

Credential Access

High
Category
Privilege Escalation
Confidence
95% confidence
Finding

The upward directory walk for .env discovery means a malicious or unexpected parent directory can influence the skill's runtime credentials and endpoints. This is especially dangerous for CLI tooling run in varied repositories, because simply changing the working directory can alter trust assumptions and cause silent credential or configuration injection.

Content

Scanner excerpt · scripts/prompt_to_drawio.py (reported line 227)May include surrounding context.

python
cwd = Path.cwd().resolve()
    for folder in [cwd, *cwd.parents]:
        candidate = folder / ".env"
        if candidate.exists():
            return candidate
    return None

Credential Access

High
Category
Privilege Escalation
Confidence
92% confidence
Finding

Bootstrapping the project environment before argparse uses environment-backed defaults causes imported .env values to influence model URL, API key, and other sensitive parameters automatically. This compounds the .env trust problem by making the injected configuration active very early and with little visibility beyond a summary message.

Content

Scanner excerpt · scripts/prompt_to_drawio.py (reported line 293)May include surrounding context.

python
argv = preprocess_argv(sys.argv[1:])
    no_dotenv, dotenv_file = parse_bootstrap_flags(argv)

    # Load .env before argparse defaults read os.environ.
    bootstrap = bootstrap_project_env(no_dotenv=no_dotenv, dotenv_file=dotenv_file)
    global DOTENV_BOOTSTRAP_RESULT
    DOTENV_BOOTSTRAP_RESULT = bootstrap

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

python
parser.add_argument(
        "--no-dotenv",
        action="store_true",
        help="Disable automatic .env loading.",
    )
    parser.add_argument(
        "--dotenv-file",

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

python
parser.add_argument(
        "--no-dotenv",
        action="store_true",
        help="Disable automatic .env loading.",
    )
    parser.add_argument(
        "--dotenv-file",

Direct Prompt Extraction

High
Category
System Prompt Leakage
Confidence
85% confidence
Finding

Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Content

Scanner excerpt · scripts/prompt_to_drawio.py (reported line 1166)May include surrounding context.

python
def build_user_content(prompt_text: str, image_data_urls: list[str]) -> str | list[dict[str, Any]]:
    if not image_data_urls:
        return prompt_text
    content: list[dict[str, Any]] = [{"type": "text", "text": prompt_text}]
    for data_url in image_data_urls:
        content.append({"type": "image_url", "image_url": {"url": data_url}})

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill can invoke docker run on the host and bind-mount local directories into a container image, which materially expands host-side attack surface. If the local Docker daemon, image provenance, or mounted paths are not trusted, this can expose sensitive files to the container or enable unsafe code execution outside the Python process.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
95% confidence
Finding

The README instructs users to execute a remotely fetched package via npx skills@latest, which is explicitly unpinned and will always resolve to the newest published version. If the package or one of its dependencies is compromised upstream, users may execute attacker-controlled code during installation.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
95% confidence
Finding

This command again relies on npx skills@latest, causing installation behavior to depend on whatever code is most recently published. In a skill-install context, that means arbitrary package updates can change what executes on the user's machine without review.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
95% confidence
Finding

Using npx skills@latest for agent-specific installation creates a supply-chain execution path with no version stability or reproducibility. A malicious or hijacked upstream release could run code at install time under the user's privileges.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
95% confidence
Finding

The global install example uses the same unpinned npx skills@latest pattern, which is riskier because global installs are often reused across projects and may affect more workflows. Compromise of the installer could lead to persistent malicious tooling on the host.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The README promotes ingesting local files, URLs, images, and PDFs while also requiring network access to an external model provider endpoint, but it does not prominently warn that sensitive local content may be transmitted off-host. In a CLI/agent skill, users may pass confidential architecture diagrams, documents, or screenshots and unintentionally exfiltrate proprietary data.

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.

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.

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.

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.

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.

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.

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.

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.

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.

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.

Skill Enumeration

Medium
Category
Agent Snooping
Confidence
85% confidence
Finding

Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.

Content

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

方案 B:手动安装(Codex 本地)

bash
mkdir -p "$HOME/.codex/skills"
git clone https://github.com/lzfxxx/prompt-to-drawio-skill.git "$HOME/.codex/skills/prompt-to-drawio"

Skill Enumeration

Medium
Category
Agent Snooping
Confidence
85% confidence
Finding

Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.

Content

Scanner excerpt · README.zh-CN.md (reported line 45)May include surrounding context.

方案 B:手动安装(Codex 本地)

bash
mkdir -p "$HOME/.codex/skills"
git clone https://github.com/lzfxxx/prompt-to-drawio-skill.git "$HOME/.codex/skills/prompt-to-drawio"

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The README advertises ingestion of local files, images, PDFs, and URLs, and separately notes network access to model APIs, but it does not clearly warn users that supplied content may be transmitted to external LLM or validation endpoints. In a CLI/agent skill, this omission is significant because users may pass sensitive internal documents or URLs assuming purely local processing, leading to unintended data exfiltration to third-party services.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.