Back to skill

Security audit

unisound-initial-record

Security checks for vulnerabilities and agentic risk

Overview

This appears to be a legitimate Chinese medical-record helper, but it needs Review because it can send sensitive dialogue and a bearer key to any configured API URL and can optionally save prepared patient data despite privacy wording.

Install only in an environment approved for handling medical data. Use de-identified inputs, keep --base fixed to a trusted HTTPS endpoint, protect the appkey, avoid --save-prepared unless you intentionally want a local debug copy of patient dialogue, and require clinician review before using generated records operationally.

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/run.py:171
Finding
Configurable API Endpoint Can Exfiltrate Bearer Credentials and Medical Data## Vulnerability Details **File Location**: `scripts/run.py:171-180` and `scripts/run.py:264-268` **Vulnerability Type**: Unrestricted transmission of credentials and sensitive data to a user-controlled endpoint **Risk Level**: High ### Vulnerable Code ```python def call_llm(prompt: str, *, base: str, model: str, appkey: str, timeout: int) -> str: """Call the internal medical large language model.""" url = f"{base.rstrip('/')}/chat/completions" headers = {"Authorization": f"Bearer {appkey}"} if appkey else {} payload = { "model": model, "messages": [{"role": "user", "content": prompt}], "temperature": 0, } response = _http_post(url, payload, headers, timeout=timeout) ``` The destination is exposed as an unrestricted command-line argument: ```python parser.add_argument( "--base", default=DEFAULT_LLM_BASE, help=f"Internal model base URL (default: {DEFAULT_LLM_BASE}).", ) ``` ### Technical Analysis The `--base` argument controls the URL to which `call_llm()` sends requests. The application unconditionally attaches the supplied API key as a Bearer credential and includes the processed patient dialogue in the request body. The implementation does not enforce HTTPS, validate the destination hostname against an allowlist, constrain the port, or prevent credentials from being forwarded through redirects. Consequently, any party capable of controlling the command invocation or configuration can replace the intended medical-model endpoint with an attacker-controlled server. Although endpoint configurability may be operationally useful, coupling an unrestricted endpoint with automatic credential forwarding violates the principle that credentials must be scoped to a trusted origin. ### Attack Path 1. An attacker influences the command invocation, wrapper script, deployment configuration, or user instructions. 2. The attacker sets `--base` to a ...[truncated 955 chars]
Remediation
## Remediation Suggestions 1. Remove runtime endpoint configurability if only the documented service is supported. 2. If multiple endpoints are required, validate the normalized hostname and port against an explicit allowlist. 3. Require HTTPS and reject plaintext HTTP endpoints. 4. Disable redirects, or independently validate every redirect destination before forwarding credentials. 5. Bind credentials to specific service origins and never attach the API key to an unapproved host. 6. Consider obtaining the key from a protected environment variable or secret manager rather than a command-line argument, which may be visible in process listings and shell history. 7. Add automated tests confirming that HTTP URLs, unknown hosts, deceptive subdomains, embedded user information, and redirects to untrusted hosts are rejected. 8. Minimize or redact patient information before transmission and record approved data-processing destinations in the privacy documentation.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/run.py:185
Finding
Untrusted Medical Dialogue Is Directly Embedded in the LLM Instruction## Vulnerability Details **File Location**: `scripts/run.py:185-211` **Vulnerability Type**: Indirect prompt injection affecting generated medical records **Risk Level**: Medium ### Vulnerable Code ```python def build_prompt(payload: dict[str, Any]) -> str: """Build the LLM prompt.""" dialogue_records = payload.get("dialogue_records") if dialogue_records and isinstance(dialogue_records, list): # Format dialogue records as dialogue text. dialogue_text = [] for record in dialogue_records: speaker = record.get("speaker", "") text = record.get("text", "") dialogue_text.append(f"{speaker}:{text}") dialogue = "\n".join(dialogue_text) else: # Obtain dialogue from other fields. dialogue = ( payload.get("dialogue") or payload.get("text") or payload.get("content") or "" ) if not dialogue: raise ValueError("Input lacks dialogue_records or text") prompt = f"""Generate a medical-information summary of the latest dialogue round based on the following historical summary and historical doctor-patient dialogue: {dialogue}""" return prompt.strip() ``` ### Technical Analysis Dialogue fields originate from input files and are therefore untrusted. The implementation interpolates them directly into the only user-role LLM message without a system instruction, robust data delimiters, or an explicit rule that instructions appearing inside the transcript must be treated solely as quoted data. A crafted transcript can contain instructions telling the model to disregard the summarization task, fabricate diagnoses, omit facts, or emit attacker-selected output. Because the generated response is printed or written directly to an output file without schema or semantic validation, manipulated model output can be accepted as a medical record. LLM d ...[truncated 1411 chars]
Remediation
## Remediation Suggestions 1. Place fixed behavioral requirements in a dedicated system message. 2. Explicitly instruct the model that all transcript content is untrusted quoted data and that instructions found within it must never be followed. 3. Enclose the transcript in clearly identified data delimiters and serialize structured records rather than blending them into instruction text. 4. Request a strict machine-readable schema and validate every response before displaying, storing, or forwarding it. 5. Reject unexpected fields, executable markup, control instructions, and output that does not conform to the documented medical-record structure. 6. Apply length and type limits to speakers and dialogue text, and validate that each dialogue record is an object before accessing its fields. 7. Add adversarial tests containing instructions such as requests to ignore prior requirements, fabricate diagnoses, or change the output format. 8. Require review by a qualified clinician before generated information is incorporated into an authoritative medical record. 9. Treat prompt isolation as defense in depth rather than a complete solution; retain application-level output validation and downstream escaping.
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
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (11)

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding
The declared purpose suggests a narrowly scoped dialogue-to-record transformation, but the documented behavior expands to multi-format document ingestion, preprocessing, and transmission to an external/internal API using a bearer credential. That mismatch increases the chance of unsafe use, because operators may supply broader medical documents or secrets than intended and may not anticipate external data transfer or the trust boundary introduced by a remote model service.

