Back to skill

Security audit

med-record-struct

Security checks for vulnerabilities and agentic risk

Overview

This medical-record skill performs its stated structuring task, but it sends full record text to a hard-coded external service while promising de-identification.

Review before installing or using this with real patient data. Treat any input record as potentially sent in full to the external service at shangbao.yunzhisheng.cn, and expect the structured result to be written to disk unless you control the output path. Use only already de-identified records unless the publisher adds enforceable redaction, consent, endpoint, and retention controls.

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/struct_followup_record.py:61
Finding

Raw Medical Records Are Transmitted to an External Service Without De-identification

Content
View full analysis

Vulnerability Details

File Location: scripts/struct_followup_record.py:61-70
Related Documentation: SKILL.md:38-40
Vulnerability Type: Sensitive medical-data disclosure to a third party
Risk Level: High

Vulnerable Code

python
payload: Dict[str, Any] = {
    "his_record": his_record,
    "diag_id": diag_id or "skill-diag",
}
if department:
    payload["department"] = department

body = _post_json(API_URL, payload, timeout=timeout)

The relevant privacy guarantee in SKILL.md states that identifiable information will be de-identified before being sent to any model or API. However, the implementation contains no de-identification step.

Technical Analysis

The complete contents of the input medical record are assigned directly to the his_record request field and transmitted to the hard-coded external endpoint:

text
https://shangbao.yunzhisheng.cn/skills/record-struct/gen_abstract_by_his

No local filtering, identifier detection, redaction, data minimization, consent check, or validation occurs before transmission. Consequently, any names, identification numbers, telephone numbers, addresses, visit identifiers, diagnoses, treatment details, or other sensitive information in the source file may be disclosed to the remote service.

HTTPS protects the request in transit against ordinary passive interception, but it does not prevent the receiving service from accessing, retaining, or further processing the record. The implementation also does not expose controls for selecting which medical-record fields may be transmitted.

Attack Path

  1. A user provides a follow-up record containing personal or sensitive medical information.
  2. struct_followup_record() reads the entire input file into record_text.
  3. call_followup_struct_api() places the unmodified text into payload["his_record"].
  4. _post_json() sends the full payload to the hard-coded external ser ...[truncated 913 chars]
Remediation
View remediation

Remediation Suggestions

  1. Implement local de-identification before constructing the HTTP payload. At minimum, detect and redact names, government identifiers, telephone numbers, email addresses, detailed addresses, medical-record numbers, and other direct identifiers.
  2. Reject transmission when identifier detection finds unresolved sensitive values, unless the user gives informed and explicit consent.
  3. Apply data minimization by transmitting only fields required for structuring rather than an unrestricted source document whenever practical.
  4. Clearly identify the external processor, its purpose, retention policy, data-processing terms, and geographic or regulatory implications.
  5. Add automated tests containing representative identifiers to verify that raw values never reach _post_json().
  6. Consider an entirely local processing mode for records that cannot legally or contractually be sent to an external processor.
  7. Update the documentation so that it accurately reflects the implemented privacy controls and does not promise de-identification until that control is verifiably present.

other

Warning
Location
scripts/struct_followup_record.py:107
Finding

Structured Medical Records Are Persisted Despite the No-Persistence Guarantee

Content
View full analysis

Vulnerability Details

File Location: scripts/struct_followup_record.py:107-111
Default Output Location: scripts/struct_followup_record.py:132-133
Related Documentation: SKILL.md:39
Vulnerability Type: Unintended persistence of sensitive medical information
Risk Level: Medium

Vulnerable Code

python
out_dir = os.path.dirname(output_path) or "."
os.makedirs(out_dir, exist_ok=True)

with open(output_path, "w", encoding="utf-8") as f:
    json.dump(structured, f, ensure_ascii=False, indent=2)

The default persistent output path is established as follows:

python
default_out = os.path.join("..", "runs", "med-followup-record-struct", "structured.json")
out_path = args.output or default_out

The privacy statement in SKILL.md claims that user input and intermediate results are not written to persistent local storage and are destroyed after the invocation. The implementation instead writes every successful structured result to the filesystem.

Technical Analysis

The API result may retain diagnoses, medications, examination results, medical history, and identifiers copied or inferred from the source record. The script creates the destination directory and writes this result to a JSON file unconditionally during successful CLI execution.

The file is created using the process’s ordinary umask and no explicit restrictive permission mode is enforced. Depending on the runtime environment, directory ownership, and umask, the result may be readable by other local accounts or processes. It may also be captured by backups, workspace synchronization, artifact collection, or later project packaging.

Although the output is the final result rather than merely an intermediate value, it remains persistent sensitive data. This behavior materially contradicts the documented assertion that processed information exists only in memory and is destroyed when the invocation ends.

Atta

...[truncated 1223 chars]

Remediation
View remediation

Remediation Suggestions

  1. Make persistent output explicitly opt-in instead of writing a file by default. Provide stdout or an in-memory return mode for callers that do not require persistence.
  2. When persistence is requested, create the file with restrictive permissions such as 0600 and ensure the containing directory is not accessible to unrelated users.
  3. Warn users that the output contains sensitive medical information and document retention, deletion, backup, and access-control responsibilities.
  4. Avoid placing sensitive output in generic workspace or run directories that may be automatically synchronized or collected.
  5. Offer a secure deletion or short-lived output mode where operationally appropriate, while acknowledging filesystem limitations such as copy-on-write storage and backups.
  6. Update SKILL.md to distinguish input handling, remote transmission, final-result storage, and intermediate storage accurately.
  7. Add tests confirming that no file is created when the user selects non-persistent operation and that persistent files receive restrictive permissions.
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 (2)

Missing User Warnings

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The script reads outpatient follow-up medical record text from a local file and sends it to an external company-controlled HTTPS API for processing, but provides no explicit consent prompt, privacy warning, data minimization, or configuration guard before transmitting potentially sensitive health information. In a medical-record processing skill, this is particularly dangerous because the payload may contain highly regulated personal health data, and users may reasonably assume processing is local unless clearly told otherwise.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding

The skill documentation indicates capabilities involving file input/output and networked self-tests, but it does not declare any explicit tool scope or permissions boundaries. In a medical-record structuring context, this is risky because the skill handles highly sensitive health data and claims privacy protections that cannot be enforced without concrete permission restrictions, increasing the chance of overbroad file access, unintended persistence, or external transmission.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.