Back to skill

Security audit

SciDraw AI Scientific Illustration

Security checks for vulnerabilities and agentic risk

Overview

The skill is coherent for generating scientific figures, but it allows credentials and prompts to be sent to arbitrary HTTP(S) API endpoints, which needs review before installation.

Install only if you trust the SciDraw provider and your local environment. Do not include confidential, regulated, or unpublished research details in prompts unless that is acceptable for SciDraw processing. Avoid setting SCIDRAW_API_BASE_URL; if it has ever pointed to an untrusted or HTTP endpoint, rotate the API key.

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/scidraw_generate.py:192
Finding

Arbitrary API endpoint override can disclose the API credential and confidential prompts

Content
View full analysis
Dict[str, Any]: headers = { "Accept": "application/json", "Authorization": f"Bearer {api_key}", "User-Agent": "SciDraw-Skill/1.0", } body = None if payload is not None: body = json.dumps(payload).encode("utf-8") headers["Content-Type"] = "application/json" ``` ```python api_base_url = os.getenv( "SCIDRAW_API_BASE_URL", DEFAULT_API_BASE_URL ).strip().rstrip("/") if not api_base_url.startswith(("https://", "http://")): die("SCIDRAW_API_BASE_URL must be an HTTP(S) URL.") prompt = read_prompt(args.prompt, args.prompt_file) out_path = Path(args.out).expanduser().resolve() request_payload = { "prompt": prompt, "aspect_ratio": args.aspect_ratio, "resolution": args.resolution, "count": args.count, } idempotency_key = f"scidraw-skill-{uuid.uuid4().hex}" started = time.monotonic() try: job = api_request( "POST", f"{api_base_url}/images/generations", api_key, payload=request_payload, extra_headers={ "Idempotency-Key": idempotency_key, "Prefer": "wait=30", }, ) ``` ### Technical Analysis The client obtains its API destination from `SCIDRAW_API_BASE_URL` and accepts any URL beginning with `http://` or `https://`. It does not validate the normalized hostname, port, or trust relationship with SciDraw. Every request made through `api_request()` attaches `SCIDRAW_API_KEY` as an `Authorization: Bearer` credential. Generation requests also transmit the complete prompt, which may contain unpublished re ...[truncated 1755 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/scidraw_generate.py:150
Finding

Unvalidated API-supplied download URLs permit server-side request forgery and unsafe file retrieval

Content
View full analysis
None: request = urllib.request.Request( url, headers={"User-Agent": "SciDraw-Skill/1.0"}, method="GET", ) destination.parent.mkdir(parents=True, exist_ok=True) try: with urllib.request.urlopen(request, timeout=120) as response: destination.write_bytes(response.read()) except (urllib.error.HTTPError, urllib.error.URLError) as exc: raise RuntimeError(f"Could not download generated image: {exc}") from exc ``` ```python saved_files: List[str] = [] for index, item in enumerate(files): url = str(item.get("url") or "") if not url: raise RuntimeError("SciDraw AI returned a file without a URL.") file_format = str(item.get("format") or "png") destination = target_path(out_path, index, len(files), file_format) download_file(url, destination) saved_files.append(str(destination)) ``` ### Technical Analysis The script treats every output URL returned by the API as trusted and passes it directly to `urllib.request.urlopen()`. It does not restrict the URL scheme or hostname, validate redirect destinations, resolve and reject private addresses, or ensure that the response is an image. A malicious or compromised API can therefore instruct the client to request loopback, link-local, private-network, cloud metadata, or other attacker-selected resources reachable from the user's machine. The unrestricted API endpoint override makes this path directly exploitable by a malicious configured backend. The response is read into memory in a single operation and then written to disk. No maximum response size, image signature validation, or content-type validation is applied. A server can co ...[truncated 1691 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (4)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill instructs use of environment variables, file reads/writes, and outbound network access to call an external API, but it does not declare any explicit tool scope or permission boundaries. This creates a real security governance gap: an agent or runtime may grant broader capabilities than users expect, increasing the risk of unintended file access, secret exposure, or network use without clear consent.

Content

No source excerpt is available for this finding.

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
80% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

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

md
key creation link above.
- Do not silently substitute another image provider. Use a different backend
  only when the user explicitly requests it.
- Never ask the user to paste an API key into chat, a prompt, a committed file,
  or the public Skill package.

## Configure the SciDraw AI API

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The script sends the full user prompt to an external third-party API, but it does not clearly disclose that data exfiltration to the user at runtime. In this skill context, prompts may contain unpublished research details, confidential figures, or sensitive biomedical/project information, so silent transmission creates a meaningful confidentiality risk even though external API use is core to the tool’s function.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

The section header and resource list at L037-L043 are presented only in Chinese, while the rest of the skill is primarily in English. This imposes a language shift on users without opt-in or justification, which matches the language/locale policy violation criteria.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.