Back to skill

Security audit

Price Monitor

Security checks for vulnerabilities and agentic risk

Overview

This skill mostly matches price monitoring, but it gives browser automation broad authority to open arbitrary URLs from a CSV without guardrails, which can reach local or private resources.

Review before installing. Use this only with product lists you control, restrict monitored URLs to trusted public retailer domains, avoid opening generated CSV files in spreadsheet software with formula evaluation enabled, and do not configure external alerts unless you are comfortable sending monitored URLs and price data to those services.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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 (2)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/monitor_prices.py:41
Finding
Unrestricted Browser Navigation Enables Access to Internal and Local Resources<![CDATA[ ## Vulnerability Details **File Location**: `scripts/monitor_prices.py:41-65`, with attacker-controlled input passed at `scripts/monitor_prices.py:145` **Vulnerability Type**: Server-Side Request Forgery and local-resource access **Risk Level**: High ### Vulnerable Code ```python def get_page_snapshot(url): """Open URL and get interactive snapshot.""" # Open the page stdout, stderr, code = run_agent_browser(["open", url]) if code != 0: return None, f"Failed to open {url}: {stderr}" # Get snapshot stdout, stderr, code = run_agent_browser(["snapshot", "-i", "--json"]) if code != 0: return None, f"Failed to get snapshot: {stderr}" try: elements = json.loads(stdout) return elements, None except json.JSONDecodeError: return None, "Failed to parse snapshot JSON" def extract_price(url, selector): """Extract price from a webpage using agent-browser.""" # Open the page stdout, stderr, code = run_agent_browser(["open", url]) if code != 0: return None, f"Failed to open page: {stderr}" # Try to find element by selector stdout, stderr, code = run_agent_browser(["get", "text", selector]) ``` The unvalidated URL originates from the product CSV: ```python price, error = extract_price(product['url'], product['selector']) ``` ### Technical Analysis The script passes a URL read directly from a user-supplied CSV file to `agent-browser open`. It does not restrict URL schemes, destination hostnames, resolved IP addresses, ports, or redirects. Consequently, a malicious product list can instruct the browser to navigate to destinations outside the intended public e-commerce scope. Depending on the protocols supported by `agent-browser`, possible targets include: - Loopback services such as `http://127.0.0.1` or `http://localhost` - Private network services in RFC 1918 address ranges - Link-local services, including cloud metadata endpoints such as ...[truncated 1858 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Permit only `http` and `https` URLs and reject all other schemes. 2. Reject URLs containing embedded credentials or malformed hostnames. 3. Resolve the hostname before navigation and reject every resolved address that is loopback, private, link-local, multicast, unspecified, or otherwise reserved. 4. Explicitly block known metadata destinations, including IPv4 and IPv6 metadata addresses. 5. Revalidate the destination after every redirect to prevent redirect-based SSRF. 6. Consider requiring an explicit allowlist of approved retailer domains. 7. Restrict unnecessary ports, preferably allowing only ports 80 and 443. 8. Run browser automation in a network sandbox that cannot reach local, private, or metadata networks. 9. Apply DNS-rebinding-resistant validation by connecting only to the already validated address or enforcing equivalent browser/network-layer controls. 10. Validate selectors and extracted data against the expected price format before storing them. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/monitor_prices.py:98
Finding
Untrusted Values Are Written to CSV Without Spreadsheet Formula Neutralization<![CDATA[ ## Vulnerability Details **File Location**: `scripts/monitor_prices.py:98-107`, with untrusted records constructed at `scripts/monitor_prices.py:160-165` and `scripts/monitor_prices.py:181-187` **Vulnerability Type**: CSV/spreadsheet formula injection **Risk Level**: Medium ### Vulnerable Code ```python def save_history(history_path, results): """Save price results to history file.""" file_exists = Path(history_path).exists() with open(history_path, 'a', encoding='utf-8', newline='') as f: fieldnames = ['timestamp', 'name', 'url', 'price', 'status'] writer = csv.DictWriter(f, fieldnames=fieldnames) if not file_exists: writer.writeheader() for result in results: writer.writerow(result) ``` Untrusted CSV fields and browser-derived text are placed into the records without neutralization: ```python results.append({ 'timestamp': timestamp, 'name': product['name'], 'url': product['url'], 'price': f'ERROR: {error}', 'status': 'error' }) ``` ```python results.append({ 'timestamp': timestamp, 'name': product['name'], 'url': product['url'], 'price': price, 'status': status }) ``` ### Technical Analysis The `name` and `url` fields originate from the input product CSV, while `price` may contain text controlled by the monitored webpage. These values are passed directly to `csv.DictWriter.writerow()`. CSV escaping and quoting only preserve the CSV structure; they do not force spreadsheet applications to interpret cells as literal text. When a generated cell begins with characters such as `=`, `+`, `-`, or `@`, spreadsheet software may evaluate it as a formula when the operator opens `price-history.csv`. An attacker can therefore place a spreadsheet formula in a product name or cause selected webpage text to contain one. Depending on the spreadsheet application and its security configuration, formulas can initiate external reques ...[truncated 1258 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Sanitize every untrusted field before writing it to CSV, including product names, URLs, prices, statuses, and error messages. 2. Treat values beginning with `=`, `+`, `-`, or `@` as dangerous. Also account for leading whitespace, tabs, carriage returns, and other characters that spreadsheet applications may ignore before formula detection. 3. Prefix dangerous values with an apostrophe or otherwise encode them so the target spreadsheet application treats them as text. 4. Validate extracted prices against a strict expected format rather than storing arbitrary page text. 5. Prefer JSON or another non-executable data format when spreadsheet compatibility is unnecessary. 6. Document that generated CSV files contain externally sourced data and should not be opened with formula evaluation enabled. 7. Add automated tests covering formula-leading values in every exported field. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • 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
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (5)

Tp4

High
Category
MCP Tool Poisoning
Confidence
90% confidence
Finding
The code substantially supports price monitoring, price history logging, and basic alerting for price changes. However, it does not implement inventory monitoring or general website content change detection; it only attempts to extract price text from pages. It also does not perform scheduling itself—execution is manual via CLI—and 'alert notifications' are only printed to the console rather than sent through a notification channel. So the description overstates the implemented capabilities, making it a mismatch.

Lp3

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding
The skill demonstrates shell usage, file reads, and file writes but does not declare any tool scope or permissions boundaries. That makes the operational capability broader and less auditable than the metadata suggests, increasing the risk of unintended command execution, local file modification, or misuse if the skill is invoked in a permissive environment.

Vague Triggers

Medium
Confidence
89% confidence
Finding
The activation language is broad enough to trigger on generic web-monitoring or tracking requests beyond narrowly defined price checks. In an agent environment, overbroad routing can cause the skill to be selected for unintended tasks, expanding exposure to browser automation, shell, and file-writing behaviors in contexts the user did not specifically authorize.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The skill advertises email and Discord webhook alerts without warning that collected monitoring data may be transmitted to third-party services. This can lead to unintentional exfiltration of URLs, pricing data, inventory details, or other monitored content outside the local environment, especially if users assume the skill is purely local.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
"""Run agent-browser command and return output."""
    cmd = ["agent-browser"] + args
    try:
        result = subprocess.run(
            cmd,
            capture_output=True,
            text=True,
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Static analysis

No suspicious patterns detected.