Back to skill

Security audit

Markdown转Notion转换器

Security checks for vulnerabilities and agentic risk

Overview

This skill needs Review because it stores an API key locally, sends Markdown to a remote Xiaobenyang API, and contains mismatched Gaokao/template references that make its true scope unclear.

Install only if you trust the Xiaobenyang service with both your API key and the Markdown content you submit. Treat the local .env file as sensitive, avoid using this on private documents unless remote processing is acceptable, and review or constrain the API endpoint settings before use.

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

Configurable API Endpoint Can Expose Credentials and User Content

Content
View full analysis

Vulnerability Details

File Location: scripts/config.py:12-18, scripts/call_api.py:49-71
Vulnerability Type: Unvalidated configurable endpoint used for sensitive outbound requests
Risk Level: Medium

Vulnerable Code

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

# API配置
base_url: str = "https://mcp.xiaobenyang.com"
mcp_id: str = "1820705335657482"
api_key: str = ""
python
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

The Pydantic settings configuration permits fields to be overridden using environment variables with the XBY_GAOKAO_ prefix and values from .env. Consequently, XBY_GAOKAO_BASE_URL can replace the intended API origin.

XiaoBenYangClient.call_tool() constructs the request URL directly from settings.base_url without validating the URL scheme or destination hostname. It then sends the API key in the XBY-APIKEY header and sends the complete tool parameters—including user-provided Markdown—in the request body.

An attacker capable of altering the process environment or the applicable .env configuration can therefore redirect requests to an attacker-controlled endpoint. The implementation does not enforce HTTPS, pin the approved hostname, or explicitly disable redirects.

Attack Path

  1. The attacker gain ...[truncated 1159 chars]
Remediation
View remediation

Remediation Suggestions

  • Remove runtime configurability of the production API origin if alternate endpoints are not required.
  • Otherwise, parse the configured URL and require:
    • The https scheme.
    • An exact approved hostname, such as mcp.xiaobenyang.com.
    • An approved port.
    • No embedded username or password.
  • Reject IP literals, malformed URLs, and unapproved subdomains.
  • Disable automatic redirects for requests carrying credentials, or validate the scheme and hostname of every redirect target before following it.
  • Separate credential-bearing transport code from general configurable HTTP clients.
  • Document that submitted Markdown is transmitted to the external service and obtain appropriate user consent for sensitive content.
  • Add tests proving that environment variables cannot redirect credential-bearing requests to HTTP or an unapproved hostname.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/config.py:47
Finding

API Key Is Persisted in Plaintext with Default File Permissions

Content
View full analysis

Vulnerability Details

File Location: scripts/config.py:47-69
Vulnerability Type: Insecure local storage and process-environment exposure of sensitive credentials
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

save_api_key_to_env() writes the API key directly into a plaintext .env file. Path.write_text() relies on the process umask and does not explicitly enforce owner-only permissions. If the file already exists with permissive permissions, rewriting it does not correct those permissions.

The function also copies the credential into os.environ. Environment variables can be inherited by subsequently launched child processes and may be visible through debugging, diagnostics, crash collection, or process-inspection facilities depending on the operating system and deployment configuration.

The file update is not atomic. It directly rewrites .env, which can produce partial configuration if the process is interrupted and does not provide secure creation semantics for the credential file.

Attack Path

  1. A user follows the documented setup workflow and su ...[truncated 1160 chars]
Remediation
View remediation

Remediation Suggestions

  • Prefer a platform credential manager, secrets service, or session-scoped secret injection instead of storing credentials in .env.
  • If local persistence is unavoidable:
    • Create the credential file atomically with owner-only mode 0600.
    • Verify and correct permissions on every load and update.
    • Refuse to use files owned by another user or files that are symbolic links.
    • Write to a securely created temporary file, flush it, and atomically replace the destination.
  • Store secrets in a user-specific configuration directory rather than the current working directory.
  • Ensure .env is excluded through .gitignore and relevant packaging, backup, logging, and diagnostic exclusions.
  • Avoid placing the key in os.environ unless required. Keep it in process-local memory and pass it only to the specific request operation.
  • Prevent secret values from appearing in exceptions, logs, telemetry, or debug output.
  • Support credential rotation and advise users to revoke any key that may already 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 (32)

Tp2

High
Category
MCP Tool Poisoning
Confidence
85% confidence
Finding

Mixing characters from multiple Unicode scripts in a single identifier is a common technique to create visually ambiguous tool names.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The skill claims Markdown/Notion conversion, yet the instructions reference reading and persisting XBY_APIKEY and configuring what appears to be an unrelated '小笨羊高考' service. That contradiction strongly suggests either repurposed or mislabeled functionality, which can mislead users into exposing credentials and allowing unexpected local file modification.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The skill claims Markdown/Notion conversion, yet the instructions reference reading and persisting XBY_APIKEY and configuring what appears to be an unrelated '小笨羊高考' service. That contradiction strongly suggests either repurposed or mislabeled functionality, which can mislead users into exposing credentials and allowing unexpected local file modification.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

