Back to skill

Security audit

unisound-chronic-screening

Security checks for vulnerabilities and agentic risk

Overview

The skill performs the advertised health screening, but it needs review because it can send sensitive health records and an API key to a configurable remote endpoint while making privacy claims the code does not enforce.

Install only if you are authorized to send resident health data to the documented medical LLM service and can control how the CLI is invoked. Do not include direct identifiers unless they are removed before input, avoid untrusted --base values, and treat any --output file as sensitive medical data requiring protected storage 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 (1)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/run.py:45
Finding
Unrestricted LLM Endpoint Override Exposes API Credentials and Sensitive Health Data## Vulnerability Details **File Location**: `scripts/run.py`, lines 45–49, 207, and 221 **Vulnerability Type**: Server-Side Request Forgery and sensitive-data disclosure through an unrestricted API endpoint **Risk Level**: High **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) ``` ```python 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 command-line `--base` value is used directly to construct the request destination without validating its scheme, hostname, port, or network range. The application then sends an `Authorization: Bearer` header containing the supplied platform credential to that destination. The request body also contains the complete health record submitted for chronic-disease screening. Consequently, any party able to control or influence the command-line arguments can redirect the request to an attacker-controlled server or an unintended internal service. Both HTTP and HTTPS destinations are accepted, so the credential and medical data may also be sent over an unencrypted connection. This violates destination-bound credential handling and least-disclosure principles. ### Attack Path 1. An attacker gains control over, or influences, the arguments used to invoke the Skill. 2. The attacker sets `--base` to a server under their control, such as `https://attacker.example/v1`, or to an unencrypted HTTP endpoint. 3. The applicati ...[truncated 1159 chars]
Remediation
## Remediation Suggestions - Remove the `--base` override from production builds if endpoint customization is unnecessary. - Otherwise, enforce a strict allowlist of approved API hostnames and ports. Parse the URL with `urllib.parse.urlsplit` and reject user-info components, fragments, unexpected paths, nonstandard ports, and all schemes except HTTPS. - Resolve the destination and reject loopback, link-local, private, multicast, reserved, and metadata-service address ranges unless a specifically approved internal endpoint requires them. Revalidate redirects or disable cross-origin redirects. - Attach the bearer credential only after confirming that the final request destination is an approved origin. Never forward credentials across redirects to another host. - Use endpoint-specific, short-lived, least-privilege credentials so one leaked key cannot access unrelated services. - Redact or minimize health information before transmission and obtain appropriate authorization for external processing. - Add automated tests confirming that attacker-controlled domains, plain HTTP URLs, embedded credentials, alternate ports, redirect-based bypasses, and internal IP literals are rejected.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (5)

Lp3

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding
The skill advertises file input/output and external network access via its documented run commands and API dependency, but it does not declare any explicit tool scope or permissions. This creates an authorization and governance gap: a caller or platform cannot easily constrain the skill's access to local files or outbound network destinations, which is especially risky in a healthcare context handling sensitive health data and an appkey.

Natural-Language Policy Violations

Medium
Confidence
92% confidence
Finding
The file consistently presents the skill name, description, instructions, inputs, and outputs only in Chinese. Under the policy rule, forcing a specific language without user opt-in can be a natural-language policy violation, and this file does not state that the skill is China-only or otherwise region-restricted.

Description-Behavior Mismatch

Medium
Confidence
93% confidence
Finding
The skill is designed to process resident health data, then sends that data to a remote LLM endpoint over the network. Because the skill description does not clearly disclose third-party or remote transmission of sensitive medical information, users and operators may unknowingly expose protected health data outside the local environment, creating privacy, compliance, and data-governance risk.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
At the call site, the full resident health record is embedded into the prompt and transmitted to the remote LLM for processing. In a medical-screening context, this materially increases sensitivity because the payload may include diagnoses, lab values, family history, and lifestyle data, and the script provides no explicit warning, consent gate, or redaction step before network disclosure.

Missing User Warnings

Low
Confidence
84% confidence
Finding
The script can persist screening results to disk, and those results may contain sensitive medical assessments and inferred disease risk. Writing such data without a clear warning or safeguards can lead to unintended retention, insecure sharing, or exposure through backups, shared directories, or downstream tooling.

Static analysis

No suspicious patterns detected.