Back to skill

Security audit

Used Price Compare

Security checks for vulnerabilities and agentic risk

Overview

The skill appears to be a real second-hand price comparison tool, but it needs review because browser access, URL handling, image fetching, and vision API configuration are too broad for safe default use.

Install only after reviewing the browser and network implications. Use a dedicated Chrome profile for bb-browser, avoid untrusted listing URLs, pin and verify bb-browser before installing it, and only enable vision analysis with a trusted HTTPS API endpoint and a provider-specific key.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (5)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/used_price_compare/fetcher.py:20
Finding
Weak Marketplace Hostname Validation Allows Navigation to Attacker-Controlled Origins<![CDATA[ ## Vulnerability Details **File Location**: `scripts/used_price_compare/fetcher.py:20-46`; request sink in `adapters/ebay/detail.js:17` and equivalent detail adapters **Vulnerability Type**: Insufficient URL validation and arbitrary browser navigation **Risk Level**: High ### Vulnerable Code ```python _PLATFORM_RULES: list[tuple[str, str, str]] = [ # (domain pattern, adapter name, platform label) (r"\.ok\.com$", "ok/detail", "ok.com"), (r"\.ebay\.", "ebay/detail", "ebay"), (r"\.gumtree\.com$", "gumtree/detail", "gumtree"), (r"\.amazon\.", "amazon/detail", "amazon"), ] def resolve_adapter(url: str) -> tuple[str, str] | None: """Determine which bb-browser adapter to use for a given URL.""" try: host = urlparse(url).hostname or "" except Exception: return None for pattern, adapter, label in _PLATFORM_RULES: if re.search(pattern, host): return adapter, label return None ``` The accepted URL is subsequently passed unchanged to an adapter: ```javascript async function(args) { if (!args.url) return { error: 'Missing argument: url' }; const resp = await fetch(args.url, { credentials: 'include' }); if (!resp.ok) return { error: `HTTP ${resp.status}`, hint: 'Check if the listing URL is valid' }; ``` ### Technical Analysis The eBay and Amazon patterns are substring checks rather than registrable-domain checks. A hostname such as `shop.ebay.attacker.example` contains `.ebay.` and is therefore accepted as eBay, despite being controlled by an attacker. The same weakness applies to names containing `.amazon.`. The accepted URL is opened in the bb-browser context with `credentials: 'include'`. Browser cookie scoping should ordinarily prevent actual eBay or Amazon cookies from being attached to an unrelated attacker domain, so direct cross-domain cookie theft is not established. Nevertheless, this permits an attacker to make the Skill navigate its browser context to an arbitrar ...[truncated 1304 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Require `https` explicitly and reject URLs containing usernames, passwords, malformed ports, or unsupported schemes. 2. Replace substring regular expressions with exact registrable-domain allowlists. 3. Accept a host only when it is exactly an approved domain or ends with `"." + approved_domain`. 4. Maintain explicit regional allowlists, for example: - `ebay.com`, `ebay.co.uk`, `ebay.com.au`, `ebay.ca` - `amazon.com`, `amazon.co.uk` - approved Gumtree and OK.com domains 5. Normalize hostnames using IDNA before comparison and reject ambiguous or invalid hostnames. 6. Revalidate the destination after every redirect. 7. Avoid `credentials: 'include'` unless authenticated marketplace access is necessary. Prefer `credentials: 'omit'` for public listing pages. 8. Add negative tests for hosts such as `ebay.attacker.example`, `amazon.evil.example`, and `ebay.com.attacker.example`. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/used_price_compare/evaluator.py:174
Finding
Unvalidated Listing Image Downloads Enable SSRF and Unbounded Memory Consumption<![CDATA[ ## Vulnerability Details **File Location**: `scripts/used_price_compare/evaluator.py:174-189` and `scripts/used_price_compare/evaluator.py:225-234` **Vulnerability Type**: Server-side request forgery and resource exhaustion **Risk Level**: High ### Vulnerable Code ```python def _download_image_as_base64(img_url: str, timeout: int = 15) -> str | None: """Download an image and return it as a base64 data URL. Returns None if download fails. """ try: req = urllib.request.Request( img_url, headers={"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36"}, ) with urllib.request.urlopen(req, timeout=timeout) as resp: data = resp.read() content_type = resp.headers.get("Content-Type", "image/jpeg") import base64 b64 = base64.b64encode(data).decode("utf-8") return f"data:{content_type};base64,{b64}" except Exception as e: logger.debug("Image download failed for %s: %s", img_url, e) return None ``` The function is invoked for image URLs obtained from listing content: ```python content: list[dict] = [{"type": "text", "text": prompt_text}] downloaded_count = 0 for img_url in item.images[: cfg.max_images]: data_url = _download_image_as_base64(img_url, timeout=cfg.timeout) if data_url: content.append({"type": "image_url", "image_url": {"url": data_url}}) downloaded_count += 1 else: logger.debug("Skipping unreachable image: %s", img_url) ``` ### Technical Analysis The downloader trusts image URLs extracted from marketplace or attacker-controlled HTML. It performs no validation of: - URL scheme - Destination hostname - Resolved IP address - Redirect destination - Response content type - Response body size Consequently, a malicious listing can cause the Python process to issue requests to loopback, private, link-local, or cloud metadata addresses. Redirects ...[truncated 1752 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Permit only HTTPS image URLs. 2. Resolve the destination hostname and reject loopback, private, link-local, multicast, unspecified, and reserved IPv4 and IPv6 addresses. 3. Re-resolve and validate every redirect target; alternatively, disable redirects and handle approved redirects manually. 4. Allowlist expected marketplace image CDN domains where practical. 5. Stream responses in bounded chunks instead of calling unbounded `resp.read()`. 6. Enforce a strict per-image size limit and a total size limit per evaluation. 7. Verify that `Content-Type` is an approved image media type and confirm the file signature before encoding. 8. Limit dimensions and decoded pixel count to prevent decompression-bomb attacks. 9. Apply separate, conservative connection and read timeouts. 10. Do not forward data fetched from untrusted locations to third-party APIs until destination validation succeeds. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/used_price_compare/evaluator.py:137
Finding
Unrestricted Vision API Endpoint Can Receive API Credentials and Listing Data<![CDATA[ ## Vulnerability Details **File Location**: `scripts/used_price_compare/evaluator.py:137-166` and `scripts/used_price_compare/evaluator.py:218-269` **Vulnerability Type**: Sensitive-data transmission to an unvalidated endpoint **Risk Level**: High ### Vulnerable Code ```python # 2. Environment variables (override file values) env_base = os.environ.get("VISION_API_BASE", "") env_key = os.environ.get("VISION_API_KEY", "") env_model = os.environ.get("VISION_MODEL", "") if env_base: cfg.api_base = env_base if env_key: cfg.api_key = env_key if env_model: cfg.model = env_model # 3. CLI override (highest priority) if model_override: cfg.model = model_override return cfg ``` The resolved endpoint receives the API key and listing content: ```python prompt_text = _VISION_EVAL_PROMPT.format( title=item.title, description=item.description[:500], condition=item.condition or "未标注", price=item.price or "未知", ) content: list[dict] = [{"type": "text", "text": prompt_text}] ``` ```python url = f"{cfg.api_base.rstrip('/')}/chat/completions" headers = { "Content-Type": "application/json", "Authorization": f"Bearer {cfg.api_key}", } req = urllib.request.Request( url, data=json.dumps(payload, ensure_ascii=False).encode("utf-8"), headers=headers, ) try: with urllib.request.urlopen(req, timeout=cfg.timeout) as resp: result = json.loads(resp.read().decode("utf-8")) ``` ### Technical Analysis `VISION_API_BASE` can originate from a persistent user configuration file or an environment variable. The value is used without checking its scheme, hostname, port, or trust status. The resulting request contains: - The configured bearer API key - Listing title - Up to 500 characters of listing description - Condition and price - Base64-encoded listing images A malicious or compromised environment can set the base URL to an attacker endpoint. Plain HTTP is also accepted, permitting interception of the bearer tok ...[truncated 1388 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Require an HTTPS API base URL and reject all other schemes. 2. Reject URLs containing embedded credentials, fragments, malformed ports, or unexpected path structures. 3. Maintain an allowlist of approved vision API domains, or require explicit confirmation when a new domain is first configured. 4. Clearly display the resolved API hostname before transmitting listing images or descriptions. 5. Separate provider credentials by endpoint so a key intended for one provider cannot be sent to another. 6. Store credentials using an operating-system credential manager rather than plaintext JSON where possible. 7. Apply restrictive permissions, such as mode `0600`, to any configuration file containing an API key. 8. Add an explicit opt-in flag for third-party image processing and document exactly which fields are transmitted. 9. Avoid logging request headers or credentials, including during exception handling. 10. Add tests rejecting HTTP, loopback addresses, private-network endpoints, and unapproved domains. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/used_price_compare/compare.py:113
Finding
Daemon Recovery Uses Broad Process Matching and Terminates Unrelated Processes<![CDATA[ ## Vulnerability Details **File Location**: `scripts/used_price_compare/compare.py:113-133`; duplicated in `scripts/used_price_compare/fetcher.py:68-88` **Vulnerability Type**: Overbroad process termination **Risk Level**: Medium ### Vulnerable Code ```python def _ensure_daemon() -> bool: """Ensure bb-browser daemon is running and connected. Returns True if ready.""" import socket, time try: result = subprocess.run( ["bb-browser", "daemon", "status"], capture_output=True, text=True, timeout=10 ) if "CDP connected: yes" in result.stdout: return True except Exception: pass # Try to restart subprocess.run(["pkill", "-f", "bb-browser"], capture_output=True) time.sleep(1) try: subprocess.Popen( ["bb-browser", "daemon", "start"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL ) time.sleep(3) return True except Exception: return False ``` The detail-fetching implementation repeats the same logic: ```python subprocess.run(["pkill", "-f", "bb-browser"], capture_output=True) time.sleep(1) try: subprocess.Popen( ["bb-browser", "daemon", "start"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, ) ``` ### Technical Analysis `pkill -f bb-browser` matches the full command line of every process owned by the invoking user that contains the text `bb-browser`. It is not limited to the daemon process created or managed by this Skill. Although the subprocess call does not use a shell and therefore is not command injection, the process selection is unnecessarily broad. A transient daemon connectivity failure can terminate unrelated browser sessions, concurrent Skill executions, debugging sessions, or other tools whose command lines include that text. ### Attack Path 1. A compare or detail operation returns the `daemon_disconnected` condition. 2. The code invokes `_ ...[truncated 763 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Use a documented bb-browser daemon stop or restart command that targets only the managed daemon. 2. If no targeted command exists, record the daemon PID when it is started. 3. Before terminating a stored PID, verify process ownership, executable path, start time, and expected command arguments. 4. Send a graceful termination signal first and use a bounded wait before any forced termination. 5. Coordinate daemon recovery with a lock so parallel requests cannot repeatedly restart the daemon. 6. Recheck daemon status after startup rather than returning success solely because `Popen()` succeeded. 7. Remove the unused `socket` import and centralize duplicated daemon-management logic in one hardened implementation. ]]>

T08 · Insecure Dependencies

Warning
Location
SKILL.md:132
Finding
Unpinned Global npm Installation Creates Supply-Chain Exposure<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:132-135`; equivalent guidance in `README.md:72` **Vulnerability Type**: Mutable and globally installed third-party dependency **Risk Level**: Medium ### Vulnerable Code ```markdown ## Failure handling - **bb-browser missing**: suggest `npm install -g bb-browser` and start the daemon. - **Adapters missing**: suggest `python scripts/cli.py install`. ``` The package is also declared as an external executable requirement: ```yaml metadata: openclaw: requires: bins: - python3 - bb-browser ``` ### Technical Analysis The recommended command installs the current npm release of `bb-browser` globally without specifying an audited version or integrity value. npm installation may execute package lifecycle scripts with the installing user’s privileges. Because the dependency is mutable, the effective code installed in the future may differ from the version reviewed alongside this Skill. A registry compromise, package-owner compromise, malicious future release, or dependency takeover could introduce arbitrary code into the execution path. The audit found no evidence that the currently referenced package is malicious. The finding concerns the unsafe, unpinned installation mechanism and global scope. ### Attack Path 1. An attacker compromises the npm package, publisher account, or a transitive dependency used by a future release. 2. The user follows the Skill’s failure guidance and runs `npm install -g bb-browser`. 3. npm resolves the latest mutable package version rather than a reviewed version. 4. Malicious package code or lifecycle scripts execute with the installing user’s privileges. 5. The globally installed executable is subsequently trusted and invoked by the Skill for marketplace operations. ### Impact Assessment A compromised package installation can execute arbitrary code with the privileges of the user running npm. The global installation can affect other project ...[truncated 256 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin `bb-browser` to a specific audited version, for example `bb-browser@<reviewed-version>`. 2. Document the expected npm registry and package publisher. 3. Record and verify package integrity information where the installation mechanism permits. 4. Prefer a project-local or isolated installation rather than `-g`. 5. Commit a lockfile for reproducible dependency resolution. 6. Audit the pinned package and its transitive dependency tree. 7. Avoid recommending installation with `sudo` or another privileged account. 8. Establish an update process that reviews package changes before changing the pinned version. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Rogue AgentSelf-Modification, Session Persistence
  • 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 (68)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The declared description promises a cross-platform second-hand price comparison and evaluation tool that compares prices across marketplaces and assesses trust, condition, and value. The actual code only retrieves details from a single Amazon product page and returns parsed fields. It does not compare against other marketplaces, compute deal quality or value, perform trust/risk analysis, or provide a broader second-hand evaluation workflow. While it does extract some supporting signals such as condition, seller info, ratings, and price, these are raw data fields rather than the higher-level comparison and assessment behavior described.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The declared description promises a broad cross-platform second-hand comparison and evaluation tool that compares prices across multiple marketplaces and assesses seller trustworthiness, condition, and value. The supplied code only searches a single marketplace, Amazon UK, and returns listing data plus basic price summaries. While it does expose some useful fields like condition, rating, and review count, it does not actually compare across marketplaces, score seller trust, or perform substantive item valuation or worth-it analysis. Its primary purpose is a single-site marketplace search adapter, which is materially narrower than the declared purpose.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The declared description promises a broad comparison/evaluation tool across marketplaces for second-hand items, including assessing seller trust, condition, and value. The supplied code only searches Amazon.com listings and returns scraped search-result data plus basic price summary stats. While it supports some relevant pieces such as condition filtering and price collection, it does not compare across multiple marketplaces, does not analyze seller trust, and does not make any judgment about whether an item is worth buying. Its primary purpose is Amazon product search, which is materially narrower than the declared purpose.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding
The implementation is limited to searching eBay and extracting listing data such as title, price, condition, shipping, seller text, image, and simple aggregate price stats. It does not compare prices across multiple marketplaces, does not perform deeper evaluation of whether an item is 'worth it,' and does not actually assess seller trust beyond returning any seller-related text found in the listing. While it partially aligns with second-hand shopping and condition-related data collection, the declared primary purpose is broader and more analytical than the code's actual single-marketplace search behavior.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The declared description promises a higher-level cross-platform comparison and evaluation skill: comparing prices across marketplaces, finding the cheapest deal, and assessing trust/value. The supplied code does not implement comparison, search, aggregation across multiple marketplaces, scoring, or valuation logic. Instead, it only reads a single provided eBay listing URL and extracts structured listing details and seller metadata. While some extracted fields could support later evaluation, this chunk itself is an eBay-specific detail scraper, so the actual behavior is materially narrower and different from the declared purpose.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The declared description promises a broader comparison and evaluation tool: cross-platform marketplace price comparison plus assessment of seller trust, item condition, and whether an item is worth buying. The code only implements a read-only scraper/search adapter for eBay Australia. It gathers listing titles, prices, URLs, condition text, shipping, and limited seller-related text from eBay search results, then computes simple aggregate price statistics. It does not compare across multiple marketplaces, does not evaluate trustworthiness beyond extracting a seller-related string if present, and does not perform any substantive value or worth-it analysis. The actual code is therefore materially narrower and different in primary purpose than the declared description.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding
The code only searches a single marketplace (eBay Canada) and returns scraped listing results plus basic price aggregation. While it includes some listing metadata such as condition, shipping, and a seller-related text snippet, it does not actually compare across multiple marketplaces or perform substantive evaluation of seller trust, item value, or whether an item is 'worth it.' The declared description promises broader comparison and assessment capabilities than the code implements, so this is a meaningful description-behavior mismatch.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding
The code implements a single-site eBay UK marketplace search adapter, not a cross-platform comparison tool. It fetches and parses ebay.co.uk search results, extracts listing title, price, URL, condition, shipping, limited seller text, image, and computes simple price summaries. While this supports basic price lookup and condition filtering, it does not compare across multiple marketplaces, does not perform substantive trust analysis, and does not evaluate whether an item is 'worth it' beyond returning raw listings and aggregate prices. The declared description therefore overstates the scope and evaluation capabilities relative to the actual code.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The code only implements a single-marketplace eBay US search adapter. It fetches eBay search results, extracts listing fields, and computes a simple price range/average from those results. While it does capture some surface metadata such as condition, shipping text, and occasional seller-related text, it does not actually compare across multiple marketplaces, score seller trustworthiness, evaluate item quality in depth, or determine whether the item is 'worth it.' The declared description therefore overstates the skill’s scope and primary purpose relative to the supplied code chunk.

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding
The code only implements a marketplace-specific detail extractor for one Gumtree listing URL. It reads a page and returns structured listing fields, but it does not compare prices across marketplaces, search for cheapest deals, aggregate multiple listings, or perform any evaluative analysis of seller trust, item value, or whether the item is worth buying. While extracting seller/member-since and condition fields could support later evaluation, those are supporting data points rather than the declared end-user capability. Therefore the declared description materially overstates the actual behavior and primary purpose of this code chunk.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding
The code only searches a single marketplace (Gumtree UK) and extracts listing data such as title, price, location, description, image, and URL. It computes basic min/max/average price summaries from those results, but it does not compare prices across multiple marketplaces, evaluate seller trustworthiness, assess item condition in any substantive way, or perform in-depth value analysis. The declared purpose therefore overstates the actual behavior and describes materially different primary capabilities.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The code only implements a read-only scraper for one marketplace domain (ok.com) and returns raw listing details from a single item page. It does not compare prices across multiple marketplaces, aggregate listings, identify cheapest options, or compute any evaluation of value or trustworthiness. While it extracts some inputs that could support later evaluation (condition, seller metadata), it does not itself perform the declared comparison or assessment behavior. Therefore the declared description materially overstates the actual implemented capability and primary purpose.

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding
The code implements a single-site search adapter for OK.com. It fetches and parses listing data, normalizes prices, and computes simple summary stats like range and average. It does not compare results across multiple marketplaces, assess seller trustworthiness, evaluate item condition, or determine whether an item is worth buying. The actual behavior is narrower and materially different from the declared purpose.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The code accurately supports the price-comparison portion of the description: it searches multiple platforms, normalizes listing data, ranks items by price, and formats a cross-platform report. However, the declared description also promises in-depth item evaluation, seller trust assessment, condition assessment, and value judgment ('worth it'). This code does not implement those capabilities; it only carries through raw seller/condition fields and explicitly states that analysis and purchase recommendations are handled by the calling agent or another sub-skill. Therefore, the description materially overstates what this code chunk does.

Tp4

High
Category
MCP Tool Poisoning
Confidence
88% confidence
Finding
The code chunk is consistent with part of the declared purpose: it supports cross-platform price comparison infrastructure by defining platforms and resolving region-specific marketplace adapters. However, it does not implement the 'in-depth item evaluation' aspects claimed in the description, such as assessing seller trustworthiness, evaluating item condition, or determining whether an item is worth buying. Those are materially distinct capabilities, and this code only handles platform selection, city/country normalization, and command construction for searches. Therefore the description overstates what this code actually does.

Self-Modification

High
Category
Rogue Agent
Content
| `--urls` | Comma-separated URLs | `evaluate`, `summarize` |
| `--vision-model` | Vision model name | `evaluate`, `summarize` |
| `action` | `show` (default) or `init` | `vision-config` |
| `--force` | Overwrite existing config | `vision-config init` |

## Output format
Confidence
85% confidence
Finding
Skill modifies its own code, configuration, or behavior at runtime. Self-modification enables an agent to escalate privileges, disable safety constraints, or install persistent backdoors.

Self-Modification

High
Category
Rogue Agent
Content
| `--urls` | Comma-separated URLs | `evaluate`, `summarize` |
| `--vision-model` | Vision model name | `evaluate`, `summarize` |
| `action` | `show` (default) or `init` | `vision-config` |
| `--force` | Overwrite existing config | `vision-config init` |

## Output format
Confidence
85% confidence
Finding
Skill modifies its own code, configuration, or behavior at runtime. Self-modification enables an agent to escalate privileges, disable safety constraints, or install persistent backdoors.

Skill Enumeration

Medium
Category
Agent Snooping
Content
- `evaluator.py` — 5-dimension scoring engine (seller trust, listing authenticity, condition value, price competitiveness, risk flags)
- `fetcher.py` — URL-to-platform routing and bb-browser subprocess management for detail pages
- `models.py` — `ItemDetail`, `SellerInfo`, `EvalScores`, `EvalResult` dataclasses
- `skills/compare/SKILL.md` and `skills/evaluate/SKILL.md` sub-skill definitions
- 10 new smoke tests covering URL routing, evaluator scoring, and CLI parser

### Changed
Confidence
80% confidence
Finding
Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.

Skill Enumeration

Medium
Category
Agent Snooping
Content
- `evaluator.py` — 5-dimension scoring engine (seller trust, listing authenticity, condition value, price competitiveness, risk flags)
- `fetcher.py` — URL-to-platform routing and bb-browser subprocess management for detail pages
- `models.py` — `ItemDetail`, `SellerInfo`, `EvalScores`, `EvalResult` dataclasses
- `skills/compare/SKILL.md` and `skills/evaluate/SKILL.md` sub-skill definitions
- 10 new smoke tests covering URL routing, evaluator scoring, and CLI parser

### Changed
Confidence
80% confidence
Finding
Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.

Skill Enumeration

Medium
Category
Agent Snooping
Content
- `evaluator.py` — 5-dimension scoring engine (seller trust, listing authenticity, condition value, price competitiveness, risk flags)
- `fetcher.py` — URL-to-platform routing and bb-browser subprocess management for detail pages
- `models.py` — `ItemDetail`, `SellerInfo`, `EvalScores`, `EvalResult` dataclasses
- `skills/compare/SKILL.md` and `skills/evaluate/SKILL.md` sub-skill definitions
- 10 new smoke tests covering URL routing, evaluator scoring, and CLI parser

### Changed
Confidence
80% confidence
Finding
Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.

Skill Enumeration

Medium
Category
Agent Snooping
Content
- `evaluator.py` — 5-dimension scoring engine (seller trust, listing authenticity, condition value, price competitiveness, risk flags)
- `fetcher.py` — URL-to-platform routing and bb-browser subprocess management for detail pages
- `models.py` — `ItemDetail`, `SellerInfo`, `EvalScores`, `EvalResult` dataclasses
- `skills/compare/SKILL.md` and `skills/evaluate/SKILL.md` sub-skill definitions
- 10 new smoke tests covering URL routing, evaluator scoring, and CLI parser

### Changed
Confidence
80% confidence
Finding
Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.

Skill Enumeration

Medium
Category
Agent Snooping
Content
- `evaluator.py` — 5-dimension scoring engine (seller trust, listing authenticity, condition value, price competitiveness, risk flags)
- `fetcher.py` — URL-to-platform routing and bb-browser subprocess management for detail pages
- `models.py` — `ItemDetail`, `SellerInfo`, `EvalScores`, `EvalResult` dataclasses
- `skills/compare/SKILL.md` and `skills/evaluate/SKILL.md` sub-skill definitions
- 10 new smoke tests covering URL routing, evaluator scoring, and CLI parser

### Changed
Confidence
80% confidence
Finding
Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.

Missing User Warnings

Medium
Confidence
85% confidence
Finding
The setup instructions tell users to launch Chrome with a remote debugging port, which grants powerful access to browser state and tabs. The README also describes cross-platform fetching via bb-browser, but it does not include any user-facing warning about privacy, active-session exposure, or the need to use a dedicated browser profile.

Lp3

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding
The skill declares broad operational capabilities through its documented workflow (shelling out to Python, browser automation, network-backed marketplace access, and likely file/env access) but does not define an explicit tool scope such as permissions or allowed-tools. That creates an unnecessary trust boundary gap: an agent may grant more capabilities than the task actually needs, increasing the blast radius if downstream scripts or adapters are compromised or behave unexpectedly.

Vague Triggers

Medium
Confidence
95% confidence
Finding
The trigger phrases include very broad terms such as 'cheapest,' 'worth it,' and 'trustworthy,' in both English and Chinese, which can cause the skill to activate in unrelated conversations. Over-broad invocation increases the chance that a shell/network-capable skill runs unexpectedly, causing unnecessary browsing, data access, or external requests in contexts where the user did not intend marketplace analysis.

Static analysis

No suspicious patterns detected.