Back to skill

Security audit

中药知识图谱

Security checks for vulnerabilities and agentic risk

Overview

The skill appears to be an authenticated remote knowledge-graph client, but it persists API keys in plaintext and contains mismatched copied gaokao/school-search references that users should review before installing.

Review this skill before installing. Only use it if you trust the XiaoBenYang service and are comfortable sending graph queries and an API key to its remote API. Do not provide a sensitive or broadly privileged key unless you are prepared for it to be stored in a plaintext .env file in the working directory; consider using a throwaway or scoped key and excluding .env from backups and source control. The gaokao/school-search leftovers should be corrected by the publisher before routine use.

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:46
Finding

API Key Stored in a Plaintext File Without Enforced Access Restrictions

Content
View full analysis

Vulnerability Details

File Location: scripts/config.py:46-65
Vulnerability Type: Plaintext credential storage with unsafe file permissions
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

Technical Analysis

The function persistently writes the user-supplied API key into a plaintext .env file in the process's current working directory. It does not explicitly set restrictive file permissions, verify file ownership, use a protected application-specific credential directory, or prevent symbolic-link traversal.

For a newly created file, effective permissions depend on the operating system and the process umask. If .env already exists, its potentially permissive permissions are retained. Storing the file relative to the current working directory also increases the possibility that it resides in a shared directory, becomes part of a source archive, or is accidentally committed to version control.

The direct use of Path.write_text() is also non-atomic. Although not independently classified here, concurrent writes or interruption could damage the configuration file.

