Back to skill

Security audit

unisound-target-screening

Security checks for vulnerabilities and agentic risk

Overview

This skill mostly matches its stated drug-target screening purpose, but needs Review because it sends sensitive research inputs to a remote model and has an unverified fallback that can execute Python code outside the package.

Install only if you are comfortable sending target-screening inputs to the documented remote medical model service and have approval to use the API key this way. Avoid confidential, regulated, or proprietary R&D data unless the endpoint's retention and access terms are acceptable. Prefer JSON or trusted spreadsheet inputs, avoid untrusted Office/PDF/image files, and remove or pin the external _shared preprocessing fallback 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)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/run.py:250
Finding
API Credential Exposure Through Command-Line Arguments## Vulnerability Details **File Location**: `scripts/run.py:250-257` **Additional Location**: `SKILL.md:68-72` **Vulnerability Type**: Sensitive credential exposure through process arguments **Risk Level**: Medium ### Vulnerable Code ```python def main(): parser = argparse.ArgumentParser(description="药物靶点筛选 — 对候选靶点进行优先级排序") parser.add_argument("--input", required=True) parser.add_argument("--output", default="") parser.add_argument("--input-type", default="auto", choices=["auto", *sorted(SUPPORTED_FILE_TYPES)]) parser.add_argument("--sheet", default=""); parser.add_argument("--encoding", default="utf-8") parser.add_argument("--save-prepared", action="store_true") parser.add_argument("--appkey", required=True, help="内部医疗大模型鉴权key(必填)") args = parser.parse_args() ``` The documented invocation also explicitly places the secret on the command line: ```bash python3 scripts/run.py --input input.json --output output.json --appkey YOUR_KEY ``` ### Technical Analysis The API bearer token is accepted as a normal command-line argument. Command-line arguments may be exposed through shell history, process inspection utilities, operating-system process interfaces, CI/CD logs, job schedulers, crash reports, and orchestration telemetry. Although the token is subsequently transmitted over HTTPS, transport encryption does not protect it from local disclosure before the request is made. The issue is particularly relevant on shared systems or where process metadata and execution logs are accessible to users other than the process owner. ### Attack Path 1. A user follows the documented command and supplies a valid API key with `--appkey`. 2. The complete command is recorded in shell history, automation logs, or process metadata. 3. A local user, administrator, monitoring service, or log reader accesses that information. 4. The exposed token is extracted. 5. The token is reused to make ...[truncated 619 chars]
Remediation
## Remediation Suggestions - Remove the `--appkey` command-line option for production use. - Read the credential from a protected environment variable or an operating-system secret store. - Prefer a secret manager or inherited file descriptor for automated deployments. - If a credential file is supported, require restrictive permissions and avoid printing its contents or path unnecessarily. - Update `SKILL.md` so examples do not encourage users to place secrets directly in commands. - Ensure application errors, request diagnostics, and CI logs never include authorization headers. - Rotate any token that may already have appeared in shell histories or execution logs.

T07 · Tool Hijacking and Spoofing

