Back to skill

Security audit

Amazon Listing Optimizer

Security checks for vulnerabilities and agentic risk

Overview

This Amazon seller tool is mostly purpose-aligned, but it has unsafe input handling that can send research terms to non-Amazon hosts and write reports outside its intended folder.

Review before installing. Use only ordinary marketplace values such as com or co.uk, avoid confidential product plans or proprietary keywords, and be aware that the scripts scrape/query Amazon and save local JSON reports. The publisher should add marketplace allowlisting, ASIN/path validation, and clearer disclosure of report writing and third-party keyword queries.

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/analyzer.py:30
Finding
Unvalidated Marketplace Input Allows Requests to Attacker-Controlled Hosts## Vulnerability Details **File Locations**: - `scripts/analyzer.py:30-40` - `scripts/keyword_extractor.py:17-44` - `scripts/competitor_spy.py:15-26` **Vulnerability Type**: User-controlled network destination **Risk Level**: Medium ### Vulnerable Code `scripts/analyzer.py:30-40`: ```python def fetch_listing(asin, marketplace="com"): """Fetch an Amazon listing page.""" url = f"https://www.amazon.{marketplace}/dp/{asin}" headers = { "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36", "Accept-Language": "en-US,en;q=0.9", } req = urllib.request.Request(url, headers=headers) try: with urllib.request.urlopen(req, timeout=15) as resp: return resp.read().decode("utf-8", errors="ignore") ``` `scripts/keyword_extractor.py:17-44`: ```python def get_amazon_suggestions(keyword, marketplace="com"): """Get Amazon search autocomplete suggestions.""" encoded = urllib.parse.quote(keyword) url = ( f"https://completion.amazon.{marketplace}/api/2017/suggestions" f"?session-id=000-0000000-0000000" f"&customer-id=000000000" f"&request-id=000000000" f"&page-type=Gateway" f"&lop=en_US" f"&site-variant=desktop" f"&client-info=amazon-search-ui" f"&mid=ATVPDKIKX0DER" f"&alias=aps" f"&prefix={encoded}" f"&event=onKeyPress" f"&limit=11" f"&fb=1" f"&suggestion-type=KEYWORD" ) headers = { "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)", "Accept": "application/json", } try: req = urllib.request.Request(url, headers=headers) with urllib.request.urlopen(req, timeout=10) as resp: data = json.loads(resp.read().decode()) ``` `scripts/competitor_spy.py:15-26`: ```python def search_amazon(q ...[truncated 2725 chars]
Remediation
## Remediation Suggestions Replace hostname interpolation with a fixed mapping from accepted marketplace identifiers to exact trusted hosts: ```python MARKETPLACE_HOSTS = { "com": "www.amazon.com", "co.uk": "www.amazon.co.uk", "de": "www.amazon.de", "fr": "www.amazon.fr", "it": "www.amazon.it", "es": "www.amazon.es", "ca": "www.amazon.ca", "com.au": "www.amazon.com.au", } def marketplace_host(marketplace): try: return MARKETPLACE_HOSTS[marketplace] except KeyError: raise ValueError("Unsupported Amazon marketplace") ``` Maintain a separate allowlist for autocomplete hosts where necessary. Additional hardening should include: - Rejecting marketplace values not present in the allowlist. - Parsing the final URL and verifying its exact hostname before each request. - Preventing redirects to hosts outside the allowlist with a restrictive redirect handler. - Applying response-size limits before loading remote content into memory. - Avoiding checks based only on hostname prefixes or the presence of the word `amazon`.

T09 · Insecure Skill Coding Practices

