Back to skill

Security audit

unisound-academic-material-generation

Security checks for vulnerabilities and agentic risk

Overview

The skill is a disclosed medical-writing generator, but it conditionally runs preprocessing code from outside the reviewed package, so it needs manual review before installation.

Install only if you trust both this skill and the runtime location of _shared/doc-preprocess. Treat all submitted inputs as sent to the configured remote medical-model API, avoid PHI or confidential strategy unless your organization approves that flow, sandbox document conversion/OCR for untrusted files, and avoid placing long-lived API keys directly in shell commands.

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

T07 · Tool Hijacking and Spoofing

Warning
Location
scripts/run.py:193
Finding
Unverified Python Module Execution from Outside the Audited Skill Directory## Vulnerability Details **File Location**: `scripts/run.py`, lines 193–200 **Vulnerability Type**: Untrusted external module loading **Risk Level**: Medium ```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 directory and executes `_shared/doc-preprocess/scripts/preprocess.py` through `exec_module()`. Python modules can run arbitrary top-level code during import. The implementation verifies only that the shared directory exists; it does not verify the module's ownership, permissions, canonical trusted location, version, or cryptographic integrity. Consequently, the effective executable code is not limited to the reviewed package. Exploitation requires an attacker to create or modify the module at the computed shared path. If that condition is met, a preprocessing error provides the trigger needed to load it. ### Attack Path 1. The attacker obtains write access to the computed `_shared/doc-preprocess/scripts` directory or its `preprocess.py` file. 2. The attacker places malicious top-level Python code in `preprocess.py`. 3. The attacker or a victim invokes the skill with an input that causes the local preprocessor to raise `PreprocessError`, such as an input requiring unavailable preprocessing support. 4. The exception handler locates the external shared directory. 5. `exec_module()` executes the malicious module during import. 6. The payload runs with the same operating-system identity, filesystem access, ...[truncated 633 chars]
Remediation
## Remediation Suggestions 1. Remove the dynamic fallback and keep all executable preprocessing logic inside the reviewed skill package. 2. If shared preprocessing is required, distribute it as a version-pinned, integrity-verified dependency installed from a trusted source. 3. Resolve the module path with `Path.resolve()` and verify that it is under an explicitly configured trusted root. 4. Verify the module against an allowlisted cryptographic hash or signed manifest before loading it. 5. Reject shared modules or parent directories writable by untrusted users. 6. Avoid executing arbitrary Python source as a recovery mechanism. Prefer a narrow, versioned interface to a separately managed component. 7. Run document preprocessing in a sandbox with minimal filesystem, network, and environment access.

T09 · Insecure Skill Coding Practices

Note
Location
scripts/run.py:185
Finding
Bearer API Credential Passed Through a Command-Line Argument## Vulnerability Details **File Location**: `scripts/run.py`, line 185; documented invocation in `SKILL.md`, line 67 **Vulnerability Type**: Command-line credential exposure **Risk Level**: Low ```python parser.add_argument("--appkey", required=True, help="内部医疗大模型鉴权key(必填)") ``` The documented command exposes the intended usage: ```bash python3 scripts/run.py --input input.json --output output.json --appkey YOUR_KEY ``` ### Technical Analysis The medical model bearer token must be supplied as the value of `--appkey`. Command-line arguments may be exposed through process inspection facilities, shell history, diagnostic reports, orchestration metadata, audit logs, or command logging performed by wrappers and job runners. Although the application does not deliberately print the credential, accepting a long-lived secret on the command line creates an avoidable disclosure channel. The token is subsequently placed in the HTTP `Authorization` header for the disclosed model API. Exploitation depends on another user, monitoring service, or logging system having access to command histories or process arguments while the command is running or after it has been recorded. ### Attack Path 1. A user launches the skill with a real API key in the `--appkey` argument. 2. The full command is saved in shell history, captured by orchestration logs, or observed through local process-inspection facilities. 3. An unauthorized local user, administrator, log reader, or compromised monitoring component retrieves the argument value. 4. The recovered key is submitted as a bearer token to the configured medical-model API. 5. The attacker can use the credential until it expires or is revoked, subject to the key's server-side permissions and quotas. ### Impact Assessment Exposure could allow unauthorized use of the associated model API account, consumption of its quota, generation of costs, and requests under the credential owner's identit ...[truncated 321 chars]
Remediation
## Remediation Suggestions 1. Obtain the credential from a dedicated secret manager or protected credential provider. 2. Alternatively, read it from standard input without terminal echo using `getpass.getpass()`. 3. If environment-based injection is required, ensure the runtime prevents environment values from appearing in logs or diagnostic output. 4. Keep any credential file outside the project directory and restrict it to the owning user, such as mode `0600` on supported systems. 5. Remove `--appkey` from documented examples and clearly warn users not to place secrets in shell commands. 6. Use short-lived, narrowly scoped tokens with server-side rate limits and rapid revocation support. 7. Rotate any key that may already have been captured in command history or execution logs.
Vulnerability Patterns
  • 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
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (16)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The declared purpose is academic material generation, but the skill also performs broad document ingestion and local external-program execution for parsing PDFs, Office files, spreadsheets, and images. That mismatch is risky because users may supply untrusted files assuming simple text generation, while the implementation expands the attack surface to parser bugs, command misuse, unsafe file conversion, and unexpected handling of sensitive local content.

