Back to skill

Security audit

unisound-rehab-plan-view

Security checks for vulnerabilities and agentic risk

Overview

This skill is a rehab-plan viewer, but it processes sensitive medical files through a remote model and includes an unsafe fallback that can execute Python code from outside the reviewed package.

Review before installing. Use only with explicit authorization to send rehabilitation data to the listed external API, avoid real patient identifiers where possible, do not pass production API keys on the command line, and avoid untrusted PDFs, Office files, or images unless the runtime is sandboxed. The external _shared/doc-preprocess fallback should be removed or integrity-checked before production use.

Vulnerability Patterns
  • Tool Hijacking and SpoofingModifies or replaces tools so legitimate-looking calls execute attacker logic
  • 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
Findings (3)

T07 · Tool Hijacking and Spoofing

Error
Location
scripts/run.py:185
Finding

Execution of an Unverified Python Module from an External Writable Path

Content
View full analysis

Vulnerability Details

File Location: scripts/run.py:185-192
Vulnerability Type: Untrusted local module loading and execution
Risk Level: High

Vulnerable Code

python
_shared_dir = Path(__file__).resolve().parent.parents[3] / "_shared" / "doc-preprocess" / "scripts"
if not _shared_dir.exists():
    print(f"ERROR: 无法读取输入文件,本地预处理失败且 _shared/doc-preprocess 不可用。原因:{exc}", file=sys.stderr)
    return 1
import importlib.util as _iu
_spec = _iu.spec_from_file_location("_shared_preprocess", _shared_dir / "preprocess.py")
_sp = _iu.module_from_spec(_spec)
_spec.loader.exec_module(_sp)

Technical Analysis

When local preprocessing raises PreprocessError, the application constructs a path outside the audited skill package and dynamically executes the preprocess.py file found there. For the audited deployment path, Path(__file__).resolve().parent.parents[3] resolves to /tmp, resulting in the expected module location:

text
/tmp/_shared/doc-preprocess/scripts/preprocess.py

The application does not verify the module's cryptographic digest, ownership, permissions, provenance, or containment beneath a trusted application directory. Calling exec_module() executes all module-level Python statements immediately.

Consequently, any party able to create or replace the expected fallback file can cause arbitrary Python code to run. Exploitation requires local write access to the relevant external directory and an input that causes the primary preprocessor to raise PreprocessError.

Attack Path

  1. An attacker with local write access creates or replaces /tmp/_shared/doc-preprocess/scripts/preprocess.py.
  2. The attacker places arbitrary module-level Python code in that file.
  3. The attacker or a victim invokes the skill with an input that causes the bundled preprocessing implementation to raise PreprocessError, such as an unsupported or unprocessable document.
  4. The exception ...[truncated 838 chars]
Remediation
View remediation

Remediation Suggestions

  • Remove the external dynamic-import fallback and use only the preprocessor shipped inside the reviewed package.
  • If shared preprocessing is required, package it as a pinned and audited dependency installed in a protected application environment.
  • Resolve the dependency beneath an immutable, administrator-controlled application root rather than a temporary or broadly writable directory.
  • Before loading any fallback module, verify its canonical path, owner, permissions, and cryptographic digest against trusted metadata.
  • Reject symbolic links and ensure every parent directory is not writable by untrusted users.
  • Avoid exec_module() for runtime discovery of source files. Import a statically declared package through a controlled Python environment instead.
  • Run the skill under a dedicated least-privileged operating-system account and restrict its filesystem and network access to reduce impact if module loading is compromised.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/run.py:172
Finding

API Credential Exposed Through a Command-Line Argument

Content
View full analysis

Vulnerability Details

File Location: scripts/run.py:172; documented at SKILL.md:68 and SKILL.md:157
Vulnerability Type: Insecure secret handling
Risk Level: Medium

Vulnerable Code

python
parser.add_argument("--appkey", required=True, help="内部医疗大模型鉴权key(必填)")

The documented invocation explicitly places the credential on the command line:

bash
python3 scripts/run.py --input input.json --output output.json --appkey YOUR_KEY

Technical Analysis