Note
Location
scripts/analyzer.py:388
Finding
Unvalidated ASIN Allows Report Writes Outside the Reports Directory## Vulnerability Details **File Location**: `scripts/analyzer.py:388-404` **Vulnerability Type**: User-controlled output path **Risk Level**: Low ### Vulnerable Code ```python if __name__ == "__main__": if len(sys.argv) < 2: print("Usage: python3 analyzer.py <ASIN> [marketplace]") print("Example: python3 analyzer.py B0XXXXXXXXX") print("Example: python3 analyzer.py B0XXXXXXXXX co.uk") sys.exit(1) asin = sys.argv[1] marketplace = sys.argv[2] if len(sys.argv) > 2 else "com" report = analyze_listing(asin, marketplace) if report: # Save report to file import os report_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "reports") os.makedirs(report_dir, exist_ok=True) report_file = os.path.join(report_dir, f"{asin}-report.json") with open(report_file, "w") as f: json.dump(report, f, indent=2) ``` ### Technical Analysis The `asin` argument is used as part of the report filename without format validation or path confinement. Under Python path semantics, if the filename argument passed to `os.path.join` is absolute, the preceding `report_dir` is discarded. For example: ```python os.path.join("/skill/reports", "/tmp/audit-report") ``` resolves to: ```text /tmp/audit-report ``` Because the code appends `-report.json`, an ASIN such as `/tmp/audit` causes the destination to resolve to `/tmp/audit-report.json` rather than a file beneath the intended `reports` directory. The write occurs only when `analyze_listing` returns a report, so exploitation requires the listing fetch to return a response that the script treats as successful. The written content is generated JSON rather than arbitrary attacker-selected bytes. ### Attack Path 1. An attacker supplies an absolute-path-like value as the ASIN: ```bash python3 analyzer.py /tmp/audit ...[truncated 1061 chars]
Remediation
## Remediation Suggestions Validate ASINs before using them in either URLs or filenames. Standard ASINs should be constrained to ten uppercase alphanumeric characters: ```python ASIN_PATTERN = re.compile(r"^[A-Z0-9]{10}$") if not ASIN_PATTERN.fullmatch(asin): raise ValueError("Invalid ASIN") ``` Also enforce path confinement independently of input validation: ```python report_dir = os.path.realpath( os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "reports") ) os.makedirs(report_dir, exist_ok=True) report_file = os.path.realpath( os.path.join(report_dir, f"{asin}-report.json") ) if os.path.commonpath([report_dir, report_file]) != report_dir: raise ValueError("Invalid report path") ``` Additional hardening should include: - Deriving filenames only from validated identifiers. - Using `os.path.basename` where user-derived filename components are unavoidable. - Rejecting absolute paths and path separators explicitly. - Avoiding overwrites by using exclusive creation mode when replacement is unnecessary. - Running the Skill with minimal filesystem permissions.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (8)

Vague Triggers

Medium
Confidence
91% confidence
Finding
The skill's trigger conditions are broad enough to match generic Amazon-related requests, such as listing quality, competitor analysis, or mentions of common seller tools. This can cause unintended invocation outside a narrowly scoped user intent, leading the agent to route users into scraping/analysis workflows they did not explicitly request and increasing the chance of inappropriate or excessive external data access.

Vague Triggers

Medium
Confidence
94% confidence
Finding
The exact-match list contains highly generic triggers such as "seasoning blend," "seasoning blend for chicken," and similar broad commercial phrases that are likely to match ordinary user shopping or cooking queries. This can cause the skill to activate outside its intended scope, leading to skill hijacking, misrouting, or inappropriate interception of benign user requests.

Vague Triggers

Medium
Confidence
96% confidence
Finding
The broad-match entries include vague phrases like "seasoning blender," "seasoning blends for cooking," and product-like strings without explicit scoping rules, making activation conditions ambiguous. Broad matching on such common language increases the chance of accidental triggering from normal cooking, shopping, or recipe-related requests, which is dangerous because it expands interception well beyond a narrow user intent.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
The request header hard-codes "Accept-Language": "en-US,en;q=0.9", which imposes a specific language/locale behavior on all users. This is a natural-language policy concern because the file does not offer a user choice or explain why English is required for this skill.

Intent-Code Divergence

Medium
Confidence
95% confidence
Finding
The top-level documentation says the script 'analyzes listings' and 'finds gaps in the market,' which implies substantive competitor evaluation. In practice, the implemented logic only fetches Amazon search results, extracts ASINs, and emits canned suggestions; it does not inspect listings in detail or perform any actual market-gap analysis.

Intent-Code Divergence

Medium
Confidence
97% confidence
Finding
The top-level documentation says the tool finds keywords from both competitor listings and search suggestions. In the implementation, all keyword discovery flows through `get_amazon_suggestions`, which only calls Amazon's autocomplete API; there is no code to fetch, parse, or analyze competitor listings.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The script transmits the user-provided seed keyword and derived variations to Amazon's autocomplete endpoint without explicit advance disclosure or consent. If a user supplies sensitive business terms, product plans, or proprietary research queries, those terms are exposed to a third party and may be logged or profiled externally.

Missing User Warnings

Low
Confidence
80% confidence
Finding
The script saves keyword research results into a JSON file under the `reports` directory, but this behavior is not disclosed in the top-level description or CLI usage text before execution. The save is only revealed after the operation completes.

Static analysis

No suspicious patterns detected.