Back to skill

Security audit

unisound-today-rehab-task

Security checks for vulnerabilities and agentic risk

Overview

This skill is not clearly malicious, but it handles sensitive rehabilitation data in broad file formats and sends selected task data to a fixed external medical-model API without strong user controls.

Review before installing. Use this only if sending rehabilitation task data to the documented external model provider is acceptable for your privacy, compliance, and data-residency requirements. Prefer JSON input, avoid feeding arbitrary patient documents unless necessary, sandbox document conversion/OCR if enabled, and do not pass real API keys directly on the command line.

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)

other

Warning
Location
scripts/run.py:14
Finding
External Disclosure of Rehabilitation and Patient Task Data<![CDATA[ ## Vulnerability Details **File Location**: `scripts/run.py`, lines 14 and 24–31, with sensitive prompt construction at lines 76–88 **Vulnerability Type**: Sensitive Health Data Disclosure **Risk Level**: Medium ### Vulnerable Code ```python API_URL = "https://maas-api.hivoice.cn/v1/chat/completions" MODEL = "u2-med" ``` ```python def _call_llm(system_prompt: str, user_prompt: str, appkey: str) -> str: payload = {"model": MODEL, "temperature": 0.0, "messages": [ {"role": "system", "content": system_prompt}, {"role": "user", "content": user_prompt}]} try: req = Request(API_URL, data=json.dumps(payload, ensure_ascii=False).encode("utf-8"), headers={"Content-Type": "application/json", "Authorization": f"Bearer {appkey}"}) resp = urlopen(req, timeout=120) return json.loads(resp.read().decode("utf-8"))["choices"][0]["message"]["content"] ``` ```python user_prompt = f"""Please generate reminders for the following rehabilitation tasks: Date: {today_str} Plan ID: {plan_id} Completed tasks: {json.dumps(completed, ensure_ascii=False)} Pending tasks: {json.dumps(pending, ensure_ascii=False)} Completion progress: {len(completed)}/{len(today_tasks)} Please convert the tasks into time-segmented reminders, mark each task's status, and provide encouragement.""" text = _call_llm(SYSTEM_PROMPT, user_prompt, appkey) ``` The final snippet is an English rendering of the source prompt text; its interpolated variables and data flow are unchanged. ### Technical Analysis The skill embeds the rehabilitation plan identifier and complete task records, including completion status and potentially user-supplied medical details, into an LLM prompt. It then sends the prompt to the fixed external endpoint `https://maas-api.hivoice.cn/v1/chat/completions`. The documented purpose discloses that a remote medical model is used, so this is not covert exfiltration. However, the implementation has no technical ...[truncated 1939 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Require explicit, informed consent before sending rehabilitation data to an external model. 2. Construct a strict allowlisted payload containing only fields necessary for reminder generation, such as a sanitized task label and completion state. 3. Remove or pseudonymize `plan_id` before transmission. 4. Recursively redact names, contact details, medical-record numbers, free-form clinical notes, and other identifiers. 5. Add an organization-controlled endpoint configuration with an allowlist rather than relying exclusively on a hardcoded third-party destination. 6. Provide a local-only mode for generating deterministic reminders without transmitting medical information. 7. Document the provider's retention, training, logging, deletion, and data-residency policies. 8. Add a preflight summary showing which fields and destination will be used, and require confirmation for sensitive inputs. 9. Enforce transport certificate validation and organizational egress controls; HTTPS alone does not address provider-side retention or authorization. 10. Add automated tests proving that unexpected task fields cannot enter the remote prompt. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/run.py:188
Finding
Bearer API Credential Exposed Through Command-Line Arguments<![CDATA[ ## Vulnerability Details **File Location**: `scripts/run.py`, line 188; documented usage in `SKILL.md`, line 57 **Vulnerability Type**: Command-Line Secret Exposure **Risk Level**: Medium ### Vulnerable Code ```python parser.add_argument("--appkey", required=True, help="Internal medical model authentication key (required)") ``` The documentation instructs users to supply the credential directly on the command line: ```bash python3 scripts/run.py --input input.json --date 2026-04-29 --output output.json --appkey YOUR_KEY ``` The descriptive text in the Python snippet is an English rendering of the source help message; the vulnerable argument behavior is unchanged. ### Technical Analysis The API bearer token is required as a normal command-line argument. Command-line arguments are commonly exposed through: - Shell history files - Process inspection tools such as `ps` - `/proc/&lt;pid&gt;/cmdline` on applicable systems - CI/CD job output and command tracing - Terminal session recording - Automation and orchestration logs - Support bundles and diagnostic tooling Although the key is subsequently placed in the HTTP `Authorization` header rather than printed directly by the program, accepting it through `argv` exposes it before the request is made. The 120-second API timeout can also extend the period during which the key remains visible in process metadata. ### Attack Path 1. A user follows the documented invocation and substitutes a valid API key for `YOUR_KEY`. 2. The shell records the full command in history, or the operating system exposes the active process arguments. 3. A local user, administrator, monitoring agent, CI log reader, or other principal with access to that metadata retrieves the key. 4. The principal uses the recovered key as a bearer token when making requests to the medical-model API. 5. Any resulting access is bounded by the permissions, quotas, and lifetime assigned to that API key. This issue does not independently provi ...[truncated 544 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove the `--appkey` command-line option as the primary credential mechanism. 2. Read the token from a dedicated environment variable or an operating-system secret manager. 3. For interactive use, support a non-echoing prompt through `getpass.getpass()`. 4. In production, use short-lived scoped credentials obtained through workload identity or a platform-managed secret injection mechanism. 5. Update `SKILL.md` so examples never place real credentials in shell commands. 6. If an environment variable is supported, warn users not to place it in committed shell scripts or globally readable configuration files. 7. Ensure exception messages, debug logs, request traces, and prepared output files never include the token. 8. Rotate any key previously used through the documented command if shell history or process logs may have been retained. 9. Apply least-privilege scopes, expiration, rate limits, and usage monitoring to every issued token. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (21)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The declared purpose is simple rehab task filtering and status tracking, but the documented behavior expands into broad document ingestion, OCR, spreadsheet parsing, and file conversion. This mismatch is dangerous because users and reviewers may authorize a seemingly narrow healthcare skill while it processes far more data types and content than expected, increasing attack surface and privacy exposure.

Lp3

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding
The skill advertises capabilities that imply file access, shell execution, environment access, and network use, but it does not declare any explicit tool scope or permission boundaries. In a medical-data workflow, this creates unnecessary ambiguity about what the skill may access or transmit, increasing the risk of over-privileged execution and unintended handling of sensitive patient information.

Description-Behavior Mismatch

Medium
Confidence
90% confidence
Finding
The documentation broadens the skill from task display/status tracking into document extraction, OCR, and natural-language analysis, which materially expands the data processing scope beyond the stated use case. In a healthcare context, this increases the chance that unrelated or sensitive patient documents are ingested and analyzed without adequate need, minimization, or review.

Context-Inappropriate Capability

Medium
Confidence
91% confidence
Finding
A simple task-listing and status-recording function should not require mandatory transmission to an internal LLM API. Forcing external model inference for routine rehab-task handling introduces avoidable disclosure of medical plan/task data and creates dependence on a remote service for functionality that could be performed locally.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill states that an internal medical model API is mandatory but does not clearly warn users that rehab plan and task data may be transmitted off-process to that service. Because this is health-related information, lack of prominent disclosure and consent can lead to privacy violations, regulatory exposure, and inappropriate sharing of sensitive patient data.

Description-Behavior Mismatch

Medium
Confidence
90% confidence
Finding
The manifest describes a patient-side postoperative rehabilitation daily-task capability, but this code is a generic ingestion/preprocessing module for PDFs, Office documents, spreadsheets, JSON, text, and images. That behavior is materially broader and not semantically aligned with constructing or managing today's rehab tasks.

Context-Inappropriate Capability

Medium
Confidence
92% confidence
Finding
The skill introduces external document conversion and OCR capabilities that are not justified by the stated postoperative rehab-task purpose, which increases attack surface without clear business need. In this context, unnecessary parsing of untrusted complex files is more dangerous because it expands what an attacker can feed into the system with little functional justification.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
The code processes user files via external converters and OCR with no visible user-facing disclosure or consent mechanism. While lack of disclosure is not a classic exploit primitive, it creates security and privacy risk because sensitive medical-adjacent documents may be processed by heavyweight third-party binaries unexpectedly, and users/operators may not understand the exposure.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
if not office_bin:
        raise PreprocessError("libreoffice/soffice not found for office document conversion.")
    with tempfile.TemporaryDirectory(prefix="med-skill-preprocess-") as tmp_dir:
        proc = subprocess.run(
            [office_bin, "--headless", "--convert-to", "txt:Text", "--outdir", tmp_dir, str(path)],
            stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, check=False,
        )
Confidence
78% confidence
Finding
The code sends user-supplied office documents to LibreOffice for conversion. Although it avoids shell injection by passing an argument list, invoking a large external document-processing binary on untrusted input increases attack surface and can expose the host to parser/RCE vulnerabilities or SSRF-like behaviors historically associated with office file processing.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
if not office_bin:
        raise PreprocessError("libreoffice/soffice not found for xls conversion.")
    with tempfile.TemporaryDirectory(prefix="med-skill-preprocess-") as tmp_dir:
        proc = subprocess.run(
            [office_bin, "--headless",
             "--convert-to", "csv:Text - txt - csv (StarCalc):44,34,76,1",
             "--outdir", tmp_dir, str(path)],
Confidence
78% confidence
Finding
This code processes user-provided .xls files through LibreOffice, which is a complex external parser with a history of security bugs. The issue is not command injection but unsafe exposure of the host to untrusted document conversion without containment or input restrictions.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
pass
    pdf_to_text = shutil_which("pdftotext")
    if pdf_to_text:
        proc = subprocess.run(
            [pdf_to_text, "-layout", str(path), "-"],
            stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, check=False,
        )
Confidence
74% confidence
Finding
Running pdftotext on untrusted PDFs similarly delegates parsing to an external binary, which can be risky because malformed PDFs may trigger parser vulnerabilities or denial-of-service conditions. The subprocess usage itself is safe from shell injection, but the untrusted-file processing model broadens the attack surface.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
cmd = [tesseract_bin, str(path), "stdout"]
    if lang_arg:
        cmd.extend(["-l", lang_arg])
    proc = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, check=False)
    if proc.returncode != 0 or not proc.stdout.strip():
        raise PreprocessError(f"Image OCR failed: {proc.stderr.strip() or 'no text returned'}")
    return proc.stdout
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def detect_tesseract_langs(tesseract_bin: str) -> Sequence[str]:
    proc = subprocess.run(
        [tesseract_bin, "--list-langs"],
        stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, check=False,
    )
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Context-Inappropriate Capability

Medium
Confidence
94% confidence
Finding
The code includes remote network access to a third-party chat completions API even though the stated capability is only to build today's rehab task reminders. In a healthcare skill, unnecessary outbound connectivity materially increases attack surface and enables data exfiltration of sensitive operational or patient information.

Description-Behavior Mismatch

Medium
Confidence
96% confidence
Finding
The skill transmits rehabilitation task details, including dates, statuses, and plan identifiers, to an external LLM endpoint to generate reminders. In a medical context, this is sensitive patient-related workflow data, and sending it off-device/off-service exceeds the narrowly described local formatting function while creating confidentiality, compliance, and third-party data handling risk.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
The natural-language instructions define the assistant persona and required output entirely in Chinese and mandate a specific response style, without indicating that users may choose another language. This is a language-policy concern because the skill appears to impose a locale/language by default rather than through documented opt-in or justified regional scope.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
The skill sends completed and pending rehabilitation tasks to an external LLM without any user-facing notice, consent flow, or privacy disclosure. Because this is medical-task data tied to a date and plan context, silent transmission to a third party creates significant privacy, trust, and possible regulatory exposure.

Natural-Language Policy Violations

Low
Confidence
83% confidence
Finding
The dependency note requires Tesseract with 'chi_sim+eng', indicating a fixed Chinese/English OCR language setup. This imposes a language/locale expectation without stating that users may choose alternatives or that the skill is limited to a justified region-specific context.

Natural-Language Policy Violations

Low
Confidence
96% confidence
Finding
The code automatically sets Tesseract to use "chi_sim+eng" when those language packs are available, which imposes a specific language/locale choice without asking the user. This matches the language/locale policy concern because the skill does not offer a user choice or document a justified region-specific constraint.

Intent-Code Divergence

Low
Confidence
95% confidence
Finding
The top-level docstring says '自包含skill' (self-contained skill), which implies the functionality is implemented within the skill itself. However, the main output generation path calls a remote API endpoint for the core reminder text, so the documentation contradicts the actual dependency and behavior.

Missing User Warnings

Low
Confidence
87% confidence
Finding
The script requires an `--appkey` credential and uses it in the Authorization header for the external API request, but provides no warning or explanatory comment about handling sensitive credentials. For code files, access to sensitive credentials should have some form of visible disclosure when no README context is available.

Static analysis

Detected: suspicious.dynamic_code_execution

Dynamic code execution detected.

Critical
Code
suspicious.dynamic_code_execution
Location
scripts/run.py:209