Back to skill

Security audit

unisound-med-teach

Security checks for vulnerabilities and agentic risk

Overview

The skill appears to be a real clinical teaching helper, but it can send medical questions and an API key to any configured model endpoint without strong scoping.

Install only if you are comfortable sending de-identified clinical teaching prompts to the configured model provider. Keep --api-url on a trusted endpoint, use a scoped key, avoid real patient identifiers, and be careful with --output on shared or backed-up systems.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/run.py:76
Finding
Unrestricted API Endpoint Can Disclose Credentials and Medical Data## Vulnerability Details **File Location**: `scripts/run.py`, lines 76–82, with attacker-controlled configuration accepted at line 204 and passed to the request at lines 260–268 **Vulnerability Type**: Unrestricted transmission of credentials and sensitive data to a user-configurable endpoint **Risk Level**: High ### Vulnerable Code ```python req = Request( api_url, data=json.dumps(payload, ensure_ascii=False).encode("utf-8"), headers={ "Content-Type": "application/json", "Authorization": f"Bearer {appkey}", }, ) resp = urlopen(req, timeout=timeout) ``` The endpoint is exposed as an unrestricted command-line argument: ```python p.add_argument("--api-url", default=DEFAULT_API_URL, help="OpenAI compatible endpoint URL") ``` The unvalidated value and sensitive inputs are then passed to `call_llm`: ```python out["answer"] = call_llm( api_url=args.api_url, model=args.model, appkey=args.appkey, system_prompt=args.system_prompt, user_prompt=user_prompt, temperature=float(args.temperature), timeout=int(args.timeout), ) ``` ### Technical Analysis The `--api-url` argument permits an arbitrary URL, but the program does not validate its scheme, hostname, port, resolved IP address, or redirect destination. `call_llm` sends an `Authorization: Bearer` header containing the supplied API key and a JSON body containing the complete medical question to this destination. Consequently, an attacker who controls the command invocation, configuration, wrapper script, or instructions copied by a user can redirect the request to an attacker-controlled endpoint. That endpoint receives both the credential and the potentially sensitive clinical content. The unrestricted URL also creates a server-side request forgery-like primitive in execution environments where the skill has access to internal or loopback services. Actual access remains limited to destinations reachable with the process's existing network privileges. Re ...[truncated 1920 chars]
Remediation
## Remediation Suggestions 1. Remove `--api-url` if endpoint customization is not a strict functional requirement, and use only the trusted constant endpoint. 2. If customization is required, validate the parsed URL before constructing the request: - Require the `https` scheme. - Permit only explicitly approved hostnames and ports. - Reject URLs containing embedded credentials. - Reject loopback, link-local, private, multicast, reserved, and unspecified IP destinations unless explicitly required. 3. Resolve the hostname and verify every resolved address against the network policy. Account for DNS rebinding by validating the destination used for the actual connection. 4. Disable automatic redirects or validate each redirect target against the same scheme, hostname, port, and IP allowlist. 5. Ensure the `Authorization` header is never forwarded when a redirect changes the origin. 6. Separate credentials by endpoint. Do not send a production API key to any endpoint other than the service for which it was issued. 7. Add automated tests confirming rejection of: - Plain HTTP URLs. - Unapproved external hosts. - Loopback and private-network addresses. - Redirects to unapproved destinations. - URLs with embedded credentials. 8. Continue instructing users to de-identify medical content, but do not rely on documentation as the primary control; enforce trusted destinations in code. 9. Revoke and rotate any API key that may previously have been transmitted to an untrusted endpoint.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • System Prompt LeakageDirect Leakage, Indirect Extraction, Tool-Based Exfiltration
  • 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)

Lp3

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding
The skill documentation declares no explicit tool scope or permission boundaries even though the implementation is described as reading local files/stdin, writing output files, and making outbound network requests to a remote model API. This creates an unnecessary trust gap: integrators and reviewers cannot easily enforce least privilege, and a caller may expose broader filesystem or network access than intended.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The module docstring and embedded prompts are written as a Chinese-only clinical case generation skill, and the default system prompt explicitly instructs the model in Chinese. There is no indication that users may choose another language or that the locale restriction is required for a region-specific compliance reason.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The skill sends user-supplied clinical questions to an external HTTPS API, and those questions may contain sensitive health or patient information. Because the code provides no notice, consent flow, redaction, or data-classification guard before transmission, operators may unknowingly exfiltrate regulated or confidential medical data to a remote service.

Missing User Warnings

Low
Confidence
87% confidence
Finding
The tool can persist both the original clinical question and model output to disk via --output without warning the user that potentially sensitive medical content will be stored locally. This increases the risk of unintended disclosure through shared filesystems, backups, logs, or weak file permissions.

Static analysis

No suspicious patterns detected.