Error
Location
scripts/run.py:268
Finding
Arbitrary Code Execution Through Unverified Shared-Module Fallback## Vulnerability Details **File Location**: `scripts/run.py:268-283` **Vulnerability Type**: Dynamic execution of an unverified Python module outside the skill package **Risk Level**: High ### Vulnerable Code ```python except PreprocessError as exc: # 回退到 _shared/doc-preprocess 尝试处理 try: _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) input_type = _sp.detect_input_type(input_path, args.input_type) if input_type == "json": data = load_json(args.input) else: artifact = _sp.load_input_artifact(input_path, input_type, args.encoding, args.sheet) ``` ### Technical Analysis When local preprocessing raises `PreprocessError`, the program constructs a path outside the project package and executes `_shared/doc-preprocess/scripts/preprocess.py` through `exec_module`. Python module loading executes all module-level statements, not merely the preprocessing functions used afterward. The code only checks whether the directory exists. It does not verify the module's cryptographic digest, trusted ownership, filesystem permissions, package provenance, or expected version. Consequently, the security of this skill depends on the integrity of an external file that was not part of the reviewed project. This is a tool-hijacking condition: a legitimate-looking preprocessing fallback can be replaced so that invocation executes attacker-controlled logic. ### Attack Path 1. An attacker obtains write access to the expected `_shared/doc-preprocess/sc ...[truncated 1337 chars]
Remediation
## Remediation Suggestions - Remove the runtime fallback to an external Python source file. - Package the preprocessing implementation as a normal, versioned dependency installed from a trusted source. - Pin the exact dependency version and verify its integrity during installation. - If dynamic loading is unavoidable, use a fixed administrator-controlled path and verify a pinned cryptographic hash before import. - Reject modules that are writable by untrusted users or whose directory hierarchy has unsafe ownership or permissions. - Avoid executing source modules merely to access document-parsing functions; use a narrowly defined and authenticated service or subprocess interface instead. - Run the skill in a sandbox with minimal filesystem, environment, credential, and network access. - Treat preprocessing failures as errors rather than silently crossing into a different trust boundary.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/run.py:140
Finding
Prompt Injection Through Untrusted Target-Screening Fields## Vulnerability Details **File Location**: `scripts/run.py:140-157` **Vulnerability Type**: Indirect prompt injection through imported document and target data **Risk Level**: Medium ### Vulnerable Code ```python user_prompt = f"""请分析以下靶点筛选结果: 适应症:{disease} 候选靶点数:{len(ranked)} 排序结果: ```json {json.dumps(ranked, ensure_ascii=False, indent=2)} ``` 评分规则:priority_score = evidence×2 + druggability×1.5 - safety_risk(high=3, medium=2, low=1) 优先级:score≥7=high, 4≤score<7=medium, <4=low 请解读排序结果,为每个靶点给出推荐理由,分析风险,给出下一步建议。""" text = _call_llm(SYSTEM_PROMPT, user_prompt, appkey) ``` ### Technical Analysis User-controlled values—including the disease name, target name, mechanism, evidence, druggability, safety risk, and references—are serialized directly into the model prompt. These values may originate from JSON, text, spreadsheets, office documents, PDFs, or OCR output. The prompt does not explicitly tell the model that embedded content is untrusted data and must never be interpreted as instructions. Markdown code fences provide formatting but are not a security boundary. A crafted field can therefore contain instructions that compete with the intended analysis request. The locally calculated numeric ranking remains deterministic and is not directly changed by this injection. However, the model-generated `text` is returned as authoritative-looking analysis and is intended to be rendered to the user, allowing injected content to manipulate recommendations, omit warnings, or misrepresent the structured scores. ### Attack Path 1. An attacker prepares an accepted input document or data file. 2. A target field or reference contains an instruction such as directing the model to ignore the requested analysis, mark a specified target as safest, or suppress the disclaimer. 3. The preprocessing logic preserves that value in the normalized target data. 4. `json.dumps(ranked, ...)` embeds the malicious instruction in ...[truncated 951 chars]
Remediation
## Remediation Suggestions - Add explicit system-level instructions that all imported fields are untrusted data and that instructions found inside them must not be followed. - Use a structured API input or schema-constrained model interface where available instead of interpolating data into free-form instructions. - Separate trusted instructions from untrusted data with clearly labeled boundaries, while recognizing that delimiters alone are not sufficient protection. - Validate field lengths and permitted formats, especially for target identifiers, categorical scores, and references. - Apply output validation to ensure every input target is represented consistently with its deterministic score and priority level. - Generate critical ranking statements directly from locally calculated structured data rather than allowing the model to redefine them. - Require human review before using generated recommendations in consequential research decisions. - Preserve and prominently render the deterministic data separately from the model narrative so discrepancies are evident.
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 (15)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The skill claims to be based on Open Targets-style target association/prioritization, yet the implementation description instead mandates sending data to an undeclared external medical LLM API and does not implement the referenced database retrieval or analysis workflow. This is dangerous because users may rely on inaccurate provenance and unknowingly transmit sensitive R&D data to a third-party service under false assumptions about how results are produced.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding
The skill claims to be based on Open Targets-style target association/prioritization, yet the implementation description instead mandates sending data to an undeclared external medical LLM API and does not implement the referenced database retrieval or analysis workflow. This is dangerous because users may rely on inaccurate provenance and unknowingly transmit sensitive R&D data to a third-party service under false assumptions about how results are produced.

