Back to skill

Security audit

中药方剂知识图谱

Security checks for vulnerabilities and agentic risk

Overview

The skill’s external knowledge-graph API use is coherent, but it persistently stores a user API key in a local plaintext .env file with weak disclosure and controls.

Install only if you are comfortable giving this skill a XiaoBenYang API key and having it stored in plaintext in a local .env file. Use a limited-scope key if possible, avoid shared workspaces, keep .env out of source control and backups, and rotate the key if it may have been exposed.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/config.py:39
Finding

API Credential Stored in an Unprotected Plaintext Environment File

Content
View full analysis

Vulnerability Details

File Location: scripts/config.py, lines 39-61
Vulnerability Type: Plaintext credential storage and environment-file injection
Risk Level: Medium

Vulnerable Code:

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

Technical Analysis

A user-supplied API credential is persisted in a predictable .env file as plaintext. The file is created using Path.write_text() without explicitly enforcing restrictive permissions. Consequently, its confidentiality depends on the process umask and the permissions of the containing directory.

The API key is also interpolated directly into an environment-file assignment without rejecting carriage returns or newline characters. A crafted key containing line breaks can introduce additional entries into .env. Those entries may subsequently be interpreted by this project or another dotenv-compatible process.

The Skill documentation explicitly directs the agent to collect and persist the credential, so this exposure occurs during the intended workflow rather than only through an exceptional code path.

Attack Path

Credential disclosure path:

  1. A user suppli ...[truncated 1521 chars]
Remediation
View remediation

Remediation Suggestions

  1. Prefer an operating-system credential store, secrets manager, or ephemeral environment variable instead of writing the key to the project directory.
  2. Obtain explicit user consent before persisting any credential and provide an option to keep it only in memory.
  3. If file persistence is unavoidable, create the secrets file atomically with owner-only permissions such as 0600; do not rely solely on the current umask.
  4. Reject API-key values containing carriage returns, newlines, NUL bytes, or other control characters before storage.
  5. Ensure .env is excluded from source control, build artifacts, logs, support bundles, and backups where appropriate.
  6. Use a dedicated secrets-file location outside the repository and document credential rotation and revocation procedures.
  7. Avoid printing credential-bearing exceptions or values and add tests confirming that malformed multiline keys are rejected.

T08 · Insecure Dependencies

Note
Location
requirements.txt:1
Finding

Unbounded Dependency Versions Permit Unreviewed Package Updates

Content
View full analysis

Vulnerability Details

File Location: requirements.txt, lines 1-4
Vulnerability Type: Non-reproducible and insufficiently constrained third-party dependencies
Risk Level: Low

Vulnerable Code:

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

Technical Analysis

Every dependency uses only an inclusive lower bound. Package resolution may therefore install any future release satisfying that constraint, including releases that were unavailable and unreviewed when the Skill was audited.

This prevents reproducible installation and broadens the supply-chain trust boundary. A compromised upstream release, malicious maintainer update, or newly introduced vulnerability could be incorporated automatically. No lock file or cryptographic package hashes are present in the reviewed project to constrain the resolved artifacts.

The audit found no evidence that the currently named packages are typosquatted or malicious. The finding concerns the unsafe resolution policy rather than a confirmed malicious dependency version.

Attack Path

  1. A dependency maintainer account or package distribution channel is compromised, or a permitted future release introduces malicious behavior.
  2. The hostile release retains a version number greater than or equal to the minimum specified in requirements.txt.
  3. A new installation resolves and downloads that release because no exact version or hash restricts it.
  4. Package installation or later import executes the compromised dependency code.
  5. That code runs with the privileges of the user or service installing or invoking the Skill.

Impact Assessment

A compromised dependency could access files, environment variables, the plaintext API key, and network resources available to the Python process. It could also alter API requests or responses and execute arbitrary Python behavior with the process owner's privilege ...[truncated 226 chars]

Remediation
View remediation

Remediation Suggestions

  1. Pin reviewed dependencies and transitive dependencies to exact versions through a generated lock file.
  2. Use cryptographic hashes, such as pip hash-checking mode, to verify downloaded distributions.
  3. Generate lock files from a trusted package index and retain provenance information for approved artifacts.
  4. Run automated vulnerability and dependency-integrity scanning in continuous integration.
  5. Update dependencies through a controlled review process rather than allowing automatic resolution to arbitrary future versions.
  6. Periodically regenerate pins so security fixes are adopted without sacrificing reproducibility.
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
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (28)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The skill description does not mention that it reads, writes, and persists API keys in local environment files and modifies runtime configuration. Handling secrets is materially different from simple knowledge-graph lookup, and undisclosed credential storage can expose sensitive data or create persistence risks on shared systems.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The skill description does not mention that it reads, writes, and persists API keys in local environment files and modifies runtime configuration. Handling secrets is materially different from simple knowledge-graph lookup, and undisclosed credential storage can expose sensitive data or create persistence risks on shared systems.

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
90% confidence
Finding

The post-init hook force-reads a specific API key from .env using custom file parsing instead of relying on standard settings mechanisms. This bypasses the declared env prefix model, increases the chance of loading unintended credentials, and normalizes direct secret scraping from local files in a skill whose stated purpose does not require explicit credential-management code.

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
90% confidence
Finding

