Back to skill

Security audit

unisound-med-clinical-decision

Security checks for vulnerabilities and agentic risk

Overview

This medical LLM skill is mostly coherent, but it can send clinical questions and a bearer API key to any configured endpoint, which needs review before use.

Install only if you control how this script is invoked. Keep --api-url pinned to the intended trusted HTTPS endpoint, use endpoint-specific keys, and do not send identifiable patient information unless your organization has approved that data flow and retention policy.

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:103
Finding
Unrestricted API Endpoint Can Exfiltrate Authentication Credentials and Clinical Data## Vulnerability Details **File Location**: `scripts/run.py:103-119`, `scripts/run.py:227`, and `scripts/run.py:283-291` **Vulnerability Type**: Unrestricted credential-bearing outbound request **Risk Level**: High ### Vulnerable Code ```python def call_llm( *, api_url: str, model: str, appkey: str, system_prompt: str, user_prompt: str, temperature: float, timeout: int, ) -> str: payload = { "model": model, "temperature": temperature, "messages": [ {"role": "system", "content": system_prompt}, {"role": "user", "content": user_prompt}, ], } try: 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 destination is accepted directly from a command-line argument: ```python p.add_argument("--api-url", default=DEFAULT_API_URL, help="OpenAI compatible endpoint URL") ``` The unvalidated value and credential are then passed to the network request: ```python out["answer"] = call_llm( api_url=args.api_url, model=args.model, appkey=args.appkey, system_prompt=system_prompt_for(task_key, args.system_prompt), user_prompt=user_prompt, temperature=float(args.temperature), timeout=int(args.timeout), ) ``` ### Technical Analysis The `--api-url` option permits an operator or integration to select an arbitrary URL. The application does not enforce HTTPS, restrict the destination to trusted model-provider hosts, reject local or private network destinations, or constrain redirects. `call_llm()` sends the following sensitive information to the selected destination: - The model API ...[truncated 2517 chars]
Remediation
## Remediation Suggestions 1. **Use an explicit endpoint allowlist** - Restrict requests to approved HTTPS hostnames and expected paths. - Prefer removing `--api-url` from production deployments if endpoint customization is unnecessary. - Compare normalized hostnames rather than using substring or suffix checks vulnerable to lookalike domains. 2. **Require secure transport** - Reject all schemes except `https`. - Reject URLs containing embedded credentials. - Continue to verify TLS certificates using a trusted certificate store. 3. **Protect against SSRF** - Reject loopback, link-local, private, multicast, and otherwise reserved IP ranges unless explicitly required. - Resolve the destination and validate all resulting addresses. - Account for DNS rebinding by ensuring the connection is made to a validated destination. - Restrict outbound network access at the container, host, or firewall level. 4. **Constrain redirects** - Disable automatic redirects for credential-bearing requests or revalidate every redirect destination. - Never forward the `Authorization` header when the scheme, host, or port changes. 5. **Separate custom endpoints from production credentials** - Require an explicit high-friction confirmation before sending credentials to a non-default endpoint. - Use endpoint-specific, short-lived credentials with minimum privileges. - Do not reuse the production model credential for development or user-selected endpoints. 6. **Reduce sensitive-data exposure** - Add enforcement or validation supporting the documented requirement to de-identify patient data. - Warn users before sending clinical content to any custom endpoint. - Avoid logging credentials, complete prompts, or sensitive response bodies. 7. **Respond to suspected exploitation** - Immediately revoke and rotate any credential that may have been sent to an untrusted endpoint. - Revie ...[truncated 180 chars]
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
88% confidence
Finding
The skill exposes file read, file write, and network-capable behavior via its script interface, but the manifest does not declare any corresponding tool scope or permission boundaries. This creates a least-privilege and transparency failure: integrators may deploy the skill without understanding that it can read local inputs, write outputs, and transmit potentially sensitive clinical data to a remote medical API.

Natural-Language Policy Violations

Medium
Confidence
92% confidence
Finding
The file-level docstring and embedded prompts are written to operate in Chinese, and the system prompt hardcodes Chinese-only instruction text. There is no indication that users may choose another language or that the locale restriction is a documented requirement for a region-specific tool.

Natural-Language Policy Violations

Medium
Confidence
97% confidence
Finding
The system prompt is entirely in Chinese and establishes the assistant's operating behavior in that language, which can enforce a specific locale implicitly. Because the code does not provide a language-selection mechanism or justify a mandatory Chinese locale, this conflicts with the stated language/locale policy criteria.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The code sends the user-supplied clinical question, selected metadata, and authentication material to a remote third-party API endpoint with no built-in consent prompt, data minimization, redaction, or warning to the operator. In a medical context, the question text and `other` metadata can easily contain protected health information or sensitive clinical details, so silent transmission creates a real privacy and compliance risk.

Static analysis

No suspicious patterns detected.