T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/run.py:131
- Finding
- Patient information is transmitted without the promised de-identification<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:26-30`; `scripts/run.py:131-142` **Vulnerability Type**: T09: Insecure Skill Coding Practices **Risk Level**: High ### Vulnerable Code The documentation claims that identifying information is removed before any external transmission: ```markdown 数据安全、隐私与伦理声明 ------------------------ - **最小必要原则**:仅处理开具处方所必需的患者信息;不要求也不鼓励包含姓名、证件号、手机号等身份信息。 - **严格脱敏**:在发送至任何模型/接口前,会对可识别个人身份的信息进行脱敏/去标识化处理。 - **不做本地持久化**:仅在内存中短暂处理;**本次调用结束即销毁**。 ``` However, the implementation places the complete input directly into the prompt and sends it to the external model: ```python def run_prescription(prescription_info: str, llm, output_path: str = "") -> int: prompt = f"""请根据以下信息,为患者提供处方开具辅助建议。 【处方信息】 {prescription_info.strip()} 请严格按照要求输出 JSON + 摘要。""" print("正在分析处方信息...") result = llm([sys_msg(SYSTEM_PROMPT), user_msg(prompt)]) ``` ### Technical Analysis There is no de-identification, redaction, field filtering, or validation between loading the clinical record and transmitting it to the model API. `prescription_info` is interpolated into the outbound prompt without modification. Although the documentation discourages users from supplying names, identification numbers, and telephone numbers, a warning is not a technical control. Unstructured clinical records commonly contain direct and indirect identifiers, including names, contact details, dates, record numbers, addresses, and rare diagnoses. This discrepancy creates a false security expectation: operators may reasonably rely on the explicit statement that de-identification occurs automatically and therefore submit records containing protected health information. ### Attack Path 1. A clinician supplies a text or JSON input containing patient identifiers and clinical information. 2. `load_input()` reads the record and returns its contents without redaction. 3. `run_prescription()` interpolates the entire record into `prompt`. 4. `make_llm_caller()` pas ...[truncated 958 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Implement local de-identification before prompt construction: - Remove names, telephone numbers, email addresses, addresses, identity numbers, patient record numbers, and other direct identifiers. - Normalize or generalize dates and rare identifying attributes where clinically appropriate. - Apply redaction to both unstructured text and every supported JSON field. 2. Reject or require explicit confirmation for input that still appears to contain identifiers after redaction. 3. Minimize transmitted fields by parsing the input into a strict clinical schema and sending only fields required for medication assessment. 4. Add automated tests covering representative identifiers, Unicode text, nested JSON objects, malformed inputs, and attempts to bypass redaction. 5. Clearly disclose the destination, retention policy, and privacy boundary of the model service. 6. If reliable de-identification cannot be guaranteed, remove the documentation claim and require users to provide pre-de-identified data explicitly. 7. Ensure that the model service and data-processing arrangements are approved for the applicable category of medical information. ]]>
