Back to skill

Security audit

unisound-health-record-management

Security checks for vulnerabilities and agentic risk

Overview

This healthcare extractor is not malware, but it can send full medical records and an API key to a configurable remote LLM without enforcing de-identification or endpoint limits.

Review before installing. Use only with de-identified records, approved medical-data processing terms for the LLM backend, a trusted HTTPS endpoint, and a controlled output location. Avoid passing real patient identifiers or long-lived API keys until the skill enforces redaction and endpoint allowlisting.

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 (3)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/run.py:29
Finding

Unredacted Health and Identity Data Is Transmitted to an External LLM Service

Content
View full analysis
Any: data = json.dumps(payload, ensure_ascii=False).encode("utf-8") req = urllib.request.Request( url=url, data=data, method="POST", headers={"Content-Type": "application/json", **headers}, ) try: ctx = urllib.request.urlopen(req) if not timeout else urllib.request.urlopen(req, timeout=timeout) ``` ```python def run_health_record(health_info: str, llm, output_path: str = "") -> int: prompt = f"""Please extract a structured resident health record from the following resident health information. [Resident health information] {health_info.strip()} Return JSON and a summary according to the required format. Use null for information that was not provided and do not fabricate information.""" print("Extracting resident health record information...") result = llm([sys_msg(SYSTEM_PROMPT), user_msg(prompt)]) ``` ```python try: health_info = load_input(input_path, args.encoding) except Exception as e: print(f"Failed to read input file: {e}", file=sys.stderr) return 1 llm = make_llm_caller(args.appkey, args.base, args.model, args.timeout) try: return run_health_record(health_info, llm, args.output) ``` ### Technical Analysis The application loads the complete contents of the supplied health-record file and embeds them directly into an LLM request. It does not locally detect, redact, tokenize, or reject direct identifiers such as names, government identification numbers, telephone numbers, or addresses. This conflicts with the privacy statements in `SKILL.md`, which state that direct identifiers are not processed and that strict de- ...[truncated 1384 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/run.py:45
Finding

Arbitrary LLM Endpoint Override Can Expose the API Credential and Medical Records

Content
View full analysis
str: payload = {"model": model, "messages": messages, "temperature": 0} resp = _http_post(url, payload, headers, timeout=timeout) ``` ```python parser.add_argument("--appkey", required=True, help="Internal medical LLM authentication key assigned by the platform.") parser.add_argument("--base", default=DEFAULT_LLM_BASE, help=f"Internal LLM base URL (default: {DEFAULT_LLM_BASE}).") ``` ```python llm = make_llm_caller(args.appkey, args.base, args.model, args.timeout) ``` ### Technical Analysis The `--base` option accepts an arbitrary URL. The application appends `/chat/completions` and sends both the Bearer credential and the complete health-record prompt to the resulting endpoint. There is no trusted-host allowlist, explicit HTTPS-only policy, endpoint identity validation, or check that the configured destination belongs to the intended medical model provider. Consequently, anyone able to influence the invocation arguments can redirect security-sensitive requests to an endpoint they control. The default endpoint uses HTTPS, but that protection is bypassed if a malicious or erroneous value is supplied through `--base`. ### Attack Path 1. An attacker persuades an operator to use a modified command, wrapper, or configuration containing `--base` with an attacker-controlled URL. 2. The application constructs the chat-completions URL from that untrusted base value. 3. It adds the platform API key to the `Authorization: Bearer` heade ...[truncated 826 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/run.py:170
Finding

Untrusted Clinical Text Can Manipulate Generated Health Records Through Prompt Injection

Content
View full analysis
int: prompt = f"""Please extract a structured resident health record from the following resident health information. [Resident health information] {health_info.strip()} Return JSON and a summary according to the required format. Use null for information that was not provided and do not fabricate information.""" print("Extracting resident health record information...") result = llm([sys_msg(SYSTEM_PROMPT), user_msg(prompt)]) ``` The returned content is only checked for basic JSON parseability: ```python parsed_json = None try: if "```" in json_part: start = json_part.find("{") end = json_part.rfind("}") + 1 json_part = json_part[start:end] parsed_json = json.loads(json_part) except json.JSONDecodeError: print("Warning: model JSON output could not be parsed; preserving raw output.", file=sys.stderr) ``` ### Technical Analysis The application directly interpolates untrusted clinical text into a model message that also contains task instructions. It does not tell the model to treat instructions found inside the record as inert data, and it does not delimit or encode the record in a way that provides robust instruction separation. An input record can therefore contain text instructing the model to ignore extraction rules, fabricate diagnoses, omit risk factors, or produce attacker-selected follow-up recommendations. Basic `json.loads` validation only establishes syntactic validity. It does not validate the expected schema, permitted types, medically plausible values, or whether output claims are supported by the source record. The documentation requires human review, which reduces operational risk when followed, but the implem ...[truncated 1134 chars]
Remediation
View remediation
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)

Missing User Warnings

High
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill sends raw resident health-record content to a remote LLM API, but the CLI and runtime flow do not present a clear user-facing warning, consent gate, or data-handling notice before transmitting highly sensitive medical information. In a healthcare context, this can expose protected health information to external infrastructure, logging systems, retention pipelines, or cross-border processing without the operator fully understanding that transmission is occurring.

Content

No source excerpt is available for this finding.

Ssd 3

High
Category
Not specified by scanner
Confidence
96% confidence
Finding

The code forwards user-supplied health records in full to the LLM and then outputs the extracted JSON and summary, creating a direct sensitive-data exposure path for medical details. Because the skill processes resident health archives, the data is especially sensitive; full-fidelity transmission and reproduction increase the chance of disclosure through the model provider, terminal output, saved files, logs, or downstream consumers.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill advertises file read, file write, and network-capable execution paths via its documented runner, but does not declare any explicit tool scope or permissions boundary in the skill manifest. In a healthcare context handling sensitive medical records and an appkey for an internal model API, this lack of least-privilege declaration increases the risk of unintended data exposure, overbroad execution, or misuse by an agent runtime that relies on manifest-scoped controls.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The description specifies the output format as "JSON + 自然语言摘要" in Chinese, and the document consistently presents the summary format in Chinese without any opt-in or alternative language option. Under the policy rule, forcing a specific language is a natural-language policy violation unless the locale restriction is explicitly justified as region-specific.

Content

No source excerpt is available for this finding.