Attack Path

  1. The Skill requests an API key from the user.
  2. The supplied key is passed to `set_api ...[truncated 1202 chars]
Remediation
View remediation

Remediation Suggestions

  1. Prefer session-only credential handling or an operating-system credential manager instead of persistent plaintext storage.
  2. If file persistence is essential, store credentials in a dedicated per-user configuration directory rather than the current working directory.
  3. Create the credential file atomically with owner-only permissions such as 0600, and verify its ownership and permissions before reading or updating it.
  4. Refuse to follow symbolic links and ensure the destination is a regular file owned by the current user.
  5. Write updates to a securely created temporary file in the same protected directory, apply restrictive permissions, and atomically replace the destination.
  6. Add .env to .gitignore and relevant packaging or backup exclusion lists.
  7. Document credential rotation and advise users to revoke any key that may have been stored in an exposed project directory.
  8. Avoid printing or returning the credential in logs, exceptions, or API responses.

T08 · Insecure Dependencies

Note
Location
requirements.txt:1
Finding

Unbounded and Unhashed Third-Party Dependencies

Content
View full analysis

Vulnerability Details

File Location: requirements.txt:1-4
Vulnerability Type: Non-reproducible dependency resolution without integrity verification
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

All dependencies are declared using open-ended minimum-version constraints. These constraints permit package managers to install any future release satisfying the minimum version, including releases that have not been reviewed or tested with this Skill.

No lock file or cryptographic hashes are provided. Consequently, installations are not reproducible and do not verify that downloaded artifacts exactly match previously audited artifacts. A compromised upstream release, maliciously replaced distribution artifact, or future incompatible version could therefore enter the runtime environment without a project code change.

The package names shown do not, by themselves, demonstrate typosquatting or malicious packages. The risk arises from unrestricted future resolution and the absence of artifact integrity controls.

Attack Path

  1. An operator installs the dependencies from requirements.txt.
  2. The package manager resolves the newest versions satisfying the >= constraints.
  3. A future dependency release or distribution artifact is compromised, malicious, or incompatible.
  4. Because there is no reviewed lock file or required hash, the package manager accepts the artifact.
  5. Malicious package code may execute during installation or when the Skill imports the dependency.
  6. Such code runs with the permissions of the process performing installation or executing the Skill.

Impact Assessment

Exploitation could permit arbitrary code execution with the privileges of the installing or runtime user. Depending on that user's permissions, the scope could include reading application data and environment v ...[truncated 381 chars]

Remediation
View remediation

Remediation Suggestions

  1. Pin every direct and transitive dependency to an explicitly reviewed version using a generated lock file.
  2. Record cryptographic hashes for approved distributions and install with hash enforcement, such as pip install --require-hashes.
  3. Generate locks using a reproducible dependency-management workflow, for example pip-tools, Poetry, or an equivalent controlled resolver.
  4. Configure automated dependency vulnerability and provenance scanning.
  5. Review and test dependency updates before regenerating the lock file.
  6. Install packages from a trusted, explicitly configured index over TLS and avoid unreviewed extra package indexes.
  7. Perform installation and runtime execution using a least-privileged isolated environment.
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 (25)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The skill claims to support a limited research use case, yet it also instructs reading and persisting API keys in .env and managing remote connection settings such as base_url, mcp_id, timeout, and retries. Secret persistence and remote-service configuration are materially different from the stated domain purpose, and they create credential-handling and exfiltration risks that are not transparently disclosed.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The skill claims to support a limited research use case, yet it also instructs reading and persisting API keys in .env and managing remote connection settings such as base_url, mcp_id, timeout, and retries. Secret persistence and remote-service configuration are materially different from the stated domain purpose, and they create credential-handling and exfiltration risks that are not transparently disclosed.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The docstring identifies the file as configuration for a gaokao skill, directly contradicting the manifest’s 中药知识图谱 purpose. In a security review, this kind of identity mismatch is a strong indicator of repurposed or misleading code, which can conceal unauthorized behavior or cause users to grant trust to code that does something else.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The configuration clearly targets a different domain/service than the declared 中药知识图谱 skill: it uses an XBY_GAOKAO environment prefix, a gaokao-oriented docstring, and external MCP service settings unrelated to a local knowledge-graph skill. This mismatch is dangerous because it suggests code reuse from another skill and creates a risk of unintended network access, hidden dependencies, or collection/use of credentials outside the user’s expected trust boundary.

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 model_post_init routine manually reads the .env file and extracts XBY_APIKEY regardless of whether the skill’s stated function justifies credential handling. This explicit secret-harvesting behavior is more sensitive than ordinary settings loading because it bypasses the normal scoped env_prefix and increases the chance of collecting or using credentials unexpectedly.

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

Directly opening and parsing .env to search for an API key is a credential-access behavior that exceeds what users would expect from a knowledge-graph skill. In context, the mismatch between advertised purpose and secret handling makes this more suspicious, because the code is reaching into a sensitive local file unrelated to the apparent task.

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

The code explicitly overrides the .env-derived value with XBY_APIKEY from the process environment, confirming active acquisition and use of a secret outside the declared skill scope. While reading environment variables is normal in many apps, in this skill context it contributes to an unnecessary credential-handling path that broadens trust assumptions.

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

This function persists an API key into a plaintext .env file, creating a durable local secret that may be exposed through source-control mistakes, backups, logs, or other local access. Because the skill is presented as a traditional-medicine knowledge graph rather than an authenticated external-service client, this credential storage is contextually unjustified and therefore more dangerous.

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 requests access patterns that imply environment access, file read/write, and network use, but it does not declare any explicit tool scope or permissions boundaries. In a skill that handles API keys and invokes remote tools, missing scope declarations weakens least-privilege controls and makes unintended capability exposure more likely.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The workflow example tells the model to call scripts.tools.search_schools(...), which is unrelated to a traditional-medicine knowledge graph and does not appear in the declared tool list. This is reinforced by the project structure naming xiaobenyang_gaokao_skill, indicating the documentation was copied from a different skill and actively conflicts with the stated intent of this one.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
85% confidence
Finding

This code performs an HTTP POST to an upstream service and sends both the supplied params payload and an API key in headers. While the behavior is implemented clearly, there is no confirmation prompt, print/log statement aimed at the user, or inline warning that user-provided data will be transmitted to an external service.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill persists an API key to a local .env file even though the stated functionality is only a traditional-medicine knowledge graph, not credentialed access to an external service. Persisting credentials expands the attack surface by leaving secrets at rest on disk, where they may be exposed through repository commits, backups, other local users, or later code paths.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The code writes the provided API key directly into .env with no explicit warning, consent flow, or indication that the secret will be persisted. This is risky because users may assume the key is used only for the current session, while the implementation silently creates a durable local secret that could later be disclosed.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
81% confidence
Finding

The skill is primarily written in Chinese and appears to assume Chinese-language operation, while some tool descriptions and intent mappings are in English. Because the documentation does not explicitly offer users a language or locale choice, it may impose a language expectation without opt-in.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
94% confidence
Finding

The dependency is specified with a lower-bound only (requests>=2.31.0), which allows future unreviewed versions to be installed and makes builds non-reproducible. Because requests has multiple known advisories across versions, leaving it unpinned prevents verifying whether deployments are using a safe release and can unexpectedly introduce a vulnerable version through dependency resolution.

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

The manifest references requests without an exact version, while the package has multiple known advisories across releases. That means the actual installed version cannot be verified from this file alone, creating a real supply-chain risk because vulnerable versions may be selected in some environments.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
93% confidence
Finding

pydantic>=2.7.0 is unpinned, so installations may resolve to different versions over time, including versions later found vulnerable. This weakens supply-chain control and makes it difficult to audit whether the deployed package version is safe, especially given known historical advisories affecting pydantic.

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 known advisories, but the unpinned requirement prevents determining whether deployment uses a patched or vulnerable release. This is a genuine but low-severity dependency governance issue rather than proof of an actively exploitable bug in the file itself.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
92% confidence
Finding

pydantic-settings>=2.2.0 does not ensure a deterministic installed version, so environments may pull different releases with different security characteristics. This creates a supply-chain hygiene issue and blocks reliable verification against known advisories.

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

Because pydantic-settings is not pinned, the project cannot demonstrate that installed environments avoid versions affected by known advisories. This leaves a verifiability gap in the dependency supply chain, even though the file itself does not prove a vulnerable version is currently used.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
93% confidence
Finding

python-dotenv>=1.0.1 permits any newer version, making the build non-reproducible and potentially exposing consumers to vulnerable or incompatible releases without review. Since the package has advisories involving file handling behavior, lack of pinning increases uncertainty about whether the installed version is safe.

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

python-dotenv has known advisories, and the unpinned requirement means the deployed version could vary by environment and may include a vulnerable release. This is dangerous because file and environment-loading libraries often interact with sensitive configuration and filesystem paths, so uncertainty around version safety is undesirable.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
85% confidence
Finding

The human-facing docstring identifies the skill in Chinese, and additional user-visible messages in the file are also written only in Chinese. This can represent a language policy issue if the skill presents a fixed language without offering the user a choice or documenting a justified locale restriction.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
90% confidence
Finding

The printed failure message is a natural-language string in Chinese and does not offer any locale choice. If surfaced to users in a broader environment, this may violate organizational language or locale expectations for user-facing text.

Content

No source excerpt is available for this finding.