Back to skill

Security audit

小豆智能租车助手

Security checks for vulnerabilities and agentic risk

Overview

This rental assistant needs review because it exposes identity details and can accept cancellation fees without confirming the latest amounts.

Review before installing. Prefer the provider's app for paid cancellations until approval is tied to the exact fee and refund amounts. Require explicit location selection, masked identity confirmations, and an optional-insurance choice followed by a fresh service quote. Phone lookup may automatically register an account. The scanner's partial instruction coverage was independently investigated, including an offline cancellation test; live service authorization, retention practices, and publisher identity remain unverified.

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/xiaodou_api.py
Finding

Cancellation automatically commits newly retrieved financial terms without an executable confirmation gate

Content
View full analysis

Impact

A direct helper invocation can cancel a paid reservation and accept the service's applicable deduction before the user has reviewed and approved those amounts.

Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Output HandlingUnvalidated Output Injection, Cross-Context Output, Unbounded Output
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (34)

Skill declares no tool scope ('permissions' or 'allowed-tools') but code capabilities were detected: network.

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding

Without declared permissions the skill's intent is opaque and cannot be validated.

Content

No source excerpt is available for this finding.

Generic order-confirmation and cancellation phrases trigger takeover without requiring car-rental context.

Medium
Category
Trigger Abuse
Confidence
98% confidence
Finding

Generic phrases such as confirming a selection or canceling an order trigger mandatory takeover without requiring an established car-rental context. This can redirect unrelated conversations into rental workflows and unnecessary data collection, although the separate confirmation requirements make immediate unauthorized booking less likely.

Content

No source excerpt is available for this finding.

The workflow transmits location and identity data to an external rental service without an explicit privacy disclosure.

Medium
Category
Output Handling
Confidence
96% confidence
Finding

The workflow defaults to the user's current location and sends address and coordinate data to the external service before confirming that location with the user; later steps also transmit identity information. These transfers are relevant to renting a car and are not evidence of malicious exfiltration, but the implicit location-sharing step and absent disclosure create a privacy risk.

Content

No source excerpt is available for this finding.

The pricing workflow instructs the agent to modify a total that its documentation explicitly says must not be modified.

Medium
Category
Excessive Agency
Confidence
97% confidence
Finding

The workflow declares the returned payAmount immutable but then instructs the agent to add an insurance amount and select coverage by default. This can produce duplicate charges, incorrect quoted totals, or orders containing an optional service the user did not explicitly select; final order confirmation reduces but does not eliminate these risks.

Content

No source excerpt is available for this finding.

The skill requires displaying complete phone and identity-document numbers without a privacy warning.

Medium
Category
Output Handling
Confidence
99% confidence
Finding

The skill explicitly requires displaying complete phone and identity-document numbers without masking. This unnecessarily exposes sensitive identifiers in chat output, transcripts, notifications, and shared screens; the separate protection for user IDs does not protect these fields.

Content

No source excerpt is available for this finding.

The order-confirmation instructions require displaying the user's full phone number and identity-document number without masking.

Medium
Category
Data Exfiltration
Confidence
99% confidence
Finding

Requiring full identity-document and phone numbers in the confirmation output creates unnecessary disclosure of sensitive personal data. This is the same underlying issue as finding-eff938c627ee4f60a82eb5d21fdb3f88, not an additional independent exposure.

Content

No source excerpt is available for this finding.

The cancellation workflow permits direct cancellation of paid orders despite documenting that paid cancellations must be handled in the app.

Medium
Category
Excessive Agency
Confidence
96% confidence
Finding

The cancellation instructions first reserve paid-order cancellation for the app, then explicitly permit direct API cancellation after a fee confirmation. This creates an ambiguous financial-action boundary that an agent could resolve in favor of direct cancellation, although the required user confirmation limits the risk.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% 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/xiaodou_api.py (reported line 47)May include surrounding context.

