Back to skill

Security audit

药物化学信息提取服务

Security checks for vulnerabilities and agentic risk

Overview

The skill claims to be a PubChem chemistry lookup, but it actually routes queries and a persisted API key through a Xiaobenyang MCP client with unclear boundaries.

Review before installing. Only use this skill if you intend to trust Xiaobenyang with both the API key and the chemical queries, and avoid entering valuable credentials until the publisher removes the PubChem/Xiaobenyang mismatch, stops plaintext .env persistence or documents it clearly, validates the outbound endpoint, and narrows the callable API surface.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/config.py:48
Finding

API Key Persisted in an Unprotected Plaintext Environment File

Content
View full analysis
bool: """将API key保存到.env文件""" try: env_path = Path(".env") lines = [] if env_path.exists(): lines = env_path.read_text(encoding="utf-8").splitlines() found = False new_lines = [] for line in lines: if line.startswith("XBY_APIKEY="): new_lines.append(f"XBY_APIKEY={api_key}") found = True else: new_lines.append(line) if not found: new_lines.append(f"XBY_APIKEY={api_key}") env_path.write_text("\n".join(new_lines) + "\n", encoding="utf-8") os.environ["XBY_APIKEY"] = api_key return True except Exception as e: print(f"保存API key失败: {e}") return False def set_api_key(api_key: str) -> bool: """设置API key并持久化到.env""" if not api_key or not api_key.strip(): return False api_key = api_key.strip() if not save_api_key_to_env(api_key): return False # 更新全局 settings 实例 settings.api_key = api_key return True ``` ### Technical Analysis The Skill explicitly collects an API credential and persists it in a project-local `.env` file as plaintext. The write operation does not enforce restrictive file permissions, use an operating-system credential store, perform an atomic replacement, or verify that the target is a regular file rather than a symbolic link. The key is interpolated directly into an environment-file line. `set_api_key()` removes only leading and trailing whitespace. It does not reject embedded carriage-return or newline characters. Consequently, a crafted value can insert additional entries into `.env`. Those entries can affect later executions when ...[truncated 2272 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/call_api.py:48
Finding

API Credential Can Be Redirected to a Configurable Untrusted Endpoint

Content
View full analysis
HttpResult: """调用小笨羊MCP工具""" url = f"{settings.base_url}/api" mcp_id = mcp_id or settings.mcp_id api_key = get_api_key() if not api_key: raise UpstreamError("API密钥未设置,请先调用 set_api_key()") headers = { "XBY-APIKEY": api_key, "func": tool_name, "mcpid": mcp_id, "Content-Type": "application/json", } # data = {k: str(v) if v is not None else "" for k, v in params.items()} t0 = time.time() try: resp = self._session.post( url=url, headers=headers, data=json.dumps(params), timeout=settings.timeout_seconds, ) ``` ### Technical Analysis `Settings` uses the prefix `XBY_GAOKAO_` and loads values from both the process environment and `.env`. Therefore, `base_url` can be overridden through `XBY_GAOKAO_BASE_URL`. `call_tool()` concatenates the configured value with `/api` and sends the API key in the custom `XBY-APIKEY` header without validating the URL scheme, hostname, port, or resolved destination. The same request body contains the user's chemical name or CAS-number query. An attacker who can modify the process environment or `.env` can select an arbitrary HT ...[truncated 2505 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (31)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The skill presents itself as a chemistry lookup service but also manages local .env state, reads environment variables, and references a seemingly unrelated 'XBY_GAOKAO/小笨羊高考' configuration. This discrepancy suggests code or documentation reuse without proper isolation, creating a risk of credential misuse, unintended persistence, and calls to unrelated services.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The skill presents itself as a chemistry lookup service but also manages local .env state, reads environment variables, and references a seemingly unrelated 'XBY_GAOKAO/小笨羊高考' configuration. This discrepancy suggests code or documentation reuse without proper isolation, creating a risk of credential misuse, unintended persistence, and calls to unrelated services.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
96% confidence
Finding

该文件实现的是一个通用的“小笨羊MCP”远程工具调用客户端,实际行为与技能声明的“仅通过 PubChem API 提取药物化学信息”明显不一致。此类能力错配意味着技能可被用作任意远程工具调用代理,扩大了可访问功能面,若上层允许用户影响 tool_name、mcp_id 或 params,则可能被滥用于执行与药物信息提取无关的敏感操作。

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

