Back to skill

Security audit

unisound-referral-guidance

Security checks for vulnerabilities and agentic risk

Overview

The skill has a legitimate medical referral purpose, but it can send raw patient information and an API key to configurable remote services despite claiming de-identification.

Review before installing. Use only with de-identified patient summaries, avoid including names or other identifiers, do not override --base except to an approved HTTPS endpoint, and use a limited, revocable API key. Treat the output as clinical decision support, not a substitute for medical judgment.

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:142
Finding
Patient Medical Data Is Transmitted Without Enforced De-identification## Vulnerability Details **File Location**: `scripts/run.py:142-149` **Related Documentation**: `SKILL.md:29-31` **Vulnerability Type**: Sensitive medical data disclosure caused by missing de-identification controls **Risk Level**: High **Category**: T09: Insecure Skill Coding Practices ### Vulnerable Code ```python def run_referral(case_summary: str, llm, output_path: str = "") -> int: prompt = f"""请根据以下患者病情摘要,给出转诊指导建议。 【患者病情】 {case_summary.strip()} 请严格按照要求输出 JSON + 摘要。""" print("正在评估患者转诊需求...") result = llm([sys_msg(SYSTEM_PROMPT), user_msg(prompt)]) ``` The documentation states: ```markdown - **严格脱敏**:发送前对可识别身份信息进行脱敏处理。 - **不做本地持久化**:仅在内存中短暂处理;**本次调用结束即销毁**。 ``` ### Technical Analysis The implementation interpolates the entire contents of `case_summary` into the LLM prompt and submits it to the configured remote service. No code identifies, removes, masks, or validates direct and indirect patient identifiers before transmission. Because `load_input` accepts arbitrary text and JSON records, submitted content can include names, identification numbers, telephone numbers, addresses, medical record numbers, dates of birth, or other protected health information. The documented instruction that users should de-identify records is not a technical safeguard, and the stronger statement that strict de-identification occurs before sending is not enforced by the implementation. This creates a confidentiality weakness at the trust boundary between the local clinical environment and the external LLM endpoint. It is particularly consequential because the information is medical data and may be subject to contractual, regulatory, and organizational privacy requirements. ### Attack Path 1. An operator supplies a text or JSON input containing a patient case with identifying information. 2. `load_input` reads and returns that information without sanitization. 3. `run_referral` inserts the complet ...[truncated 1063 chars]
Remediation
## Remediation Suggestions 1. Implement local de-identification before constructing the LLM prompt. At minimum, detect and mask common identifiers such as names, government identifiers, phone numbers, email addresses, postal addresses, medical record numbers, and exact dates not required for referral decisions. 2. Prefer structured input with an explicit allowlist of medically necessary fields instead of transmitting arbitrary records. 3. Reject records containing likely identifiers when safe automatic redaction cannot be guaranteed. Return a clear error requesting sanitized input. 4. Display the sanitized payload for operator confirmation before sending it when the workflow permits human review. 5. Add automated tests covering direct identifiers, indirect identifiers, nested JSON fields, and free-form clinical notes. 6. Ensure the remote provider's retention and logging controls are suitable for medical information and are reflected accurately in the documentation. 7. Revise `SKILL.md` so it does not claim strict de-identification unless that control is actually implemented and verified. 8. Document the external transmission boundary, the receiving service, retention behavior, and residual re-identification risks.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/run.py:44
Finding
Unrestricted LLM Base URL Can Exfiltrate the API Key and Patient Records## Vulnerability Details **File Location**: `scripts/run.py:44-49` **Related Configuration Location**: `scripts/run.py:203` **Vulnerability Type**: Unvalidated destination URL used for credential-bearing sensitive-data requests **Risk Level**: High **Category**: T09: Insecure Skill Coding Practices ### Vulnerable Code ```python def make_llm_caller(appkey: str, base: str = DEFAULT_LLM_BASE, model: str = DEFAULT_LLM_MODEL, timeout: int = 0): url = f"{base.rstrip('/')}/chat/completions" headers = {"Authorization": f"Bearer {appkey}"} def llm(messages: List[Dict[str, str]]) -> str: payload = {"model": model, "messages": messages, "temperature": 0} resp = _http_post(url, payload, headers, timeout=timeout) ``` The destination is exposed directly as a command-line argument: ```python parser.add_argument("--base", default=DEFAULT_LLM_BASE, help=f"内部大模型 base URL(默认:{DEFAULT_LLM_BASE})。") ``` ### Technical Analysis The `--base` argument accepts an arbitrary URL. `make_llm_caller` appends `/chat/completions` and sends both of the following to that destination: - The API key in the `Authorization: Bearer` header. - The complete LLM message payload, including the patient's clinical record. The code does not require HTTPS, validate the hostname, enforce an endpoint allowlist, or bind credentials to the expected origin. Consequently, an attacker-controlled `--base` value can convert a normal referral request into credential and medical-data exfiltration. A plain HTTP destination also permits network observers to intercept or modify the request. In addition, the use of the standard URL opener is not accompanied by an explicit policy preventing cross-origin redirects from affecting sensitive requests. Destination and redirect handling should therefore be constrained before attaching authentication material. ### Attack Path 1. An attacker persuades an operator or deployment administrat ...[truncated 1848 chars]
Remediation
## Remediation Suggestions 1. Remove arbitrary endpoint configuration if custom LLM providers are not an essential requirement. 2. Otherwise, enforce an explicit allowlist of approved HTTPS hostnames and ports before constructing or sending the request. 3. Reject non-HTTPS URLs whenever an authorization credential or patient data will be transmitted. 4. Parse the URL with `urllib.parse.urlsplit` and validate the normalized scheme, hostname, port, user-information component, and resolved destination. Do not rely on string-prefix checks. 5. Bind each credential to its intended origin. Never send the internal service's `appkey` to a custom endpoint. 6. Disable redirects for authenticated requests or validate every redirect target and strip authorization headers whenever the origin changes. 7. Consider certificate or public-key pinning where the operational environment can support it. 8. Use short-lived, least-privilege API credentials with service-side audience restrictions, quotas, and rapid revocation. 9. Record the approved destination hostname in security audit logs without logging credentials or patient prompts. 10. Add tests confirming rejection of HTTP URLs, unapproved hosts, deceptive hostnames, embedded credentials, unusual ports, and cross-origin redirects.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (4)

Lp3

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding
The skill advertises and documents capabilities that involve reading local input files, optionally writing output files, and making network requests to an external API, but it does not declare any explicit tool scope or permissions. This creates a least-privilege and governance gap: a host may grant broader access than intended, and users cannot easily audit what resources the skill is expected to touch, which is more sensitive here because the data is medical and may include patient information.

Natural-Language Policy Violations

Medium
Confidence
90% confidence
Finding
The natural-language content and usage instructions are presented only in Chinese, which effectively forces a specific language on users. The policy allows locale constraints only when they are explicitly optional or clearly justified as region-specific; this file does not state such a justification or offer an opt-in choice.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The script sends raw patient case summaries to a remote LLM service via `make_llm_caller(...)->_http_post(...)` without any explicit consent notice, privacy warning, or minimization step at the point of use. Because the content is medical data and may contain sensitive personal health information, this creates a real confidentiality and compliance risk if users provide identifiable details or if the endpoint retains/logs prompts.

Natural-Language Policy Violations

Low
Confidence
83% confidence
Finding
The natural-language instructions, prompts, argument descriptions, and expected outputs are all fixed in Chinese, which effectively enforces a single language experience. The file does not offer user opt-in, locale selection, or documentation that this is intentionally limited to a Chinese-only regional workflow.

Static analysis

No suspicious patterns detected.