T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/run.py:123
- Finding
- Patient Data Is Transmitted Without the Promised De-identification<![CDATA[ ## Vulnerability Details **File Location**: `scripts/run.py:123-132` **Related Documentation**: `SKILL.md:27-30` **Vulnerability Type**: Sensitive patient-data disclosure caused by missing de-identification **Risk Level**: High ### Vulnerable Code ```python def run_advice(patient_info: str, llm, output_path: str = "") -> int: prompt = f"""请根据以下患者信息,给出常见病诊疗建议。 【患者信息】 {patient_info.strip()} 请严格按照要求输出 JSON + 摘要。""" print("正在分析患者信息并生成诊疗建议...") result = llm([sys_msg(SYSTEM_PROMPT), user_msg(prompt)]) ``` The relevant documentation states that identifiable information will be de-identified before being sent to any model or API. However, the implementation does not contain identifier detection, redaction, pseudonymization, or filtering logic. ### Technical Analysis `load_input()` accepts arbitrary text or JSON-based patient records and returns their content without modification. `run_advice()` then interpolates the complete value of `patient_info` into the LLM prompt. The resulting prompt is sent through `make_llm_caller()` to the configured `/chat/completions` endpoint. Consequently, names, telephone numbers, government identifiers, detailed addresses, medical record numbers, and other protected health information present in the input may be transmitted to a remote service verbatim. This behavior directly conflicts with the documented guarantee of strict de-identification. The use of HTTPS protects the transport channel against ordinary passive interception, but it does not prevent the receiving API operator from obtaining the unredacted data. The caller-controlled `--base` option can also redirect transmission to a different endpoint when an unsafe or incorrect base URL is supplied. ### Attack Path 1. A patient-information file contains clinical data together with direct identifiers. 2. `load_input()` reads and returns the record without sanitization. 3. `run_advice()` inserts the entire record into the prompt using `patient_info.s ...[truncated 870 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Implement local de-identification before constructing the prompt. Detect and redact, at minimum: - Names - Telephone numbers and email addresses - Government and insurance identifiers - Medical record numbers - Exact addresses - Other organization-specific patient identifiers 2. Use an allowlisted structured input schema so only clinically necessary fields are transmitted. 3. Display a blocking warning or require explicit confirmation if likely identifiers remain after redaction. 4. Add automated tests covering identifiers in both plain-text and JSON input. 5. Restrict `--base` to an approved HTTPS endpoint allowlist, or require an explicit unsafe-development flag for custom endpoints. 6. Clearly document residual privacy limitations and data-handling behavior. 7. Do not claim strict de-identification until the control is implemented and validated. 8. Review the remote provider's retention, logging, access-control, and data-processing policies before transmitting health information. ]]>