call_tool 接口直接接受外部传入的 mcp_id、tool_name 和 params,并将其作为请求头和请求体发送到上游 MCP API,本质上支持调用任意 MCP 工具。对于一个宣称只做药物化学信息提取的技能,这属于过度授权/能力暴露问题;一旦攻击者可控这些参数,就可能借技能访问不应开放的远程功能、数据源或操作接口。

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/config.py (reported line 13)May include surrounding context.

python
model_config = SettingsConfigDict(
        env_prefix="XBY_GAOKAO_",
        env_file=".env",
        env_file_encoding="utf-8",
        extra="ignore",
    )

Credential Access

High
Category
Privilege Escalation
Confidence
91% confidence
Finding

The custom model_post_init force-reads .env and extracts XBY_APIKEY, bypassing normal typed configuration boundaries and pulling in a credential unrelated to the advertised PubChem service. This unnecessary secret access increases the chance of misuse, unintended disclosure, or hidden coupling to external services.

Content

Scanner excerpt · scripts/config.py (reported line 31)May include surrounding context.

python
default_year: int = 2025

    def model_post_init(self, __context):
        # 强制从 .env 文件读取 XBY_APIKEY
        env_path = Path(".env")
        if env_path.exists():
            content = env_path.read_text(encoding="utf-8")

Credential Access

High
Category
Privilege Escalation
Confidence
91% confidence
Finding

Creating a Path('.env') and conditionally reading it is part of explicit local credential access logic rather than passive configuration. In context, this supports secret harvesting and persistence behavior that is unnecessary for a public chemical lookup skill and therefore elevates security concern.

Content

Scanner excerpt · scripts/config.py (reported line 32)May include surrounding context.

python
def model_post_init(self, __context):
        # 强制从 .env 文件读取 XBY_APIKEY
        env_path = Path(".env")
        if env_path.exists():
            content = env_path.read_text(encoding="utf-8")
            for line in content.splitlines():

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/config.py (reported line 39)May include surrounding context.

python
if line.startswith("XBY_APIKEY="):
                    self.api_key = line.split("=", 1)[1].strip()
                    break
        # 如果环境变量有值,覆盖 .env 的值
        env_val = os.getenv("XBY_APIKEY", "")
        if env_val:
            self.api_key = env_val

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The skill persists and retrieves an unrelated XBY API credential even though the declared purpose is PubChem chemical information extraction. This creates unnecessary credential handling and local secret storage that broadens the attack surface, especially because the code can overwrite .env and expose or repurpose credentials unrelated to the advertised function.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The functions save_api_key_to_env and set_api_key give the skill the ability to modify and persist API credentials on the local filesystem without any necessity evident from the skill's stated purpose. This is dangerous because a skill intended only for data retrieval should not silently change host configuration or leave long-lived secrets behind in .env.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
96% confidence
Finding

The function dedicated to saving an API key into .env implements active credential persistence on disk, which materially increases the exposure window for secrets. Because this skill is supposed to extract PubChem data, local secret-writing behavior is disproportionate and could be abused to plant or overwrite credentials in the host environment.

Content

Scanner excerpt · scripts/config.py (reported line 48)May include surrounding context.

python
def save_api_key_to_env(api_key: str) -> bool:
    """将API key保存到.env文件"""
    try:
        env_path = Path(".env")
        lines = []
        if env_path.exists():
            lines = env_path.read_text(encoding="utf-8").splitlines()

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding

The skill declares no explicit tool scope or permission boundaries even though it appears capable of using environment access, file read/write, and network operations. In practice, this increases the blast radius of prompt-induced misuse, especially because the skill also instructs collecting and persisting credentials and calling external services.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The skill description does not disclose that user chemical queries and API credentials may be sent to external services. This is a transparency and privacy issue because users may reasonably expect a PubChem lookup but not realize their inputs and secrets are being routed to a third-party backend.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill instructs the model to ask for an API key and save it via configuration persistence without explaining storage, retention, or security implications. Collecting and persisting user credentials in this way can expose secrets to local compromise, accidental reuse by other skills, or leakage through logs and prompts.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The workflow example references a school-search function unrelated to chemical information extraction, indicating copy-paste drift or poor maintenance. While not an exploit by itself, this can cause the model to invoke the wrong tools or normalize unrelated capabilities, increasing the chance of unintended data access or external requests.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