High
Category
Not specified by scanner
Confidence
95% confidence
Finding

The API-key setup and project structure indicate persistent credential storage and external service integration that do not align with a simple Markdown converter. This makes the skill more dangerous in context because users would not reasonably expect secret collection, local persistence, or outbound API transmission from the declared functionality.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The workflow documentation is inconsistent with the advertised converter and references an unrelated search/Gaokao-style routing pattern. In security terms, this kind of spec drift is risky because it obscures the real operational behavior and can hide broader tool invocation or data exfiltration paths behind an innocuous description.

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

This function is the entry point for persisting an API key to a plaintext .env file, which creates a credential-at-rest exposure. In a Markdown-to-Notion converter, this is more suspicious because the surrounding configuration references an unrelated service, so users may unknowingly store a secret for a different backend in a local project file.

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

The skill declares no explicit tool scope or permissions boundaries even though it clearly expects environment access, file reads/writes, and network use. In an agent setting, undocumented capabilities increase the chance of over-privileged execution, user surprise, and misuse of local secrets or filesystem state.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill explicitly tells the agent to ask for an API key and store it, but gives no warning about persistence, storage location, reuse, or access controls. In context, this is more dangerous because the skill's true behavior is already mismatched, so users may disclose credentials without informed consent about where they are stored or sent.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The return-handling instructions tell the agent to display raw API responses directly, which is inconsistent with a pure content-conversion tool and may expose backend data structures, error details, or unintended sensitive fields. Directly surfacing raw upstream responses increases the chance of information leakage and unsafe content propagation.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The file implements a generic remote API proxy rather than a narrowly scoped Markdown-to-Notion conversion helper, which creates a capability/description mismatch. In a skill advertised for local document transformation, hidden generic upstream invocation expands the attack surface and can enable undisclosed data transfer or unexpected remote actions.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
79% confidence
Finding

The class docstring explicitly presents the client as a Chinese-language API client, and all user-facing strings in this file are fixed in Chinese. Because there is no language choice, opt-in, or documented locale-specific justification in the file, this may violate the language/locale policy constraint.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

A document-conversion skill making outbound requests to a generic upstream MCP service means user-supplied content and metadata may leave the local trust boundary. Because the code accepts arbitrary tool names and parameters and posts them externally, this can result in covert exfiltration or execution of unintended remote capabilities beyond simple format conversion.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The request sends both user-controlled parameters and an API credential to an external service without any visible user-facing disclosure or consent mechanism. In the context of a content-conversion skill, users may reasonably expect local transformation, so silent transmission of document contents and secrets materially increases privacy and supply-chain risk.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The docstring identifies the settings as belonging to a different skill ('小笨羊高考Skill配置'), which is inconsistent with the advertised Markdown-to-Notion converter. Such mismatches are a supply-chain trust red flag because they suggest copied or repurposed code, making it harder to verify what service the stored credentials actually belong to and increasing the risk of misrouting secrets.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

This code persists an API key into a local .env file and updates process environment state, creating unnecessary credential-at-rest exposure for a skill whose declared purpose is Markdown-to-Notion conversion. In this context, storing secrets on disk without clear necessity, consent, or secure storage increases the chance of accidental disclosure through backups, source packaging, shared workspaces, or local file access.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The function writes the API key to .env with no user-facing warning, confirmation, or disclosure that the secret will be stored on disk. Silent persistence is dangerous because users may expect a transient session token, while the implementation leaves a recoverable local artifact that can be exposed by other tools, archives, or unintended sharing.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The function forwards raw user-supplied markdown to an external API via call_api without any visible disclosure, consent mechanism, or indication of data handling limits. In a content-management converter, markdown may contain sensitive notes, secrets, internal docs, or embedded tokens, so silent transmission to a third party creates a real data exposure and privacy risk.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
96% confidence
Finding

The dependency specifier requests>=2.31.0 is unpinned, so builds may resolve to different versions over time. That weakens reproducibility and can unexpectedly introduce vulnerable or breaking releases into the skill's environment.

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

requests has known advisories, and because the manifest does not pin a specific version, it is impossible to verify from this file whether the installed release is affected. In a tool that likely communicates with external APIs, uncertainty around HTTP client security increases risk, even though the requirement minimum may or may not already exclude some issues.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
96% confidence
Finding

pydantic>=2.7.0 allows any newer version to be installed, which makes dependency resolution non-deterministic and can silently pull in insecure or incompatible releases. This is a software supply-chain hygiene issue even if no exploit is immediately present in this 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
86% confidence
Finding

pydantic has published advisories, but the open-ended specifier prevents determining whether an affected version could be installed. This creates audit uncertainty and can leave consumers exposed if dependency resolution selects a vulnerable release.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.