Back to skill

Security audit

古诗词知识图谱

Security checks for vulnerabilities and agentic risk

Overview

This skill is not clearly malicious, but it should be reviewed because it stores an API key in a local plaintext .env file, sends requests to an external API, and contains mismatched poetry and gaokao documentation.

Install only if you trust the Xiaobenyang service and are comfortable giving it an API key and graph queries. Use a low-privilege, revocable key, avoid running the skill from a shared or sensitive directory, and remove or protect the .env file after use. The publisher should align the docs with the poetry graph purpose, avoid plaintext key persistence, and enforce read-only query behavior before approval.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/config.py:40
Finding

API Key Stored in a Plaintext File Without Permission or Symlink Protections

Content
View full analysis

Vulnerability Details

File Location: scripts/config.py, lines 40-68
Vulnerability Type: Plaintext credential storage and unsafe file handling
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

The API key is persisted as plaintext in a .env file located relative to the process working directory. The implementation does not:

  • Restrict the resulting file to owner-only permissions.
  • Verify that .env is a regular file rather than a symbolic link.
  • Use an atomic, exclusive file-creation operation.
  • Resolve the file under a trusted, application-specific configuration directory.
  • Use an operating-system credential store.

Consequently, the effective confidentiality of the API key depends on the process umask, directory permissions, and integrity of the current working directory. If an attacker can inspect files in that directory, the API key can be recovered directly. If an attacker can prepare .env as a symbolic link, invoking set_api_key() may overwrite another file writable by the running process.

Attack Path

Credential disclosure path:

1 ...[truncated 1331 chars]

Remediation
View remediation

Remediation Suggestions

  1. Prefer an operating-system credential manager, secret-management service, or environment-only configuration rather than persistent plaintext storage.
  2. If file storage is unavoidable, use a fixed application-specific configuration directory owned by the current user rather than the current working directory.
  3. Reject an existing path if it is a symbolic link or is not a regular file.
  4. Create the file atomically with owner-only permissions, such as mode 0600 on POSIX systems.
  5. Write through a securely created temporary file in the same directory, apply restrictive permissions, and atomically replace the destination.
  6. Verify ownership and permissions before reading an existing credential file.
  7. Add .env to source-control ignore rules and document that it contains sensitive credentials.
  8. Avoid including API-key values in exceptions, logs, or diagnostic output.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/tools.py:23
Finding

Read-Only Cypher Restriction Is Not Enforced Before Forwarding User Input

Content
View full analysis

Vulnerability Details

File Location: scripts/tools.py, lines 23-40
Vulnerability Type: Missing validation and authorization enforcement for graph queries
Risk Level: Medium

Vulnerable Code

python
def execute_read_cypher(
    query: str
) -> Dict[str, Any]:
    """
    MCP Tool to execute a read Cypher query on the graph database.
    
    Args:
        query: The Cypher query to execute.
    
    Returns:
        JSON-formatted query results as a string or an error message.
    """
    arguments = {
        "query": query
    }
    
    return call_api("1815529854199818", "execute_read_cypher", arguments)

Technical Analysis

The function is documented as executing a read-only Cypher query, but it forwards arbitrary query text to the external service without locally verifying that the query is read-only. There is no allowlist of permitted clauses, blocklist of mutation and administration clauses, procedure-call policy, query complexity limit, or result-size limit.

The security boundary therefore depends entirely on the external API and the database identity used by that service. If the remote implementation does not strictly enforce read-only behavior at the database authorization layer, an attacker may submit mutating or administrative Cypher through a tool presented to the Agent as read-only.

Text filtering alone is not a sufficient primary control because Cypher syntax, subqueries, comments, and callable procedures can make reliable parsing difficult. The authoritative protection must be a database account whose permissions physically prevent writes and unsafe procedure execution.

Attack Path

  1. An attacker submits a request that causes the Agent to invoke execute_read_cypher.
  2. The attacker supplies a mutation, administrative statement, unsafe procedure invocation, or resource-intensive query instead of a normal read query.
  3. The function places the su ...[truncated 961 chars]
Remediation
View remediation