Passing bearer credentials as command-line arguments exposes them beyond the intended application boundary. Depending on the operating system and deployment environment, process arguments may be available through process inspection facilities, monitoring agents, job metadata, audit logs, crash diagnostics, or orchestration dashboards. Interactive use can also retain the complete command in shell history.

Although the application does not print the credential directly, the documented secret-delivery mechanism creates avoidable credential exposure. The key is subsequently used as a bearer token, so possession of the value may be sufficient to authenticate to the configured model endpoint.

Attack Path

  1. A user follows the documented command and provides a real API key through --appkey.
  2. The full command is recorded in shell history, process telemetry, orchestration logs, or another process-visible argument listing.
  3. A local user, system operator, log reader, or compromised monitoring component retrieves the argument value.
  4. The exposed bearer credential is replayed against the configured medical-model API.
  5. Unauthorized requests can be made until the key expires or is revoked.

Impact Assessment

The attacker may gain the API access associated with the exposed key. Potential effects include unauthorized model usage, consumption of quotas, financial charges, service disruption through quota exhaustion, and actions att ...[truncated 196 chars]

Remediation
View remediation

Remediation Suggestions

  • Deprecate and remove the --appkey argument.
  • Retrieve the credential from an approved secret manager or a protected environment variable.
  • For interactive execution, support a non-echoing secret prompt through getpass.
  • Where supported, accept the credential through a restricted file descriptor or a credential file with strict owner-only permissions.
  • Update SKILL.md so examples never place real secrets in command-line arguments.
  • Ensure orchestration logs, errors, telemetry, and crash reports redact authorization values.
  • Use short-lived, narrowly scoped credentials and implement rotation and immediate revocation procedures for exposed keys.

other

Warning
Location
scripts/run.py:76
Finding

Patient Health Information Transmitted to an External API Without Data-Minimization Controls

Content
View full analysis

Vulnerability Details

File Location: scripts/run.py:76-91 and scripts/run.py:21-31
Vulnerability Type: Sensitive health data disclosure
Risk Level: Medium

Vulnerable Code

The complete mapped rehabilitation record is embedded in the model prompt:

python
user_prompt = f"""请解读以下康复计划:

计划ID:{plan_id}
手术类型:{surgery_type}
当前阶段:{current_phase}
阶段目标:{phase_goal}
康复任务:{json.dumps(tasks, ensure_ascii=False)}
注意事项:{json.dumps(precautions, ensure_ascii=False)}

请生成患者友好的康复计划解读。"""

text = _call_llm(SYSTEM_PROMPT, user_prompt, appkey)

The prompt is transmitted to the configured external endpoint:

python
API_URL = "https://maas-api.hivoice.cn/v1/chat/completions"
MODEL = "u2-med"

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"]

Technical Analysis

The skill transmits the plan identifier, surgery type, rehabilitation phase, treatment goals, assigned tasks, and precautions to maas-api.hivoice.cn. These fields can contain health information and may become identifying when combined with a patient-specific plan identifier or free-form task and precaution content.

The network behavior is documented and uses HTTPS, so it is not hidden exfiltration. However, the implementation does not enforce explicit consent, remove identifiers, minimize free-form content, warn before transmission, provide a local-processing option, or expose controls concerning ...[truncated 1703 chars]

Remediation
View remediation

Remediation Suggestions

  • Require explicit, informed authorization before transmitting patient information to the external processor.
  • Clearly disclose the destination service, categories of data transmitted, processing purpose, retention period, and applicable privacy terms.
  • Remove plan_id from the prompt unless it is demonstrably necessary for model inference.
  • Pseudonymize or redact direct and linkable identifiers before request construction.
  • Apply field-level data minimization and limit free-form tasks and precautions to information required for the requested summary.
  • Add configurable redaction rules for names, patient numbers, contact details, dates, and other identifying information.
  • Provide a local or non-network rendering mode for users who cannot authorize third-party processing.
  • Establish an approved data-processing agreement with the API provider and verify encryption, access control, retention, deletion, audit, and incident-response requirements.
  • Avoid logging request bodies and ensure patient data is removed from diagnostics and error telemetry.
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • System Prompt LeakageDirect Leakage, Indirect Extraction, Tool-Based Exfiltration
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (18)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The stated purpose is a narrow patient rehab-plan viewing skill, but the specification also enables broad document ingestion, OCR, Office/PDF conversion, and generic preprocessing pipelines. That mismatch is dangerous because it expands the attack surface well beyond a simple viewer, introducing parser, converter, and prompt-injection-style risks from untrusted files without making those risks obvious to users or reviewers.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding

