Back to skill

Security audit

DuckDuckGo搜索服务

Security checks for vulnerabilities and agentic risk

Overview

The skill appears to provide search and webpage-fetching through a third-party XiaoBenYang MCP proxy, but its DuckDuckGo branding, reused gaokao configuration, and plaintext API-key persistence create material review concerns.

Review this skill carefully before installing. It is not a direct DuckDuckGo-only implementation: it uses a XiaoBenYang API key and sends requests to a XiaoBenYang MCP endpoint. Only use a limited, revocable API key, avoid submitting private URLs or secrets as search/fetch inputs, and check that .env is protected and excluded from version control.

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

API Key Persisted Without Restrictive File Permissions

Content
View full analysis

Vulnerability Details

File Location: scripts/config.py, lines 41–60
Vulnerability Type: Plaintext credential storage with uncontrolled file permissions
Risk Level: Medium

Vulnerable Code

python
def save_api_key_to_env(api_key: str) -> bool:
    """Store API key in 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 stores the user-provided API key as plaintext in .env using Path.write_text(). It does not create the file with owner-only permissions, correct the permissions of an existing file, or use a protected credential store.

The resulting access permissions depend on the operating system, process umask, and any permissions already assigned to .env. In a shared or improperly configured environment, another local account or process may be able to read the credential. Updating an existing .env also rewrites the file without first validating that it is a regular file owned by the expected user, and the update is not atomic.

Sending the API key to the documented HTTPS API in scripts/call_api.py is necessary for the declared authenticated proxy functionality and is not, by itself, confirmed exfiltration. The vulnerability is specifically ...[truncated 1199 chars]

Remediation
View remediation

Remediation Suggestions

  1. Prefer storing the credential in an operating-system credential manager or secret-management service rather than in a project-local plaintext file.
  2. If persistence is unnecessary, retain the key only for the current process or session.
  3. If .env persistence is required on POSIX systems, create and maintain it with owner-only mode 0600.
  4. Validate that an existing .env is a regular file owned by the expected user and reject symbolic links or unexpected file types before writing.
  5. Use an atomic update: create a protected temporary file in the same directory, write and flush its contents, set restrictive permissions, and atomically replace .env.
  6. Add .env to version-control ignore rules and clearly document that it contains a secret.
  7. Never include the credential in application logs, exception messages, or returned tool data.
  8. Support key rotation and revocation so a disclosed credential can be invalidated promptly.
  9. Document that search queries and requested URLs are forwarded to the third-party API, warning users not to submit secrets or private signed URLs.
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 (29)

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 advertises DuckDuckGo search and webpage fetching/parsing, but the document reveals undeclared credential management and local .env persistence tied to a different service domain. In agent environments, undisclosed secret storage and off-path service usage materially increase the risk of data handling that users did not consent to.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The skill advertises DuckDuckGo search and webpage fetching/parsing, but the document reveals undeclared credential management and local .env persistence tied to a different service domain. In agent environments, undisclosed secret storage and off-path service usage materially increase the risk of data handling that users did not consent to.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The core workflow instructs the agent to request and persist an API key for a xiaobenyang/gaokao service even though the skill is presented as a DuckDuckGo search server. This is dangerous because it creates a strong social-engineering vector: users may provide sensitive credentials believing they are enabling a simple search tool, while the agent is actually configured for a different remote service.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

High
Category
Not specified by scanner
Confidence
96% confidence
Finding

The project structure and examples reference unrelated functions and a configuration pattern inconsistent with the purported DuckDuckGo tool set, indicating the skill may be repurposed from another project. Such contradictions reduce auditability and can conceal unexpected capabilities like arbitrary remote calls or credential handling that are not obvious from the headline description.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The configuration code materially conflicts with the advertised DuckDuckGo search service by handling an unrelated XBY_APIKEY credential, hardcoding an external base URL, and providing persistence helpers for that secret. In an MCP skill context, this mismatch is a strong indicator of hidden credential collection or repurposed code that could exfiltrate or retain secrets unrelated to the declared capability.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The class docstring identifies the code as configuration for a different skill ('小笨羊高考Skill配置'), directly contradicting the declared DuckDuckGo search service. In security review, this kind of identity mismatch is a significant trust and provenance issue because it suggests code reuse from an unrelated system or deliberate mislabeling to hide non-declared functionality.

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 explicitly forces reading XBY_APIKEY from .env, bypassing the declared env_prefix scheme and targeting an unrelated credential name. In the context of a DuckDuckGo search skill, proactively scanning local secret files for non-service credentials is suspicious and can enable unauthorized harvesting or retention of secrets.

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 opens and reads the local .env file directly to search for a specific credential unrelated to the stated functionality. In this skill context, direct secret-file inspection is more dangerous because the skill is presented as a search tool, so operators may not expect local credential access at all.

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 prioritizes the XBY_APIKEY environment variable and loads it into the global settings object, continuing the pattern of handling an unrelated secret. While reading environment variables is normal, doing so for an undeclared, mismatched credential in this skill increases the chance of unintended secret capture and misuse.

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

This function is dedicated to storing an API key into .env, creating durable local secret storage that may be unintentionally exposed through filesystem access, backups, or version control mistakes. Combined with the service mismatch, this looks less like ordinary configuration and more like undeclared credential retention behavior.

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

The skill declares no explicit tool scope or permission boundaries even though its documented behavior includes environment access, local file reads/writes, credential persistence, and network access. In an agent setting, missing scope declarations increase the chance that the model or runtime will invoke capabilities beyond what users reasonably expect, especially when handling secrets such as API keys.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The skill exposes a webpage fetch capability but omits any warning that user-supplied URLs will be transmitted to external destinations and that retrieved content may come from arbitrary sites. In an agent context this can lead to privacy leakage, unintentional contact with sensitive/internal URLs, or user surprise about outbound requests.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

This code exposes a generic upstream MCP invocation primitive by accepting arbitrary mcp_id, tool_name, and params and forwarding them directly to the remote /api endpoint. In the context of a skill advertised as DuckDuckGo search and content parsing, this significantly broadens capability beyond the declared scope and can enable unauthorized tool use, data exfiltration, or abuse of privileged upstream functionality if callers can influence these fields.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

This code sends params to a remote API via requests.Session.post and includes an API key in the request headers. While the file has internal logging for success and errors, it does not provide any user-facing warning, confirmation, or explanatory comment/docstring disclosing that user-supplied data and credentials are being sent over the network.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The module can write API keys into a local .env file and also mutate the process environment at runtime, which exceeds the stated role of a search and content-parsing service. Persisting secrets locally increases the chance of accidental disclosure through source control, logs, backups, or other local users/processes, especially when this behavior is not clearly disclosed to operators.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The function silently persists an API key to .env without any user-facing warning, confirmation, or disclosure. This creates a secret-handling risk because users or deployers may reasonably assume the key is used transiently, while it is actually stored on disk where it may later be exposed.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
95% confidence
Finding

The dependency uses a lower-bound constraint (requests>=2.31.0) instead of pinning or tightly constraining an exact version, which makes builds non-reproducible and can silently pull in a vulnerable or breaking upstream release later. In a network-search MCP server that fetches remote content, dependency drift increases supply-chain risk because the service is internet-facing and likely to process untrusted input.

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

The manifest does not pin the requests version, so it is impossible to verify from this file alone whether the deployed package avoids known advisories affecting requests. This uncertainty is more relevant here because the skill is a search/content-fetching service and requests is likely central to handling untrusted remote URLs and responses.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
93% confidence
Finding

Using pydantic>=2.7.0 allows any newer version to be installed, preventing reproducible deployments and making it unclear whether a future resolved version contains newly introduced security issues. Since this skill likely parses externally sourced data and configuration, validation-library version drift can affect reliability and exposure to parser-related flaws.

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

Because pydantic is not version-pinned, the file does not demonstrate whether the installed version is affected by known advisories. For a service that parses and validates externally influenced data, inability to verify parser-library safety is a legitimate supply-chain concern even if no specific vulnerable version is shown here.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
92% confidence
Finding

The pydantic-settings dependency is not pinned, so installations may resolve to different versions over time, including versions with security defects or behavior changes. Because settings libraries often handle secrets and environment-derived configuration, unexpected dependency changes can have security consequences beyond simple instability.

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

The unpinned pydantic-settings dependency means the actual installed version may or may not contain a known security issue, and this cannot be verified from the manifest. Given that settings packages may read secrets and configuration from the environment or filesystem, unverifiable versions create avoidable uncertainty in a security-sensitive area.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
93% confidence
Finding

python-dotenv>=1.0.1 is unpinned, allowing future installs to pick arbitrary newer versions whose security posture is unknown at deployment time. Since dotenv tooling interacts with environment files and potentially secrets, uncontrolled upgrades can introduce file-handling or secrets-management risks.

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