类和函数文档字符串多次明确描述其用途是“调用小笨羊MCP API/工具”,这与技能清单中宣称的 PubChem API 化学信息提取服务不是同一意图。这里不是简单的文档不完整,而是代码文档主动表明了另一个上游系统和更通用的调用目的。

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

Settings 类的文档字符串写的是“"""小笨羊高考Skill配置"""”,表明该文件原始意图属于另一个高考相关技能,而非当前 manifest 中的药物化学信息提取服务。这种内联文档与技能宣称用途直接不符,显示出明显的意图/代码文档漂移。

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

Persisting an API key to .env without clear user consent or warning can cause unintended secret exposure through local files, backups, source control mistakes, or other processes reading the file. In a skill that should primarily query public chemical data, this behavior is not justified and materially increases secret-handling risk.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The project structure names the package as a gaokao skill rather than a chemistry skill, which reinforces the evidence of cross-purpose reuse. This inconsistency weakens trust in the skill boundary and may hide inherited code paths or configuration behaviors unrelated to the stated purpose.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
94% confidence
Finding

The dependency specification for requests is unpinned, allowing future installs to resolve to different versions over time. This creates supply-chain and reproducibility risk, and makes it impossible to determine from the manifest alone whether deployment will pick a vulnerable release.

Content

Scanner excerpt · requirements.txt (reported line 1)May include surrounding context.

text
requests>=2.31.0
pydantic>=2.7.0
pydantic-settings>=2.2.0
python-dotenv>=1.0.1

Unverifiable Dependency: requests has 16 known advisory(ies) (CVE-2014-1830 (Exposure of Sensitive Information to an Unauthorized Actor in Requests); CVE-2024-47081 (Requests vulnerable to .netrc credentials leak via malicious URLs); CVE-2024-35195 (Requests `Session` object does not verify requests after making first request wi) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
90% confidence
Finding

requests has known advisories, and because the manifest does not pin a specific version, there is no way to verify whether installed environments are using a fixed or affected release. In a service that calls external APIs, this uncertainty is meaningful because HTTP client flaws can affect confidentiality or request integrity depending on usage.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
93% confidence
Finding

The dependency specification for pydantic is unpinned, so installations are not reproducible and may silently pull in newer releases with breaking changes or known security issues. This weakens supply-chain control even if no specific vulnerable version is shown in the file.

Content

Scanner excerpt · requirements.txt (reported line 2)May include surrounding context.

text
requests>=2.31.0
pydantic>=2.7.0
pydantic-settings>=2.2.0
python-dotenv>=1.0.1

Unverifiable Dependency: pydantic has 4 known advisory(ies) (CVE-2021-29510 (Use of "infinity" as an input to datetime and date fields causes infinite loop i); CVE-2024-3772 (Pydantic regular expression denial of service); CVE-2021-29510 (Pydantic is a data validation and settings management using Python type hinting.) +1 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
87% confidence
Finding

pydantic has published advisories, but the unpinned requirement prevents verification that deployed instances are on a safe version. This is primarily an auditability and supply-chain control problem, though impact depends on whether affected parsing paths are reachable in the application.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
92% confidence
Finding

The pydantic-settings package is declared with only a minimum version, which leaves the actual installed version uncontrolled. That increases exposure to future vulnerable or incompatible releases and prevents reliable auditing of what code is deployed.

Content

Scanner excerpt · requirements.txt (reported line 3)May include surrounding context.

text
requests>=2.31.0
pydantic>=2.7.0
pydantic-settings>=2.2.0
python-dotenv>=1.0.1

Unverifiable Dependency: pydantic-settings has 1 known advisory(ies) (CVE-2026-58203 (pydantic-settings: NestedSecretsSettingsSource follows symlinks outside secrets_)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
86% confidence
Finding

pydantic-settings has at least one known advisory, and the lack of version pinning means the deployed version cannot be verified from this file. If the application uses secrets-loading features, vulnerable versions could increase risk of unintended file access or secret exposure.

Content

No source excerpt is available for this finding.