The code checks for and reads the local .env file directly, which is a sensitive file that may contain multiple secrets unrelated to this skill. Even though only one key is extracted here, direct file access to a secret store is riskier than least-privilege environment access and is suspicious in context because the manifest does not describe credential-handling functionality.

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

Credential Access

High
Category
Privilege Escalation
Confidence
96% confidence
Finding

This function is explicitly designed to save an API key into a local .env file, creating a durable plaintext credential store inside the project workspace. In the context of a skill whose manifest does not mention authenticated external services, this is unnecessary secret persistence and increases the risk of accidental disclosure or misuse.

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 advertises network, environment, and file read/write capabilities without declaring any explicit tool scope or permission boundaries. This increases the attack surface because a user and the host platform cannot easily determine or constrain what the skill may access, especially since it also handles API keys and persists configuration locally.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The skill instructs the model to solicit a user API key and persist it locally without warning the user about storage, lifetime, scope, or access controls. This is dangerous because credentials may be written to disk in plaintext or exposed to other processes, backups, or users on the host environment.

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 an unrelated gaokao/school-search function, indicating the skill documentation may have been copied from another project without proper review. Such inconsistencies are risky because they suggest the routing logic and tool mapping may not match the stated domain, leading to unintended tool invocation or hidden generic functionality.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
86% confidence
Finding

This code performs an outbound HTTP POST carrying user-supplied parameters and authenticates with a sensitive API key in headers. While errors and success are logged, there is no user-facing print, confirmation, or warning comment/docstring disclosing that data will be sent to an external service.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The configuration class identifies itself as a different skill ('小笨羊高考Skill配置') than the manifest describes. This inconsistency is a supply-chain and trust signal problem: it suggests code reuse from another project or packaging mix-ups, making it harder to verify what the skill really does and whether hidden dependencies or behaviors were unintentionally included.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill includes logic to persist and manage an external API credential even though the declared functionality is a traditional Chinese medicine knowledge graph. This mismatch expands the skill's capability beyond its stated purpose, creates unnecessary secret-handling risk, and could enable undisclosed outbound access if the key is later used elsewhere.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The function writes the provided API key directly into a local .env file without any user-facing confirmation, warning, or secure-storage control. Persisting secrets this way can expose credentials through local file disclosure, accidental commits, backups, shared workspaces, or other tooling that reads project files.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
87% confidence
Finding

The skill name, description, and operational instructions are entirely in Chinese, and no alternative language option or opt-in is provided. Under the language/locale policy, forcing a specific language without user choice can be a natural-language policy violation unless the locale restriction is clearly documented and justified.

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 different gaokao-related skill, which is a strong indicator of template reuse and poor provenance control. While not directly exploitable by itself, it undermines confidence in the skill's integrity and raises the likelihood of latent unrelated code paths or misconfigurations.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
97% confidence
Finding

The dependency is specified with a lower-bound only (requests>=2.31.0), which makes builds non-reproducible and allows future installs to resolve to different versions, including versions later found vulnerable or behaviorally incompatible. Because the exact installed version is not constrained, security review and patch status verification are weakened.

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
91% confidence
Finding

requests has known advisories, and because the manifest does not pin an exact version, it is impossible to verify from this file whether deployed instances are using an affected release. The risk is contextual and indirect here, but the unverifiable version state is a real supply-chain security weakness.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
97% confidence
Finding

The dependency is unpinned (pydantic>=2.7.0), so installations may pick different versions over time, undermining reproducibility and making it difficult to know whether a deployed environment includes a vulnerable release. This is a supply-chain hygiene issue rather than an immediately exploitable code flaw in this file alone.

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
88% confidence
Finding

pydantic has published advisories, and the lack of version pinning means the deployed version cannot be confirmed as safe from the manifest alone. While this file does not prove an exploitable condition by itself, it leaves security posture unverifiable and increases supply-chain uncertainty.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
96% confidence
Finding

Using pydantic-settings>=2.2.0 without an upper bound or exact pin permits uncontrolled version drift across environments. That increases exposure to future vulnerable releases and makes auditing the effective dependency set difficult.

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 advisory listed, and with only a minimum version specified, the actual installed release may still be affected. This makes dependency risk assessment incomplete and can conceal vulnerable deployments.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
96% confidence
Finding

The unpinned python-dotenv>=1.0.1 allows any newer version to be installed, which can introduce vulnerable or breaking releases without code changes. This reduces build determinism and complicates incident response and advisory triage.

Content

Scanner excerpt · requirements.txt (reported line 4)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: python-dotenv has 2 known advisory(ies) (CVE-2026-28684 (python-dotenv: Symlink following in set_key allows arbitrary file overwrite via ); CVE-2026-28684 (python-dotenv reads key-value pairs from a .env file and can set them as environ)), 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

python-dotenv has known advisories, and the manifest does not specify an exact version, so there is no reliable way to determine whether installations are affected. In isolation this is low severity, but it represents avoidable supply-chain ambiguity.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
83% confidence
Finding

The class/docstring and user-visible error/message strings in this file are written only in Chinese, indicating a fixed language choice. There is no indication that users can opt into another language or that the locale restriction is intentionally documented as region-specific.

Content

No source excerpt is available for this finding.