Back to skill

Security audit

Airbnb搜索扩展

Security checks for vulnerabilities and agentic risk

Overview

This Airbnb search skill wraps a third-party API, but it needs review because it stores API keys in plaintext, contains mismatched school-exam configuration, and exposes a robots.txt bypass option.

Review carefully before installing. Use only if you trust Xiaobenyang with your Airbnb search parameters and API key, understand that the key is stored in a local plaintext .env file, and avoid enabling ignoreRobotsText. The publisher should remove gaokao remnants, document credential storage and deletion, disable robots.txt bypass, and pin dependencies before broad distribution.

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:45
Finding
API Key Persisted in a Plaintext File Without Access Hardening<![CDATA[ ## Vulnerability Details **File Location**: `scripts/config.py:45-66` **Vulnerability Type**: Plaintext storage 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 The `save_api_key_to_env` function writes the user-supplied API key directly into a plaintext `.env` file in the process's current working directory. The implementation does not: - Enforce restrictive file permissions such as `0600`. - Verify whether an existing `.env` path is a regular file rather than a symbolic link. - Use a dedicated, user-private configuration directory. - Prevent the file from being included in source-control commits, backups, build artifacts, or diagnostic bundles. - Offer session-only credential handling or integration with an operating-system credential store. The actual exposure depends on the process umask, working directory permissions, repository practices, and other local processes. Nevertheless, the code itself provides no confidentiality controls beyond ordinary filesystem defaults. The Skill instructions at `SKILL.md:17-19` and `SKILL.md:33` explicitly direct the agent to collect the key and call `set_api_key`, making ...[truncated 1327 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Prefer session-only credential handling or an operating-system credential manager rather than writing the key to the project directory. 2. If file persistence is required, store the credential in a deterministic user-private configuration directory outside the repository. 3. Create the credential file atomically with permissions set to `0600`; verify and correct permissions on existing files before reading them. 4. Reject symbolic links and verify that the destination is a regular file owned by the expected user. 5. Add `.env` to `.gitignore` and relevant artifact, backup, and diagnostic exclusion lists. 6. Avoid retaining the credential in global process state longer than necessary. 7. Document where the key is stored, how it is protected, and how the user can revoke or delete it. 8. Add automated tests that verify restrictive permissions and safe handling of existing files and symbolic links. ]]>

other

Warning
Location
scripts/tools.py:6
Finding
Airbnb Tools Permit Explicit Bypass of robots.txt Rules<![CDATA[ ## Vulnerability Details **File Location**: `scripts/tools.py:6-54` and `scripts/tools.py:56-97` **Vulnerability Type**: Robots exclusion policy bypass capability **Risk Level**: Medium ### Vulnerable Code ```python def airbnb_search( location: str, placeId: Optional[str] = None, checkin: Optional[str] = None, checkout: Optional[str] = None, adults: Optional[float] = None, children: Optional[float] = None, infants: Optional[float] = None, pets: Optional[float] = None, minPrice: Optional[float] = None, maxPrice: Optional[float] = None, cursor: Optional[str] = None, ignoreRobotsText: Optional[bool] = None ) -> Dict[str, Any]: """ Search for Airbnb listings with various filters and pagination. Provide direct links to the user Args: location: Location to search for (city, state, etc.) placeId: Google Maps Place ID (overrides the location parameter) checkin: Check-in date (YYYY-MM-DD) checkout: Check-out date (YYYY-MM-DD) adults: Number of adults children: Number of children infants: Number of infants pets: Number of pets minPrice: Minimum price for the stay maxPrice: Maximum price for the stay cursor: Base64-encoded string used for Pagination ignoreRobotsText: Ignore robots.txt rules for this request Returns: """ arguments = { "location": location, "placeId": placeId, "checkin": checkin, "checkout": checkout, "adults": adults, "children": children, "infants": infants, "pets": pets, "minPrice": minPrice, "maxPrice": maxPrice, "cursor": cursor, "ignoreRobotsText": ignoreRobotsText } return call_api("1777316659557379", "airbnb_search", arguments) ``` ```python def airbnb_listing_details( id: str, checkin: Optional[str] = None, checkout: Optional[str] = ...[truncated 3056 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove `ignoreRobotsText` from both public function signatures and outbound argument dictionaries. 2. If compatibility requires retaining the field, force it to `False` locally and do not accept user- or model-controlled values. 3. Use an authorized Airbnb API or another retrieval mechanism that complies with the target's access policies and contractual terms. 4. Implement server-side controls so the remote MCP service cannot override crawler-policy enforcement based solely on client input. 5. Add request validation and tests confirming that bypass flags cannot be submitted. 6. Document permitted data sources, rate limits, and compliance requirements for listing retrieval. 7. Record auditable policy decisions without logging credentials or unnecessarily sensitive search data. ]]>
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.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The documentation and project structure suggest unrelated gaokao/school-search configuration logic, credential persistence, and service endpoint management that do not fit the stated Airbnb use case. This indicates either repurposed code or hidden functionality, increasing the risk of credential misuse, misleading consent, and broader-than-expected system access.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The documentation and project structure suggest unrelated gaokao/school-search configuration logic, credential persistence, and service endpoint management that do not fit the stated Airbnb use case. This indicates either repurposed code or hidden functionality, increasing the risk of credential misuse, misleading consent, and broader-than-expected system access.

Context-Inappropriate Capability

High
Confidence
96% confidence
Finding
The skill exposes an 'ignoreRobotsText' option, effectively encouraging bypass of site access restrictions. In the context of a travel-planning/listing-research skill, this is unnecessary and materially increases legal, policy, and anti-bot abuse risk while normalizing behavior that may violate target-site rules.

Description-Behavior Mismatch

High
Confidence
98% confidence
Finding
The configuration clearly targets a different product/domain than the declared Airbnb search extension: it uses an unrelated Chinese exam skill description, XBY_GAOKAO_ prefix, and xiaobenyang.com endpoint. In an agent skill context, this mismatch is dangerous because it can route user data or credentials to an unintended external service, indicating supply-chain confusion, code reuse from another skill, or hidden exfiltration paths.

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
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
88% confidence
Finding
This code manually reads the entire .env file and extracts XBY_APIKEY, bypassing the structured settings mechanism and any expected scoping from the declared env_prefix. In the context of a mismatched skill/domain, this is more suspicious because it explicitly hunts for a secret tied to another application name, increasing the likelihood of unauthorized credential reuse or unintended cross-skill secret access.

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.

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
90% confidence
Finding
This function writes API credentials to a plaintext .env file, creating durable local secret exposure. In an end-user skill/extension, plaintext persistence is risky because secrets may leak through filesystem access, backups, logs, or accidental repository inclusion, especially when the skill already appears to be wired to an unrelated external service.

Lp3

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding
The skill declares no explicit tool scope or permissions while its documented/project capabilities imply access to environment variables, local file read/write, and network operations. This weakens containment and transparency, making it easier for a skill to access sensitive resources beyond what a user would reasonably expect.

Context-Inappropriate Capability

Medium
Confidence
90% confidence
Finding
The skill requires users to provide a third-party API key and persists it, but this sensitive credential handling is not disclosed in the manifest description. That undermines informed consent and can expose users to credential leakage, misuse, or unexpected billing if the storage or downstream service is compromised.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The instructions tell the agent to collect and store a user API key without warning the user how it will be stored, protected, or reused. This is dangerous because users may unknowingly place a billing-linked or privileged secret into local persistent storage without understanding the exposure or retention model.

Intent-Code Divergence

Medium
Confidence
96% confidence
Finding
The workflow examples and project structure reference unrelated gaokao/school-search functions, which strongly suggests copy-pasted or mismatched implementation guidance. This can cause an agent or maintainer to invoke unintended functions or trust a skill whose true behavior differs from its declared purpose.

Natural-Language Policy Violations

Medium
Confidence
90% confidence
Finding
Multiple user-facing strings and docstrings are written only in Chinese, including error and status messages, with no indication that the skill supports language selection or is intentionally limited to a Chinese-speaking context. This creates a natural-language policy concern because the skill appears to impose a specific language without user opt-in.

Intent-Code Divergence

Medium
Confidence
87% confidence
Finding
The comment at L31 says the code 'forces' reading XBY_APIKEY from .env, but the surrounding BaseSettings configuration uses the XBY_GAOKAO_ prefix and the code then allows the environment variable to override the .env value at L39-L42. This documentation actively misrepresents both the key naming convention and the effective precedence behavior implemented by the code.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The function persists a supplied API key directly into a local .env file and process environment without any user-facing warning, consent flow, or storage hardening. In a desktop extension/agent setting, this increases the chance of accidental long-term secret retention, inclusion in backups or source control, and exposure to other local processes or users.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
The tool explicitly exposes an `ignoreRobotsText` parameter, allowing callers to bypass a target site's robots.txt restrictions. For a travel-planning/search skill, this capability is not necessary for legitimate user functionality and enables policy-evasive scraping behavior, increasing legal/compliance risk and the chance the skill is used for unauthorized data collection.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
The listing-details function repeats the same unsafe capability by exposing `ignoreRobotsText` to callers, permitting selective bypass of robots.txt when fetching individual listings. In the context of an Airbnb research extension, this exceeds the stated purpose and creates a mechanism for deliberate scraping-policy evasion across both search and detail endpoints.

Natural-Language Policy Violations

Low
Confidence
85% confidence
Finding
The skill name and nearly all operational instructions are written in Chinese, with no indication that users may interact in other languages or choose a preferred locale. Under the language/locale policy, a skill should not impose a specific language unless the constraint is explicitly justified or presented as an opt-in choice.

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
The dependency is specified with a lower-bound version only, so builds can resolve to different future releases over time. This weakens supply-chain control and makes it harder to ensure the installed version is free of known vulnerabilities or breaking changes.

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
89% confidence
Finding
Requests has published advisories, but because the manifest does not pin a concrete version, it is impossible to verify whether the resolved package is affected. In this desktop extension context, requests is likely used for remote network access, so an unsafe resolved version could expose network-layer issues or credential leakage depending on implementation.

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
Using an unpinned pydantic version allows environment-dependent or time-dependent installs, reducing reproducibility and making security posture unverifiable. If a vulnerable release is selected, the application may inherit known flaws without any change to source code.

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
Pydantic has known advisories, and the open-ended version specifier makes the effective risk unverifiable at install time. While requirements.txt alone does not prove exploitability, it does show inadequate dependency governance that could allow a vulnerable parser/validation library into production.

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
A minimum-version-only requirement for pydantic-settings means the actual installed package may vary across systems and over time. This creates supply-chain uncertainty and can silently introduce vulnerable or incompatible releases.

Static analysis

No suspicious patterns detected.