Back to skill

Security audit

地理空间数据访问服务

Security checks for vulnerabilities and agentic risk

Overview

The skill appears to be a remote data-catalog wrapper, but its documentation, backend identity, and credential storage are inconsistent enough that users should review it before installing.

Review this skill carefully before installing. It asks for an API key, stores it in a local plaintext .env file, and sends tool inputs plus that key to the XiaoBenYang backend. Install only if you trust that service with the key and queries, and avoid using a high-privilege or reused credential.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/config.py:45
Finding

API Credential Persisted in an Unprotected Plaintext Environment File

Content
View full analysis

Vulnerability Details

File Location: scripts/config.py:45-63
Vulnerability Type: Plaintext sensitive-data storage with insufficient file-permission enforcement
Risk Level: Medium

The persistence behavior is explicitly required by SKILL.md:17-18 and SKILL.md:34.

Vulnerable Code

python
def save_api_key_to_env(api_key: str) -> bool:
    """Persist the API key to the .env file."""
    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"Failed to save API key: {e}")
        return False

Technical Analysis

The function permanently writes the user-provided XBY_APIKEY into a plaintext .env file in the process's current working directory. Path.write_text() does not explicitly enforce owner-only permissions. A newly created file therefore receives permissions derived from the process umask, while an existing file retains its existing permissions. In environments with a permissive umask or a previously over-permissive .env, other local users or processes may be able to read the credential.

The implementation also accepts internal carriage-return or newline characters. Although set_api_key() strips leading and trailing whitespace, embedded line breaks remain valid and are interpolated directly into the file. A crafted value can consequently injec ...[truncated 2261 chars]

Remediation
View remediation

Remediation Suggestions

  1. Prefer an operating-system credential store, deployment secret manager, or session-scoped environment variable instead of persistent plaintext storage.
  2. Obtain explicit user consent before persisting the key and clearly document where it will be stored and how it can be revoked.
  3. Reject values containing \r, \n, or NUL characters before writing:
    python
    if any(char in api_key for char in ("\r", "\n", "\0")):
        return False
    
  4. Create and maintain the .env file with owner-only permissions (0600). Verify and correct permissions even when the file already exists.
  5. Write updates atomically through an owner-only temporary file, then replace the destination to reduce corruption and race risks.
  6. Avoid storing unrelated settings in the same credential file. If persistence is unavoidable, use a dedicated file outside shared project directories.
  7. Ensure .env is excluded from source control, archives, diagnostic bundles, and automated logs.
  8. Provide credential rotation and revocation instructions in SKILL.md, and recommend immediate rotation if the file may have been exposed.
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 (40)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The skill claims to be a geospatial MCP server, but the documented functions are generic Source Cooperative account/product/file enumeration tools, including scanning unpublished products, with no visible JSON-RPC server implementation. This mismatch obscures the true access scope and can cause users to authorize a broader dataset-discovery capability than intended.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The skill claims to be a geospatial MCP server, but the documented functions are generic Source Cooperative account/product/file enumeration tools, including scanning unpublished products, with no visible JSON-RPC server implementation. This mismatch obscures the true access scope and can cause users to authorize a broader dataset-discovery capability than intended.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The workflow examples reference gaokao/school-query behavior inside a skill advertised as geospatial data access, indicating copy-paste contamination and severe documentation inconsistency. This is risky because operators may trust the published purpose while the actual routing logic, parameter extraction, and credential flow target a different service or data domain.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The class docstring refers to a different skill ('小笨羊高考Skill配置') than the manifest describing a geospatial data access service, which is a strong inconsistency signal. Such mismatches can indicate repurposed code, hidden functionality, or poor provenance, reducing trust and increasing the likelihood that credential handling or endpoint behavior does not match the advertised purpose.

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

The custom post-init logic explicitly reads .env and extracts XBY_APIKEY outside the normal settings flow, increasing secret-handling complexity and bypassing safer centralized configuration patterns. This makes credential access more invasive and can unintentionally consume secrets from local files in contexts where users did not expect it.

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

Creating a hardcoded Path('.env') for direct secret access is part of an explicit plaintext credential retrieval mechanism. In the context of a geospatial service, this broadens access to local secrets without a clear functional need and increases the chance of mishandled credentials.

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

This function is dedicated to saving an API key into .env, explicitly implementing plaintext credential persistence on the local filesystem. If exploited through local access, backups, logs, or accidental repository inclusion, the stored key could grant unauthorized access to the remote service and any associated data or billing.

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