Lp3

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding
The skill advertises capabilities that imply filesystem access, shell execution, environment access, and network use, but it does not declare any explicit tool scope or permissions boundary. This is dangerous because operators and downstream systems cannot enforce least privilege, and a skill that processes untrusted documents plus invokes external tools can be abused to read sensitive files, execute unsafe conversions, or exfiltrate data over the network.

Natural-Language Policy Violations

Medium
Confidence
85% confidence
Finding
The natural-language content of the skill, including the title, description, usage guidance, and examples, is presented only in Chinese. Under the language/locale policy rule, forcing a specific language without user opt-in or an explicit justified regional constraint is a policy concern.

Description-Behavior Mismatch

Medium
Confidence
87% confidence
Finding
This utility supports broad extraction from many document, spreadsheet, PDF, JSON, and image formats, which exceeds the narrow stated purpose of academic material generation. That mismatch increases the skill's attack surface by enabling ingestion and transformation of arbitrary local content and complex file formats that are not obviously necessary for the declared role.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The module docstring is written entirely in Chinese, which imposes a specific language on users or maintainers without offering any language choice or documenting a justified locale restriction. This matches the language/locale policy violation category for natural-language content in code files.

Context-Inappropriate Capability

Medium
Confidence
90% confidence
Finding
Invoking LibreOffice/soffice for arbitrary office-document conversion gives the skill a powerful file-processing capability outside its stated generation role. Because these are large external parsers handling attacker-supplied content, they meaningfully increase the chance of parser exploitation, local file access side effects, or denial-of-service in the host environment.

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
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
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
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
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
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Context-Inappropriate Capability

Medium
Confidence
85% confidence
Finding
The OCR path allows arbitrary image text extraction via tesseract, a capability broader than the stated academic material generation purpose. This expands the skill from content generation into general document ingestion and creates additional attack surface through untrusted image parsing and potential extraction of unintended sensitive text from uploaded images.

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.

Natural-Language Policy Violations

Medium
Confidence
90% confidence
Finding
The top-level skill description is written to generate this academic material as a Chinese-language skill, and the prompts throughout the file are hard-coded in Chinese. There is no opt-in, language selection, or documented region-specific justification, which can violate language/locale policy requirements.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill sends user-provided material content, including medical academic inputs and references, to an external remote LLM endpoint without any in-code disclosure, consent flow, data classification check, or redaction step. In a medical/pharma context, these inputs may contain confidential strategy, unpublished evidence, regulated medical information, or personal data, so undisclosed transfer to a third party materially increases confidentiality and compliance risk.

Natural-Language Policy Violations

Medium
Confidence
88% confidence
Finding
The system prompt is entirely in Chinese and instructs the model's behavior without offering any language selection mechanism. This enforces a specific locale by default rather than letting the user opt in or documenting why Chinese-only output is required.

Missing User Warnings

Low
Confidence
82% confidence
Finding
The script requires an appkey and uses it as a Bearer token for the external API request, but provides no warning about supplying sensitive credentials on the command line. Command-line secrets can be exposed through shell history or process listings, and the file contains no cautionary message about this risk.

Static analysis

Detected: suspicious.dynamic_code_execution

Dynamic code execution detected.

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