Lp3

Medium
Category
MCP Least Privilege
Confidence
87% confidence
Finding
The skill advertises executable capabilities including filesystem access, shelling out, environment access, and network use, but does not declare any tool scope or permissions boundary. This creates an over-privileged and opaque execution model where operators and users cannot easily assess or constrain what the skill may do, increasing the chance of unintended file access, command execution, or data exfiltration.

Natural-Language Policy Violations

Medium
Confidence
88% confidence
Finding
The skill name and all user-facing documentation are in Chinese, and the OCR/tooling note explicitly requires Chinese language data support, but the file does not state that the skill is intentionally limited to Chinese-speaking users or offer a language choice. This can violate locale/language policy when a skill imposes a specific language without opt-in.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The documentation states that user-supplied inputs must be sent to an internal medical model API, but it provides no clear privacy, retention, confidentiality, or data-handling warning. In a pharmaceutical R&D context, uploaded targets, mechanisms, evidence, and source references may be commercially sensitive, so silent mandatory transmission creates significant confidentiality and compliance risk.

Description-Behavior Mismatch

Medium
Confidence
94% confidence
Finding
The file implements a broad, multi-format document ingestion pipeline unrelated to the narrowly described target-screening function. Scope expansion is dangerous in agent skills because it introduces extra parsers, file handlers, and execution paths that enlarge the attack surface without a clear product need, making abuse and latent parser bugs more likely.

Natural-Language Policy Violations

Medium
Confidence
89% confidence
Finding
The module docstring is written entirely in Chinese and presents the tool as a general-purpose preprocessing utility, but nowhere in this file is there any indication that the language choice is optional or limited to a region-specific use case. For a general utility skill, hard-coding a single locale in user-facing natural language can violate language-choice policy when no opt-in is provided.

Context-Inappropriate Capability

Medium
Confidence
89% confidence
Finding
The utility executes local document-conversion and OCR binaries on supplied files, giving the skill a powerful host-interaction capability that is not justified by the manifest. In practice, this creates a meaningful attack surface for parser exploits, malicious documents, local file processing abuse, and denial of service, and the mismatch with the stated skill purpose makes the behavior more suspicious rather than less.

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
72% confidence
Finding
The code invokes LibreOffice/soffice on attacker-supplied office documents, which is a risky parser/converter surface even though it does not use shell expansion. In a skill whose stated purpose is target screening rather than broad document conversion, accepting arbitrary DOC inputs and handing them to a powerful local executable increases the chance of file-based RCE, SSRF-like external fetches, macro-related behaviors, or denial of service through malformed documents.

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
74% confidence
Finding
This launches LibreOffice to convert user-controlled XLS files, exposing the system to vulnerabilities in a large external parser stack. While there is no shell injection, the security issue is unsafe processing of untrusted legacy office content by a local executable that is broader and more dangerous than needed for the declared pharmaceutical screening use case.

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
Calling pdftotext on untrusted PDFs is not command injection, but it does delegate parsing to an external binary that may contain memory-safety or resource-exhaustion vulnerabilities. The risk is lower than the office-conversion cases, but in an agent skill context this still broadens the attack surface beyond what is necessary for target-screening logic.

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
96% confidence
Finding
The system prompt is entirely in Chinese and explicitly requires '输出Markdown格式', while the skill description and CLI do not indicate that Chinese is optional or region-specific. This creates a language/locale policy issue because the skill appears to mandate a specific language without user opt-in.

Ssd 3

Medium
Confidence
95% confidence
Finding
User-supplied disease and target data are interpolated directly into the prompt sent to an external LLM API without clear delimitation or defensive handling. Because this skill processes potentially sensitive preclinical or R&D target-screening inputs, prompt injection and unintended disclosure risks are elevated: malicious content inside fields could steer the model, and confidential research details are transmitted to a third-party service.

Static analysis

Detected: suspicious.dynamic_code_execution

Dynamic code execution detected.

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