T07 · Tool Hijacking and Spoofing
- Location
scripts/run.py:263- Finding
Unauthenticated External Preprocessor Module Execution
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill has a coherent clinical-statistics purpose, but it also sends sensitive trial summaries to a remote model and can execute an unverified external preprocessor.
Install only if you trust the remote medical-model endpoint, are authorized to send trial-derived data there, and can run the skill in a contained environment. Avoid untrusted Office/PDF/image inputs, prefer JSON/CSV/XLSX, and review any AI-generated clinical interpretation with a qualified statistician.
scripts/run.py:263Unauthenticated External Preprocessor Module Execution
scripts/run.py:128Prompt Injection Through Attacker-Controlled Clinical Trial Fields
The declared purpose is narrow clinical-trial statistics, but the documented behavior includes broad document ingestion, conversion, OCR, and text extraction across many formats. That mismatch widens the attack surface far beyond simple statistical processing, enabling risky parsing of untrusted files and use of external utilities that may expose the runtime to malformed-document exploits or unauthorized processing of unrelated sensitive content.
The skill advertises capabilities that imply file I/O, shell execution, environment access, and network access, but it does not declare any explicit tool scope or permission boundaries. In a clinical-trial context, this creates an opaque trust boundary: sensitive trial data may be read, transformed, transmitted, or written without clear least-privilege constraints, increasing the chance of unintended exfiltration or dangerous tool use.
The skill explicitly sends data to a model API but does not provide a clear privacy or data-handling warning, despite processing clinical-trial records that may include highly sensitive regulated data. Users may unknowingly transmit confidential subject, protocol, or endpoint information to a remote service without understanding retention, jurisdiction, or access implications.
The manifest describes a capability for clinical trial data statistics, specifically referencing descriptive statistics and group comparison. This file instead implements broad ingestion and text/table extraction for pdf/doc/docx/xls/xlsx/csv/txt/json/images, which is a generic document-processing capability rather than statistical analysis support itself.
The skill introduces generic document-conversion and OCR capability via external binaries, which materially increases attack surface for a statistics-focused tool. In this context, broader ingestion of arbitrary office, PDF, and image files is more dangerous because users may submit untrusted research artifacts, causing the host to process attacker-controlled documents with heavyweight parsers.
This code feeds attacker-supplied office documents into LibreOffice conversion, which has a long history of parser and document-processing attack surface. Even without shell injection, invoking a large external parser on untrusted files can expose the host to denial-of-service or exploitation of vulnerabilities in the converter, and this preprocessing utility broadens the skill beyond its core statistics purpose.
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,
)
This invokes LibreOffice on untrusted XLS files for conversion, exposing the environment to a complex external file parser. The main risk is not command injection but unsafe processing of adversarial documents, which can lead to crashes, resource exhaustion, or exploitation of converter vulnerabilities.
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)],
Running pdftotext on untrusted PDFs creates exposure to parser bugs and decompression/resource-exhaustion issues in external PDF tooling. The command is not shell-injectable as written, but processing arbitrary attacker-controlled PDFs still expands the attack surface of the skill host.
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,
)
The OCR path automatically sets Tesseract language selection to "chi_sim+eng" when those language packs are available. This imposes a specific language/locale preference in behavior without any user opt-in or documented justification, which matches the language-policy violation criteria.
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
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 calls execute external commands. Without careful input validation, this enables command injection.
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,
)
Natural-language strings in the module description, CLI description, and system prompt are written to require Chinese-language behavior, including a fixed instruction to output Markdown in that language context. The file does not provide any language or locale opt-in/out mechanism, which can violate language-choice policy for general-purpose skills.
The code performs a remote chat-completions API call that is not obviously required for the core task of descriptive statistics computation. This expands the attack surface and creates data egress, dependency, and availability risks that are out of scope for a purely local statistics utility.
The skill sends trial-derived statistical results and metadata (for example trial_id, population, group labels, sample size, and endpoint summaries) to an external LLM service for interpretation, despite presenting itself as a local clinical-trial statistics helper. In a clinical context, even derived data can be sensitive or regulated, and this creates a confidentiality and compliance risk if operators assume processing remains local.
Clinical trial data and metadata are embedded into a prompt and transmitted externally without any user-facing warning in this file. In regulated medical/pharma workflows, undisclosed external sharing can violate confidentiality expectations, contractual controls, or data-handling requirements even if the transmitted content is partially aggregated.
Untrusted fields such as trial_id, population, and potentially group labels are interpolated directly into the LLM prompt, allowing an attacker to embed natural-language instructions that can influence the model's interpretation output. Although this does not lead to code execution here, it can corrupt clinical analysis narratives, suppress limitations, or produce misleading conclusions in a sensitive medical decision-support context.
Detected: suspicious.dynamic_code_execution