Remediation Suggestions

  1. Configure the upstream database connection with a dedicated account that has read-only access and no schema-management, write, administrative, or unsafe procedure permissions.
  2. Parse Cypher using a syntax-aware parser and allow only explicitly supported read constructs.
  3. Reject mutation and administration operations, including creation, deletion, updates, merges, schema changes, privilege changes, data loading, and unapproved procedure calls.
  4. Maintain an allowlist of callable procedures and functions rather than relying only on keyword blocking.
  5. Apply query execution timeouts, memory limits, row limits, traversal-depth limits, and response-size limits upstream.
  6. Add negative tests covering mutation clauses, nested subqueries, comments, mixed-case syntax, procedure calls, and denial-of-service query patterns.
  7. Return a validation error before making the network request when the query violates the read-only policy.

T08 · Insecure Dependencies

Note
Location
requirements.txt:1
Finding

Unbounded Dependency Constraints Permit Unreviewed Future Releases

Content
View full analysis

Vulnerability Details

File Location: requirements.txt, lines 1-4
Vulnerability Type: Non-reproducible dependency resolution and supply-chain exposure
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 a minimum-only version constraint. A new installation can therefore resolve to any future compatible or incompatible release available from the configured package index. The resulting environment is not reproducible and may include versions that were never tested or reviewed with this Skill.

The reviewed package names are established packages, and there is no evidence of dependency confusion, typosquatting, or a currently malicious release. The risk arises because future resolution is unrestricted: a compromised release, unexpected major behavior change, or newly introduced vulnerability can automatically enter fresh installations.

Attack Path

  1. A future dependency release is compromised, contains a security regression, or introduces incompatible behavior.
  2. A user performs a fresh installation or rebuild using the minimum-only constraints.
  3. The package resolver selects that later release because no upper bound, lock file, or hash constraint prevents it.
  4. The dependency is installed and imported by the Skill.
  5. Any malicious package initialization or vulnerable behavior executes with the permissions of the Skill process.

This path requires compromise or vulnerability of an allowed dependency release; the audit found no evidence that this condition currently exists.

Impact Assessment

Potential impact depends on the affected dependency and can include arbitrary code execution under the Skill process account, credential access, network access, or application failure. The current confirmed impact is limited to non-reproducible builds and inability to gua ...[truncated 70 chars]

Remediation
View remediation

Remediation Suggestions

  1. Generate and commit a reviewed lock file or fully pinned dependency set.
  2. Use exact versions and package hashes, for example through pip-compile with hash generation.
  3. Install with hash verification enabled, such as pip install --require-hashes.
  4. Update dependencies through a controlled process that includes changelog review, automated tests, vulnerability scanning, and source-integrity checks.
  5. Use a trusted package index and restrict fallback to untrusted or public indexes where private package names are involved.
  6. Regularly refresh pins so that reproducibility does not prevent timely security updates.
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 (28)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The skill claims a simple poetry knowledge graph role, but it reads and writes a local .env file, manages runtime configuration, and persists API credentials. That behavior materially expands the attack surface beyond user-visible functionality and can lead to secret exposure or unauthorized configuration changes.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The skill claims a simple poetry knowledge graph role, but it reads and writes a local .env file, manages runtime configuration, and persists API credentials. That behavior materially expands the attack surface beyond user-visible functionality and can lead to secret exposure or unauthorized configuration changes.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The documentation mixes an ancient-poetry graph skill with unrelated gaokao/school-search project structure and workflow references. Such inconsistent identity is a strong supply-chain risk signal because it suggests copied or repurposed instructions that may hide the skill's true behavior and confuse security review.

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

This code forcibly reads XBY_APIKEY from a local .env file during initialization, creating intentional secret ingestion logic beyond normal configuration loading. In a poetry skill, this is unnecessary and increases the chance that credentials are harvested from local files without clear need or disclosure.

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

The explicit existence check and file read for .env participates in local credential access behavior. Even if intended for convenience, it normalizes direct access to local secret files and broadens exposure in a skill whose declared purpose does not require secret management.

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

This logic prefers a credential recovered from local files or environment and stores it in the settings object for later use, enabling persistent access to an API secret. In context, this is more dangerous because the skill’s declared poetry function does not justify handling third-party credentials at all.

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

