Back to skill

Security audit

香烟检测

Security checks for vulnerabilities and agentic risk

Overview

The skill appears to use a remote API for cigarette detection, but it stores API keys in plaintext and can send keys and images to a configurable endpoint.

Review before installing. Use only non-sensitive images, do not provide an API key you cannot rotate, and avoid running this skill in a workspace where .env files may be committed, backed up, or shared. The publisher should remove the Gaokao leftovers, validate or pin the upstream API host, avoid plaintext key persistence, and clearly disclose that images are sent to Xiaobenyang's remote service.

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

Error
Location
scripts/call_api.py:52
Finding
Configurable API Endpoint Can Expose Credentials and Submitted Images<![CDATA[ ## Vulnerability Details **File Location**: `scripts/config.py:9-19`, `scripts/call_api.py:52-71` **Vulnerability Type**: Unvalidated credential-bearing endpoint configuration **Risk Level**: High ### Vulnerable Code ```python # scripts/config.py:9-19 model_config = SettingsConfigDict( env_prefix="XBY_GAOKAO_", env_file=".env", env_file_encoding="utf-8", extra="ignore", ) # API configuration base_url: str = "https://mcp.xiaobenyang.com" mcp_id: str = "1820705335657482" api_key: str = "" ``` ```python # scripts/call_api.py:52-71 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 key is not configured") headers = { "XBY-APIKEY": api_key, "func": tool_name, "mcpid": mcp_id, "Content-Type": "application/json", } t0 = time.time() try: resp = self._session.post( url=url, headers=headers, data=json.dumps(params), timeout=settings.timeout_seconds, ) ``` ### Technical Analysis The Pydantic configuration permits environment variables with the `XBY_GAOKAO_` prefix to override settings, including `base_url`. Consequently, `XBY_GAOKAO_BASE_URL` can replace the expected service endpoint. The HTTP client constructs its destination directly from this configurable value without validating the URL scheme or destination host. It then transmits the API key in the `XBY-APIKEY` header and sends the complete tool parameters in the request body. Those parameters contain either a user-provided image URL or the full Base64-encoded image. There is no HTTPS-only enforcement, hostname allowlist, or redirect-origin validation. A malicious or mistakenly configured endpoint can therefore receive both the API credential and image input. ### Attack Path 1. An attacker with influence over deployment configuration, process environment variables, or the loaded `.env` configuration sets `XBY_GAOKAO_BASE_URL` to an attack ...[truncated 1154 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove runtime configurability of the production API origin unless it is operationally required. 2. If configuration is required, parse the URL and enforce: - The `https` scheme. - An exact hostname allowlist, such as `mcp.xiaobenyang.com`. - An expected port and path. - Rejection of embedded credentials, fragments, and unexpected URL components. 3. Disable redirects for credential-bearing requests or manually validate every redirect destination before forwarding sensitive headers. 4. Never forward `XBY-APIKEY` across origins. 5. Separate test and production clients so test endpoint overrides cannot be enabled accidentally in production. 6. Add automated tests proving that HTTP endpoints, unapproved hosts, malformed URLs, and cross-origin redirects are rejected. 7. Rotate the API key if requests may already have been sent to an untrusted endpoint. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/config.py:42
Finding
API Key Is Persisted in a Plaintext Environment File Without Explicit Permission Hardening<![CDATA[ ## Vulnerability Details **File Location**: `scripts/config.py:42-64` **Vulnerability Type**: Plaintext credential storage **Risk Level**: Medium ### Vulnerable Code ```python def save_api_key_to_env(api_key: str) -> bool: """Save 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 API key is written directly into `.env` as plaintext. The implementation does not explicitly create or verify the file with owner-only permissions, verify file ownership, or protect the credential using an operating-system secret store. The effective permissions depend on the process umask and any pre-existing file permissions. If `.env` already exists with permissive access, rewriting it does not necessarily correct those permissions. The credential can also be exposed through project backups, workspace archives, container layers, or accidental source-control inclusion. The same key is additionally copied into the process environment, making it available to code executing within the process and potentially to diagnostic tooling with sufficient access. ### Attack Path 1. A user supplies an API key as required by the Skill workflow. 2. `set_api_key` calls `save_api_key_to_env`. 3. The function writes `XBY_APIKEY=<credential>` into `.e ...[truncated 903 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Prefer session-only credential handling or a platform secret manager instead of writing the key to the project directory. 2. If local persistence is unavoidable: - Create the file atomically with owner-only mode `0600`. - Verify that the file is a regular file and is owned by the expected account. - Reject symbolic links and unsafe pre-existing files. - Correct overly permissive permissions before writing. 3. Store secrets outside the source tree and ensure `.env` is excluded through `.gitignore`, packaging exclusions, backup rules, and container build exclusions. 4. Avoid retaining the key in the process environment longer than necessary. 5. Use a narrowly scoped API key with minimal permissions and quota. 6. Provide key rotation and revocation procedures. 7. Add tests that verify secure file permissions and safe behavior when `.env` already exists. ]]>
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 documentation references reading/writing .env files, persisting API keys, loading credentials from environment variables, and even unrelated gaokao/default-year configuration, which is materially inconsistent with a narrowly scoped image-detection skill. This broadens the attack surface and suggests code reuse or hidden functionality that could mishandle secrets or perform actions unrelated to the user’s request.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The skill documentation references reading/writing .env files, persisting API keys, loading credentials from environment variables, and even unrelated gaokao/default-year configuration, which is materially inconsistent with a narrowly scoped image-detection skill. This broadens the attack surface and suggests code reuse or hidden functionality that could mishandle secrets or perform actions unrelated to the user’s request.

Description-Behavior Mismatch

High
Confidence
98% confidence
Finding
The file for a cigarette-detection skill contains configuration for an unrelated Gaokao/MCP service, including base URL, MCP identifier, and API-key handling. This capability mismatch is dangerous because it introduces unexplained network/service integration and credential handling that are not required for the stated image-detection purpose, increasing the risk of hidden data flow or unauthorized service access.

Credential Access

High
Category
Privilege Escalation
Content
model_config = SettingsConfigDict(
        env_prefix="XBY_GAOKAO_",
        env_file=".env",
        env_file_encoding="utf-8",
        extra="ignore",
    )
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
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")
Confidence
92% confidence
Finding
The model_post_init routine explicitly reads .env and extracts XBY_APIKEY manually, creating custom credential-loading logic beyond normal framework behavior. In the context of an image-detection skill, this unexplained secret harvesting is high risk because it widens access to credentials and bypasses clearer, centralized secret-management patterns.

Credential Access

High
Category
Privilege Escalation
Content
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():
Confidence
90% confidence
Finding
The code checks for the existence of .env and reads its contents directly, which is part of a custom credential access path. In this mismatched skill context, directly inspecting a sensitive configuration file is suspicious because the advertised function does not require managing external service credentials, making hidden or unnecessary secret access more dangerous.

Credential Access

High
Category
Privilege Escalation
Content
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
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Context-Inappropriate Capability

High
Confidence
97% confidence
Finding
The code can persist an API key into a local .env file and reuse it later, even though the declared purpose is image-based cigarette detection. Storing credentials on disk without a clear operational need broadens secret exposure through source packaging, backups, logs, or accidental inclusion in repositories, and creates a hidden persistence mechanism in a low-trust skill context.

Credential Access

High
Category
Privilege Escalation
Content
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()
Confidence
94% confidence
Finding
This function is explicitly designed to save an API key into .env, establishing durable credential persistence in the skill's working directory. In a skill whose stated purpose is object detection from images, this is an unnecessary credential-handling capability that increases the chance of secret leakage through files, packaging, backups, or repository commits.

Lp3

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding
The skill declares no explicit tool or permission scope even though its documented/project capabilities include environment access, file read/write, and network use. Without least-privilege boundaries, a consumer cannot easily determine or constrain what the skill may access, increasing the risk of credential handling abuse or unintended data exposure.

Intent-Code Divergence

Medium
Confidence
93% confidence
Finding
References to unrelated gaokao/search functionality inside a cigarette-detection skill indicate copy-paste drift or mixed-purpose tooling. Such inconsistencies are dangerous because they can misroute user input, invoke the wrong tools, or conceal broader capabilities than users expect.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill asks users to provide image URLs or Base64 image data but does not warn that this content will be transmitted to an external service. Users may unknowingly send sensitive images or internal URLs to a third party, creating privacy, confidentiality, and potential SSRF-like risk depending on how remote fetching is implemented.

Ssd 3

Medium
Confidence
93% confidence
Finding
Instructing the agent to directly display raw API responses can expose sensitive or unnecessary data, including user-submitted image-derived content, internal identifiers, verbose error traces, or echoed request metadata. Raw output bypasses minimization and redaction, making accidental disclosure more likely.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
This code sends the provided params to a remote endpoint and includes a credential in the request headers. The file contains no confirmation prompt, print/log statement informing the user that data will be transmitted externally, and no inline warning near the operation.

Intent-Code Divergence

Medium
Confidence
99% confidence
Finding
The docstring identifies the code as a '小笨羊高考Skill配置', which conflicts with the manifest claiming cigarette detection. This inconsistency is a strong trust and provenance warning: it suggests code reuse or substitution from another project, making hidden functionality and mis-scoped permissions more likely in a security review.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The function writes the supplied API key to .env and exports it into the process environment with no user-facing warning, confirmation, or security controls. This is risky because users may unknowingly cause long-lived credential persistence, and other components in the same runtime may subsequently access the secret from the environment.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The function sends a user-provided image URL to an external API endpoint via call_api, but this file provides no disclosure, consent handling, or indication to callers that image content will leave the local environment. Because images may contain sensitive visual data, silent transmission to a third-party service creates a real privacy and data-governance risk even if the code is otherwise straightforward.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
This function transmits raw base64-encoded image content to an external API without any visible user warning or disclosure in the file. Sending the full image bytes off-box is more privacy-sensitive than passing a reference, since the entire potentially sensitive image is directly exfiltrated to a remote service.

Natural-Language Policy Violations

Low
Confidence
86% confidence
Finding
The entire skill name and instructions are written only in Chinese, with no indication that users may choose another language or that the locale limitation is required for a region-specific compliance reason. This can violate language/locale policy when a skill implicitly mandates one language without opt-in.

Unpinned Dependencies

Low
Category
Supply Chain
Content
requests>=2.31.0
pydantic>=2.7.0
pydantic-settings>=2.2.0
python-dotenv>=1.0.1
Confidence
97% confidence
Finding
The dependency specification uses a lower-bound only constraint (`requests>=2.31.0`), which makes builds non-reproducible and allows future installs to resolve to unexpected versions. This increases supply-chain risk and makes it impossible to determine from the manifest alone whether a vulnerable or incompatible release will be installed.

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
93% confidence
Finding
`requests` has multiple known advisories, but the manifest does not pin the installed version, so exposure cannot be verified. This is dangerous because an environment may resolve to an affected release, especially in CI/CD or redeployments where dependency state changes over time.

Unpinned Dependencies

Low
Category
Supply Chain
Content
requests>=2.31.0
pydantic>=2.7.0
pydantic-settings>=2.2.0
python-dotenv>=1.0.1
Confidence
96% confidence
Finding
`pydantic>=2.7.0` is unpinned, so dependency resolution may pull different versions over time across environments. That weakens build integrity and can silently introduce vulnerable or breaking releases into the skill.

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
91% confidence
Finding
`pydantic` has known advisories, and without exact version pinning there is no reliable way to assess whether deployed environments are vulnerable. This creates a real but low-severity supply-chain risk because the package selected at install time may differ from what was tested.

Unpinned Dependencies

Low
Category
Supply Chain
Content
requests>=2.31.0
pydantic>=2.7.0
pydantic-settings>=2.2.0
python-dotenv>=1.0.1
Confidence
95% confidence
Finding
`pydantic-settings>=2.2.0` permits any newer version, making installations non-deterministic. In a security context, that means potentially affected versions could be installed later without any manifest change.

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
90% confidence
Finding
`pydantic-settings` is listed with a known advisory, and the lack of a fixed version means the actual security posture is unverifiable from this file. Even if the current environment happens to be safe, future installs could select an affected version.

Static analysis

No suspicious patterns detected.