Back to skill

Security audit

generic-drug-scout

Security checks for vulnerabilities and agentic risk

Overview

The skill has a coherent PatSnap report-generation purpose, but it needs review because it combines sensitive local config access, unsafe overwrite behavior, and generated HTML opened from external data.

Review before installing or running. Use only in a workspace where PatSnap MCP access is intended, avoid --overwrite except on a dedicated output folder, do not point --target at existing project/home directories, and treat generated HTML/CSV as untrusted until the serialization and export issues are fixed.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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 (4)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/create_static_report_html.py:33
Finding

Stored JavaScript Injection Through Unsafe JSON Embedding

Content
View full analysis
str: params = report_data.get("params") or {} seed = ( f" window.INITIAL_REPORT_PARAMS = {json.dumps({'date_from': params.get('date_from'), 'date_to': params.get('date_to')}, ensure_ascii=False)};\n" f" window.INITIAL_REPORT_DATA = {json.dumps(report_data, ensure_ascii=False)};\n" ) if MARKER not in html: raise RuntimeError("Could not find init marker in template") html = html.replace(MARKER, seed + MARKER, 1) ``` The equivalent vulnerable construction in `scripts/create_seeded_screening_platform.py` is: ```python def inject_initial_data(index_path: Path, data: dict, date_from: str, date_to: str) -> None: html = index_path.read_text(encoding="utf-8") seed = ( f" window.INITIAL_REPORT_PARAMS = {json.dumps({'date_from': date_from, 'date_to': date_to}, ensure_ascii=False)};\n" f" window.INITIAL_REPORT_DATA = {json.dumps(data, ensure_ascii=False)};\n" ) if MARKER not in html: raise RuntimeError("Could not find init marker in index.html") html = html.replace(MARKER, seed + MARKER, 1) index_path.write_text(html, encoding="utf-8") ``` The equivalent vulnerable construction in `scripts/generate_seeded_platform.py` is: ```python html = index_path.read_text(encoding="utf-8") seed = ( f" window.INITIAL_REPORT_PARAMS = {json.dumps({'date_from': args.date_from, 'date_to': args.date_to}, ensure_ascii=False)};\n" f" window.INITIAL_REPORT_DATA = {json.dumps(data, ensure_ascii=False)};\n" ) if MARKER not in html: raise SystemExit("Could not ...[truncated 2426 chars]
Remediation
View remediation
``` Populate it with JSON that is safe for HTML text context, and then parse its `textContent`: ```javascript const reportData = JSON.parse( document.getElementById("initial-report-data").textContent ); ``` 3. At minimum, encode HTML-significant characters before insertion: ```python safe_json = ( json.dumps(report_data, ensure_ascii=False) .replace("<", "\\u003c") .replace(">", "\\u003e") .replace("&", "\\u0026") ) ``` 4. Apply the same shared safe-serialization function in all three generation scripts. 5. Validate the report structure and accepted field types before generating HTML. 6. Add regression tests using values containing: ```text

T09 · Insecure Skill Coding Practices

Error
Location
scripts/generate_seeded_platform.py:14
Finding

Arbitrary Recursive Directory Deletion Through Unsafe Overwrite Targets

Content
View full analysis
None: if dst.exists(): if not overwrite: raise SystemExit(f"Target already exists: {dst}. Pass --overwrite to replace it.") shutil.rmtree(dst) shutil.copytree(src, dst) ``` ### Technical Analysis Both scripts accept an arbitrary path through `--target`. When `--overwrite` is present and the target exists, the entire target is recursively deleted with `shutil.rmtree()`. No validation rejects sensitive locations such as: - A filesystem or drive root. - The user's home directory. - The current project directory. - The Skill package itself. - An unrelated directory that was not created by this application. The primary script, `create_seeded_screening_platform.py`, includes an `ensure_safe_target()` function, demonstrating that target validation was anticipated. ...[truncated 1265 chars]
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
assets/platform-template/app/server.py:344
Finding

Local File Disclosure Through Incorrect Path Containment Validation

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
assets/platform-template/app/index.html:529
Finding

Spreadsheet Formula Injection in CSV Export

Content
View full analysis
[row.drug_name,row.drug_type,row.phase,row.assignee,row.compound_expiry,row.crystal_expiry,row.delta,row.match_level,row.compound_patent,row.crystal_patent,row.notes]); const csv = [headers, ...rows].map(cols => cols.map(value => `"${String(value ?? "").replace(/"/g, '""')}"`).join(",")).join("\n"); const blob = new Blob(["\ufeff" + csv], { type: "text/csv;charset=utf-8" }); const url = URL.createObjectURL(blob); const a = document.createElement("a"); a.href = url; a.download = "仿药速探筛查结果.csv"; a.click(); URL.revokeObjectURL(url); } ``` ### Technical Analysis The exporter escapes double quotes but does not neutralize spreadsheet formula prefixes. Values beginning with characters such as the following may be interpreted as formulas when opened in spreadsheet software: ```text = + - @ ``` Leading spaces, tabs, carriage returns, or other control characters may also be used to bypass simplistic prefix checks in some spreadsheet clients. CSV quoting prevents delimiter injection but does not reliably force spreadsheet applications to treat a cell as plain text. The exported fields originate from MCP report data and can include externally controlled drug names, assignee names, patent values, match labels, and notes. ### Attack Path 1. An attacker causes an MCP-backed report field to begin with a spreadsheet formula marker. 2. The frontend stores the field in `state.rows`. 3. The user selects the CSV export function. 4. The exporter quotes the value but leaves the formula prefix intact. 5. The user opens the downloaded CSV in a spreadsheet application. 6. The spreadsheet interprets the a ...[truncated 843 chars]
Remediation
View remediation
columns.map(safeCsvCell).join(",")) .join("\n"); ``` Further hardening: 1. Apply protection to every field, not only selected text columns. 2. Account for leading whitespace and control characters. 3. Document that exported values are treated as text. 4. Where practical, generate a typed spreadsheet format with cells explicitly marked as strings. 5. Add tests for `=`, `+`, `-`, `@`, tabs, carriage returns, and leading whitespace. 6. Verify behavior in the spreadsheet applications expected to consume the report. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (17)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 36)May include surrounding context.

md
- `index.html`:前端报告 UI,包含 V1 价值亮点弹窗。

Agent Config Directory Access

High
Category
Agent Snooping
Confidence
92% confidence
Finding

The skill explicitly depends on reading ~/.codex/config.toml, which is part of the agent's configuration directory and may contain sensitive MCP endpoint details or other secrets. Access to agent config materially raises the sensitivity of the skill because compromising or over-reading this file can expose credentials, internal service topology, or reusable connection metadata.

Content

Scanner excerpt · SKILL.md (reported line 40)May include surrounding context.

md
- `server.py`:本地 HTTP 服务和由 MCP 支撑的 `/api/search` 端点。
- `assets/`:页面使用的本地图片。

后端期望 `~/.codex/config.toml` 中存在以下 MCP 服务名:

- `zhihuiya_logic_096456`:用于医药情报。
- `zhihuiya_logic_2b0355`:用于 PatSnap 专利检索/获取。

Agent Config Directory Access

High
Category
Agent Snooping
Confidence
93% confidence
Finding

This instruction tells implementers to read MCP URLs from ~/.codex/config.toml, reinforcing direct dependency on sensitive agent configuration. Even though it advises not to hardcode API keys, pulling connection data from the config directory still creates a high-value access path that could leak secrets or enable unauthorized reuse of internal MCP endpoints.

Content

Scanner excerpt · SKILL.md (reported line 165)May include surrounding context.

md
更新 `server.py` 时:

- 不要在平台文件中嵌入 API key。
- 从 `~/.codex/config.toml` 读取 MCP URL。
- 除日期窗口外,保持 V1 查询参数固定为小分子 + CN + 晶型专利。
- 保留独立的 `rows` 和 `not_promoted` 输出,使 UI 能区分主表候选和排除记录。
- `rows` 是经过药物证据验证后进入主表的候选。

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The instructions, warnings, and setup guidance are presented only in Chinese, which forces a specific language experience on users. The policy allows locale constraints only when justified or when users are given a language choice, neither of which is present here.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding

The skill describes capabilities that read local configuration, write files, invoke network-backed MCP services, and launch local processes, but it declares no explicit tool scope or permission boundaries. In an agent ecosystem, missing scope metadata increases the chance the skill is run with broader-than-necessary privileges, making unintended file, network, or process actions more likely.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · SKILL.md (reported line 52)May include surrounding context.

先运行实时 MCP 筛查:

powershell
python generic-drug-scout-v1\scripts\create_seeded_screening_platform.py --target .\仿药速探V1_真实结果平台 --window-years 2 --overwrite

然后根据 MCP 结果 JSON 创建静态报告:

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · SKILL.md (reported line 52)May include surrounding context.

先运行实时 MCP 筛查:

powershell
python generic-drug-scout-v1\scripts\create_seeded_screening_platform.py --target .\仿药速探V1_真实结果平台 --window-years 2 --overwrite

然后根据 MCP 结果 JSON 创建静态报告:

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill instructs the agent to automatically open a generated HTML report in the default browser immediately after creation, without warning or confirmation. Launching a local process as a side effect can surprise users, and opening HTML generated from external MCP data increases risk if the report contains unsafe active content or if browser invocation is abused.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

This section makes immediate browser opening mandatory via exec or subprocess after file creation, again without a safety interstitial or user consent. Requiring process execution as part of normal completion normalizes unsolicited local actions and broadens the blast radius if file paths or HTML content are influenced by external or untrusted data.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The document declares lang="zh-CN", and the interface text and locale formatting are consistently hard-coded to Chinese. Under the policy, forcing a specific language or locale without user opt-in should be flagged unless the constraint is explicitly documented and justified as region-specific.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

The skill hardcodes Chinese labels and later returns multiple Chinese-only status strings and notes, which imposes a specific locale on users. There is no opt-in, locale selection, or documentation justifying that the skill is intentionally Chinese-only.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The mcp_call helper performs outbound HTTP POST requests carrying tool arguments, and those arguments later include drug names, country filters, patent numbers, and related search inputs. The file contains no warning, confirmation, or descriptive comment informing users that submitted search data will be sent to external MCP endpoints.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
86% confidence
Finding

This manifest-like JSON includes locale-specific values such as country "CN" and Chinese-language labels, which can reflect a fixed language/locale assumption. Under the policy, forcing a specific locale without opt-in or explicit justification is a natural-language policy concern.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

Multiple UI strings and the CLI description are fixed in Chinese, replacing interface text and report messaging without any opt-in or alternative locale handling. This can violate a language/locale policy when skills are expected to avoid forcing a specific language unless the constraint is explicitly documented and justified.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
78% confidence
Finding

This code reads a user-scoped configuration file from ~/.codex/config.toml and extracts MCP server URLs, which is access to potentially sensitive local configuration data. There is no confirmation prompt, user-facing warning, or explanatory comment/docstring near this access to disclose that the server depends on reading local config.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
79% confidence
Finding

The default target directory name is set to a Chinese-only string, which imposes a specific locale in user-facing behavior without any opt-in or alternative. The file does not indicate that the skill is region-specific or offer a language choice, so this may conflict with language/locale policy expectations.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
89% confidence
Finding

The argument parser description includes Chinese text only ("仿药速探 V1") in the user-facing CLI description, with no indication of language choice or opt-in. This can violate a language/locale policy when tools are expected to be locale-neutral or offer the user a choice.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.dynamic_code_execution

Dynamic code execution detected.

Critical
Code
suspicious.dynamic_code_execution
Location
scripts/create_seeded_screening_platform.py:25