The code adds API credential persistence and retrieval capabilities that are not justified by a poetry knowledge-graph skill. This mismatch increases suspicion because the skill can collect, store, and reuse secrets locally, creating unnecessary credential exposure and expanding the attack surface beyond its declared purpose.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
95% confidence
Finding

The function writes an API key directly into a local .env file, giving the skill a local secret-storage capability unrelated to its stated educational function. Plaintext local storage makes credentials easier to recover by other local processes, accidental commits, backups, or logs.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
96% confidence
Finding

The save_api_key_to_env function explicitly persists API credentials to a plaintext .env file, which is a direct credential exposure risk. Such files are commonly copied into backups, readable by other tools, or accidentally committed, and the capability is unrelated to the stated educational skill purpose.

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

The skill exposes capabilities consistent with environment access, file read/write, and network use, but does not declare any tool scope or permissions boundary. That omission reduces transparency and weakens least-privilege controls, especially because the skill also persists secrets and reaches external services.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill instructs collection of an API key from the user and storage via set_api_key without warning that the secret may be persisted in .env or otherwise retained. This creates a credential-handling risk because users may disclose sensitive tokens without informed consent, and local persistence increases exposure to later leakage.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The workflow instructs the model to call a school-search function that is not part of the declared tool surface. Contradictory invocation guidance can cause unsafe fallback behavior, unexpected tool routing, or reviewer misunderstanding of what operations the skill may attempt.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

This code performs a network POST to an external service and includes both user-supplied params and a credential header. While internal logging exists for success and error cases, there is no user-facing disclosure, confirmation, or warning in the code about transmitting data off-system.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The class docstring references a different skill domain than the manifest, which is a trust and integrity issue. While not directly exploitable on its own, this inconsistency can indicate code reuse from another project or undeclared functionality, making the secret-handling behavior more suspicious in context.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The code persists a supplied API key to .env without any visible warning, consent, or confirmation step in the storage path. Users may reasonably expect temporary use, but instead the credential is retained on disk and in process environment state, increasing the risk of unintended disclosure.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
97% confidence
Finding

The dependency specification uses a lower-bound range instead of an exact pinned version, which makes builds non-reproducible and can cause the environment to resolve to unexpected or vulnerable releases over time. For a skill package, this increases supply-chain risk because security posture depends on whatever version the installer happens to select.

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

The manifest does not pin requests, and the package has multiple historical advisories, so there is no way to verify from this file whether deployed environments will resolve to a safe release. This creates unverifiable exposure to known CVEs, especially in environments that rebuild frequently or pull from permissive caches.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
97% confidence
Finding

Using pydantic>=2.7.0 leaves dependency resolution open-ended, so future installations may pull different versions with different behavior or security characteristics. This is a real supply-chain hygiene issue even though the file itself does not prove exploitation.

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

Because pydantic is unpinned and has known advisories, the actual installed version may be vulnerable and cannot be determined from the manifest alone. The risk is amplified by the common use of pydantic in parsing and validation paths, where vulnerable behavior can be reachable from untrusted input.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
96% confidence
Finding

The pydantic-settings dependency is not pinned, so the installed version cannot be predicted or audited reliably. That weakens reproducibility and may expose deployments to vulnerable or breaking upstream releases without any change to this repository.

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

The unpinned pydantic-settings dependency prevents verification of whether installations use a release affected by published advisories. Since settings libraries often interact with local files, environment variables, and secrets, uncertainty around version safety is a meaningful supply-chain concern.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
96% confidence
Finding

python-dotenv>=1.0.1 permits any later version, which means environments may install different packages over time and inherit unknown security issues or behavior changes. This is a genuine dependency-management weakness, though low severity by itself.

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

python-dotenv has published advisories, and the current >= specifier makes it impossible to tell whether a deployment will install an affected version. This matters because dotenv tooling often reads or writes local configuration files, so vulnerable versions can affect secrets handling and filesystem safety.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
87% confidence
Finding

The code includes natural-language strings such as the class docstring and error messages in Chinese, which imposes a specific language on users. There is no indication of user opt-in, language selection, or justification that the skill is intentionally region-specific.

Content

No source excerpt is available for this finding.