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

Content
View full analysis

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
View 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)

Undeclared Tool Scope

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.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.