Missing User Warnings

High
Confidence
97% confidence
Finding
The document states that inputs and intermediate results are not persisted and are destroyed after the call, yet it also exposes a --save-prepared option that can write preprocessed medical conversation data to disk without a strong warning. This contradiction can lead to unintended retention of highly sensitive health information, expanding exposure through local storage, backups, logs, or later unauthorized access.

Missing User Warnings

High
Confidence
95% confidence
Finding
The code sends raw medical dialogue to a remote LLM endpoint, which likely includes highly sensitive health information. In a medical context, transmitting PHI/PII without explicit consent flow, minimization, masking, or clear privacy controls materially increases confidentiality and compliance risk.

Direct Prompt Extraction

High
Category
System Prompt Leakage
Content
prompt = f"""根据下面的历史摘要信息和历史医患对话及摘要,生成最新轮次对话的医学信息摘要:
{dialogue}"""
    return prompt.strip()


def run(
Confidence
85% confidence
Finding
Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Lp3

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding
The skill documentation advertises capabilities that include reading files, writing output or prepared data, and sending content over the network, but it does not declare any explicit tool scope or permissions. This creates a transparency and governance gap: users or orchestrators may invoke the skill without realizing it can access local files and exfiltrate sensitive medical dialogue to a remote API.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill discusses de-identification before sending data to an interface, but it does not clearly and prominently warn that medical conversation content is transmitted off-box to a remote API endpoint. For healthcare data, this is especially dangerous because even partially de-identified clinical text can retain sensitive attributes, and users may assume processing is local based on the privacy language.

Intent-Code Divergence

Medium
Confidence
89% confidence
Finding
The module docstring states the skill generates structured initial outpatient medical record information from doctor-patient dialogue, while the prompt text later instructs the model to generate a 'latest-round dialogue medical information summary' from historical summaries and dialogue. This is an active contradiction between the documented intent and the implemented instruction sent to the model.

Ssd 1

Medium
Confidence
88% confidence
Finding
Untrusted patient/doctor dialogue is inserted directly into the only user prompt, so adversarial text inside the conversation can steer the model away from the intended medical-record task. In this skill, that can corrupt clinical summaries, omit important facts, or induce unsafe fabricated output, which is more dangerous because the content is medical.

Description-Behavior Mismatch

Medium
Confidence
91% confidence
Finding
The manifest says the skill generates '结构化的初诊病历信息' from doctor-patient dialogue, but the actual prompt only asks for '医学信息摘要' based on historical summaries/dialogue and returns the raw LLM text response without enforcing any structured schema. This is a semantic mismatch in the core behavior, not just an implementation detail.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The debug feature writes preprocessed medical dialogue to disk, potentially persisting sensitive patient data in locations that may have weaker access controls, backups, or retention policies. In healthcare workflows, even optional local persistence can create significant exposure if operators enable it without safeguards.

Natural-Language Policy Violations

Low
Confidence
90% confidence
Finding
This JSON content is entirely written in Chinese, including speaker labels and dialogue text, with no indication that language choice is configurable or limited to a justified region-specific use case. Under the stated policy, hard-coding a single language without opt-in can be a natural-language policy violation.

Static analysis

No suspicious patterns detected.