The skill advertises executable behaviors such as file access, shelling out to external tools, network calls, and possible environment access, but does not declare any tool scope or permission boundaries. In a medical-data workflow, this lack of explicit capability restriction increases the risk of over-privileged execution, unintended file/system access, and unreviewed outbound data transfer.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The skill accepts broad medical document/image inputs and sends content to a remote model endpoint, but does not clearly warn users that potentially sensitive health information may be transmitted off-box for inference. In a healthcare context, this creates significant privacy and compliance risk, especially when OCR and document parsing may extract more PHI than the user expects.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

The file specifies Chinese OCR support via "chi_sim+eng" and uses exclusively Chinese-facing descriptions and field examples, but it does not state that the skill is intentionally limited to a China-specific workflow or offer language/locale selection. Under the policy, forcing a specific language or locale without user opt-in is a natural-language policy concern.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The file implements a broad ingestion utility for many document and image formats that exceeds the stated scope of a patient rehab-plan viewing skill. This unnecessary capability expansion increases attack surface by introducing multiple parsers and conversion paths that may be reachable through skill workflows, especially in a medical context that may handle sensitive patient documents.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The code invokes external conversion and OCR binaries (LibreOffice, pdftotext, tesseract) on input files, significantly widening the trusted computing base. In a patient-facing rehab-plan skill, this is more dangerous because the feature appears broader than necessary and may expose the system to third-party parser exploits, sandbox escapes, or denial-of-service through crafted files.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/preprocess.py (reported line 111)May include surrounding context.

python
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,
        )

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/preprocess.py (reported line 126)May include surrounding context.

python
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)],

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/preprocess.py (reported line 153)May include surrounding context.

python
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,
        )

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/preprocess.py (reported line 171)May include surrounding context.

python
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

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/preprocess.py (reported line 178)May include surrounding context.

python
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,
    )

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The skill's stated function is to let patients view or interpret a rehab plan, yet it depends on a remote model endpoint and separate authentication key. That expands the trust boundary and introduces unnecessary exposure, since sensitive medical data and credentials now flow to an external service not implied by the feature description.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The code sends the full rehabilitation-plan content, including medical details such as surgery type, phase, tasks, and precautions, to an external LLM API for interpretation. In a medical patient-facing context this is sensitive health information, so undisclosed third-party transmission materially increases privacy, confidentiality, and compliance risk.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The system prompt mandates Chinese behavior and Markdown output in Chinese-context phrasing, with no indication that the user may choose another language. This is a natural-language locale policy concern because the skill enforces a specific language without documented opt-in or justification.

Content

No source excerpt is available for this finding.

Ssd 1

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

Untrusted input fields from the rehab plan are interpolated directly into the LLM prompt, allowing an attacker controlling plan content to inject instructions that compete with the system prompt. In this implementation the model output is returned to the patient, so the main risk is manipulated or unsafe medical guidance rather than code execution, but in a healthcare context misleading recovery instructions can still cause harm.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The build path constructs a prompt from patient rehab-plan fields and sends it to the external API without any visible user-facing notice, consent, or privacy warning. In healthcare, silent disclosure of treatment-related data to a third party can violate user expectations and regulatory requirements, making the context more dangerous than a generic content-summarization tool.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
93% confidence
Finding

The code sets Tesseract to use "chi_sim+eng" whenever those models are available, which imposes a specific language policy in natural-language processing behavior. There is no user choice, configuration input, or documented region-specific justification in this file.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

Accepting the API credential via a command-line argument can expose it through shell history, process listings, job logs, and orchestration metadata. While this is not as severe as direct patient-data leakage, it can enable unauthorized use of the external medical-model service if the host environment is shared or monitored.

Content

No source excerpt is available for this finding.