The skill declares no explicit tool scope or permission boundaries despite requiring environment access, local file read/write, and network operations. In an agent setting, this weakens least-privilege controls and increases the blast radius if the skill is misused, compromised, or invoked with unexpected inputs.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill description and operating instructions are written as mandatory guidance in Chinese, including directives to the model such as how to question the user and proceed. There is no indication that the user may choose another language or that the locale constraint is required for a region-specific compliance reason, which fits the policy category for language/locale restrictions without opt-in.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

L514-L516 说明工具函数返回 dict 且应从 result["raw"] 读取原始数据,但多个工具示例此前直接返回列表或产品/文件元数据对象,例如 list_accounts、search、get_product_details。这是文档内部对代码/接口行为的直接矛盾,会误导调用方如何处理结果。

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

This code performs an HTTP POST to an upstream API and includes both user-supplied parameters and an API key in the request headers. While the code has internal logging and docstrings, there is no user-facing confirmation, prompt, or warning that data will be transmitted to an external service.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The module persists the API key to a local .env file in plaintext, creating a durable secret on disk that may be exposed through source-control mistakes, backups, local compromise, or overly broad file permissions. For a geospatial data access skill, storing credentials locally is not inherently required and increases the attack surface beyond transient in-memory use.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The code modifies both the local filesystem and process environment to store credentials, giving the skill state-changing capability unrelated to simple data discovery or access. This can surprise users, leave credentials behind after use, and make accidental leakage or misuse more likely in shared or multi-user environments.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The function writes an API key to .env without any user-facing warning, confirmation, or disclosure that a plaintext secret will be persisted locally. This undermines informed consent and can cause users to unknowingly leave sensitive credentials on disk where other software, users, or future commits may expose them.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
81% confidence
Finding

This code file is a code file, so SQP-2 applies. Every helper forwards user-provided inputs to call_api(...), which is a network operation, but the file provides no confirmation prompt, logging/print disclosure, or warning comment/docstring that user queries and resource identifiers will be sent to an external API service.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

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

md
{
        "key": "harvard-lil/gov-data/metadata/metadata.jsonl.zip",
        "s3_uri": "s3://us-west-2.opendata.source.coop/harvard-lil/gov-data/metadata/metadata.jsonl.zip",
        "http_url": "https://data.source.coop/harvard-lil/gov-data/metadata/metadata.jsonl.zip",
        "size": 1012127330,
        "last_modified": "2025-02-06T16:20:22+00:00"
    }

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

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

md
{
        "key": "harvard-lil/gov-data/metadata/metadata.jsonl.zip",
        "s3_uri": "s3://us-west-2.opendata.source.coop/harvard-lil/gov-data/metadata/metadata.jsonl.zip",
        "http_url": "https://data.source.coop/harvard-lil/gov-data/metadata/metadata.jsonl.zip",
        "size": 1012127330,
        "last_modified": "2025-02-06T16:20:22+00:00"
    }

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/tools.py (reported line 169)May include surrounding context.

python
{
        "key": "harvard-lil/gov-data/metadata/metadata.jsonl.zip",
        "s3_uri": "s3://us-west-2.opendata.source.coop/harvard-lil/gov-data/metadata/metadata.jsonl.zip",
        "http_url": "https://data.source.coop/harvard-lil/gov-data/metadata/metadata.jsonl.zip",
        "size": 1012127330,
        "last_modified": "2025-02-06T16:20:22+00:00"
    }

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
93% confidence
Finding

L524 将项目结构标注为 xiaobenyang_gaokao_skill/,与文件顶部声明的“地理空间数据访问服务”明显不符。虽然这更像复制粘贴错误,但它会让读者对技能真实意图和实现归属产生混淆,属于文档意图与实际技能身份的不一致。

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
96% confidence
Finding

The dependency specification for requests uses a lower-bound only constraint, which allows future unresolved versions to be installed. This weakens build reproducibility and can unintentionally introduce vulnerable or breaking releases through the software supply chain.

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 multiple known advisories, and because the manifest does not pin the package version, there is no way to verify whether deployed instances are using an affected release. In a networked MCP service that likely makes outbound HTTP requests, this uncertainty increases supply-chain and runtime exposure.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
96% confidence
Finding

The pydantic dependency is not pinned to a specific version, so installations may resolve to different releases over time. This creates supply-chain risk because vulnerable or incompatible versions could be pulled into deployments without code changes.

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, but the unpinned manifest prevents verification that a safe version will actually be installed. Since this package handles validation and parsing, an affected release could expose the service to denial of service or unsafe input-handling behaviors.

Content

No source excerpt is available for this finding.