python
def request_json(url, payload, timeout, verify_ssl):
    #print(f"request param {payload}")
    response = requests.post(
        url,
        json=payload,
        headers={"Content-Type": "application/json;charset=UTF-8"},

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Confidence
50% confidence
Finding

Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Content

Scanner excerpt · scripts/xiaodou_api.py (reported line 100)May include surrounding context.

python
def location_third_store(args, prefix):
    payload = {
        "name": getattr(args, "%s_name" % prefix),
        "code": getattr(args, "%s_code" % prefix),
        "addressTypeName": getattr(args, "%s_address_type_name" % prefix),
        "closeTime": getattr(args, "%s_close_time" % prefix),

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Confidence
50% confidence
Finding

Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Content

Scanner excerpt · scripts/xiaodou_api.py (reported line 106)May include surrounding context.

python
"closeTime": getattr(args, "%s_close_time" % prefix),
        "openTime": getattr(args, "%s_open_time" % prefix),
        "phone": getattr(args, "%s_phone" % prefix),
        "name": getattr(args, "%s_name" % prefix),
        "address": getattr(args, "%s_address" % prefix),
        "city": getattr(args, "%s_city" % prefix),
        "cityCode": getattr(args, "%s_city_code" % prefix),

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Confidence
50% confidence
Finding

Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Content

Scanner excerpt · scripts/xiaodou_api.py (reported line 101)May include surrounding context.

python
def location_third_store(args, prefix):
    payload = {
        "name": getattr(args, "%s_name" % prefix),
        "code": getattr(args, "%s_code" % prefix),
        "addressTypeName": getattr(args, "%s_address_type_name" % prefix),
        "closeTime": getattr(args, "%s_close_time" % prefix),
        "openTime": getattr(args, "%s_open_time" % prefix),

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Confidence
50% confidence
Finding

Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Content

Scanner excerpt · scripts/xiaodou_api.py (reported line 102)May include surrounding context.

python
payload = {
        "name": getattr(args, "%s_name" % prefix),
        "code": getattr(args, "%s_code" % prefix),
        "addressTypeName": getattr(args, "%s_address_type_name" % prefix),
        "closeTime": getattr(args, "%s_close_time" % prefix),
        "openTime": getattr(args, "%s_open_time" % prefix),
        "phone": getattr(args, "%s_phone" % prefix),

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Confidence
50% confidence
Finding

Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Content

Scanner excerpt · scripts/xiaodou_api.py (reported line 103)May include surrounding context.

python
"name": getattr(args, "%s_name" % prefix),
        "code": getattr(args, "%s_code" % prefix),
        "addressTypeName": getattr(args, "%s_address_type_name" % prefix),
        "closeTime": getattr(args, "%s_close_time" % prefix),
        "openTime": getattr(args, "%s_open_time" % prefix),
        "phone": getattr(args, "%s_phone" % prefix),
        "name": getattr(args, "%s_name" % prefix),

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Confidence
50% confidence
Finding

Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Content

Scanner excerpt · scripts/xiaodou_api.py (reported line 104)May include surrounding context.

python
"code": getattr(args, "%s_code" % prefix),
        "addressTypeName": getattr(args, "%s_address_type_name" % prefix),
        "closeTime": getattr(args, "%s_close_time" % prefix),
        "openTime": getattr(args, "%s_open_time" % prefix),
        "phone": getattr(args, "%s_phone" % prefix),
        "name": getattr(args, "%s_name" % prefix),
        "address": getattr(args, "%s_address" % prefix),

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Confidence
50% confidence
Finding

Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Content

Scanner excerpt · scripts/xiaodou_api.py (reported line 105)May include surrounding context.

python
"addressTypeName": getattr(args, "%s_address_type_name" % prefix),
        "closeTime": getattr(args, "%s_close_time" % prefix),
        "openTime": getattr(args, "%s_open_time" % prefix),
        "phone": getattr(args, "%s_phone" % prefix),
        "name": getattr(args, "%s_name" % prefix),
        "address": getattr(args, "%s_address" % prefix),
        "city": getattr(args, "%s_city" % prefix),

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Confidence
50% confidence
Finding

Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Content

Scanner excerpt · scripts/xiaodou_api.py (reported line 107)May include surrounding context.

python
"openTime": getattr(args, "%s_open_time" % prefix),
        "phone": getattr(args, "%s_phone" % prefix),
        "name": getattr(args, "%s_name" % prefix),
        "address": getattr(args, "%s_address" % prefix),
        "city": getattr(args, "%s_city" % prefix),
        "cityCode": getattr(args, "%s_city_code" % prefix),
        "districtName": getattr(args, "%s_district_name" % prefix),

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Confidence
50% confidence
Finding

Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Content

Scanner excerpt · scripts/xiaodou_api.py (reported line 121)May include surrounding context.

python
def location_payload(args, prefix, address_type=False, fence_code=False):
    payload = {
        "address": getattr(args, "%s_address" % prefix),
        "city": getattr(args, "%s_city" % prefix),
        "cityCode": getattr(args, "%s_city_code" % prefix),
        "districtName": getattr(args, "%s_district_name" % prefix),

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Confidence
50% confidence
Finding

Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Content

Scanner excerpt · scripts/xiaodou_api.py (reported line 108)May include surrounding context.

python
"phone": getattr(args, "%s_phone" % prefix),
        "name": getattr(args, "%s_name" % prefix),
        "address": getattr(args, "%s_address" % prefix),
        "city": getattr(args, "%s_city" % prefix),
        "cityCode": getattr(args, "%s_city_code" % prefix),
        "districtName": getattr(args, "%s_district_name" % prefix),
        "lat": getattr(args, "%s_lat" % prefix),

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Confidence
50% confidence
Finding

Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Content

Scanner excerpt · scripts/xiaodou_api.py (reported line 122)May include surrounding context.

python
def location_payload(args, prefix, address_type=False, fence_code=False):
    payload = {
        "address": getattr(args, "%s_address" % prefix),
        "city": getattr(args, "%s_city" % prefix),
        "cityCode": getattr(args, "%s_city_code" % prefix),
        "districtName": getattr(args, "%s_district_name" % prefix),
        "lat": getattr(args, "%s_lat" % prefix),

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Confidence
50% confidence
Finding

Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Content

Scanner excerpt · scripts/xiaodou_api.py (reported line 109)May include surrounding context.

python
"name": getattr(args, "%s_name" % prefix),
        "address": getattr(args, "%s_address" % prefix),
        "city": getattr(args, "%s_city" % prefix),
        "cityCode": getattr(args, "%s_city_code" % prefix),
        "districtName": getattr(args, "%s_district_name" % prefix),
        "lat": getattr(args, "%s_lat" % prefix),
        "lng": getattr(args, "%s_lng" % prefix),

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Confidence
50% confidence
Finding

Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Content

Scanner excerpt · scripts/xiaodou_api.py (reported line 123)May include surrounding context.

python
payload = {
        "address": getattr(args, "%s_address" % prefix),
        "city": getattr(args, "%s_city" % prefix),
        "cityCode": getattr(args, "%s_city_code" % prefix),
        "districtName": getattr(args, "%s_district_name" % prefix),
        "lat": getattr(args, "%s_lat" % prefix),
        "lng": getattr(args, "%s_lng" % prefix),

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Confidence
50% confidence
Finding

Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Content

Scanner excerpt · scripts/xiaodou_api.py (reported line 110)May include surrounding context.

python
"address": getattr(args, "%s_address" % prefix),
        "city": getattr(args, "%s_city" % prefix),
        "cityCode": getattr(args, "%s_city_code" % prefix),
        "districtName": getattr(args, "%s_district_name" % prefix),
        "lat": getattr(args, "%s_lat" % prefix),
        "lng": getattr(args, "%s_lng" % prefix),
        "date": getattr(args, "%s_date" % prefix),

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Confidence
50% confidence
Finding

Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Content

Scanner excerpt · scripts/xiaodou_api.py (reported line 124)May include surrounding context.

python
"address": getattr(args, "%s_address" % prefix),
        "city": getattr(args, "%s_city" % prefix),
        "cityCode": getattr(args, "%s_city_code" % prefix),
        "districtName": getattr(args, "%s_district_name" % prefix),
        "lat": getattr(args, "%s_lat" % prefix),
        "lng": getattr(args, "%s_lng" % prefix),
        "date": getattr(args, "%s_date" % prefix),

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Confidence
50% confidence
Finding

Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Content

Scanner excerpt · scripts/xiaodou_api.py (reported line 111)May include surrounding context.

python
"city": getattr(args, "%s_city" % prefix),
        "cityCode": getattr(args, "%s_city_code" % prefix),
        "districtName": getattr(args, "%s_district_name" % prefix),
        "lat": getattr(args, "%s_lat" % prefix),
        "lng": getattr(args, "%s_lng" % prefix),
        "date": getattr(args, "%s_date" % prefix),
    }

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Confidence
50% confidence
Finding

Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Content

Scanner excerpt · scripts/xiaodou_api.py (reported line 125)May include surrounding context.

python
"city": getattr(args, "%s_city" % prefix),
        "cityCode": getattr(args, "%s_city_code" % prefix),
        "districtName": getattr(args, "%s_district_name" % prefix),
        "lat": getattr(args, "%s_lat" % prefix),
        "lng": getattr(args, "%s_lng" % prefix),
        "date": getattr(args, "%s_date" % prefix),
    }