Back to skill

Security audit

Amazon After Sales Flow Luoqianchenguni Max

Security checks for vulnerabilities and agentic risk

Overview

This skill is mostly a disclosed Amazon after-sales automation tool, but it exposes live-account browser automation with under-scoped controls that could run an arbitrary browser executable or navigate to attacker-controlled lookalike pages.

Install only if you are comfortable giving this skill control of an authenticated browser session for Amazon. Use it interactively, avoid untrusted JSON inputs, do not pass browser.executablePath or browser.userDataDir, keep auto_send off unless you deliberately intend to send, and review generated messages/screenshots before sharing or retaining them.

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 (3)

T09 · Insecure Skill Coding Practices

Error
Location
skills/_easybuy_browser_runtime.js:56
Finding
Weak Amazon Hostname Validation Permits Navigation to Attacker-Controlled Domains<![CDATA[ ## Vulnerability Details **File Location**: `skills/_easybuy_browser_runtime.js`, lines 56-80 **Vulnerability Type**: Improper hostname allowlist validation **Risk Level**: High ### Vulnerable Code ```javascript function amazonBase(origin) { if (!origin) return "https://www.amazon.com"; try { const u = new URL(String(origin)); if (["http:", "https:"].includes(u.protocol) && /amazon\./i.test(u.hostname)) { return `${u.protocol}//${u.host}`; } } catch { } return "https://www.amazon.com"; } function isTrustedAmazonUrl(raw) { try { const u = new URL(String(raw)); const hostOk = /(^|\.)amazon\./i.test(String(u.hostname || "")); return u.protocol === "https:" && hostOk; } catch { return false; } } function sanitizeAmazonUrl(raw, fieldName = "url") { const value = String(raw || "").trim(); if (!value) throw new Error(`${fieldName}_missing`); if (!isTrustedAmazonUrl(value)) throw new Error(`${fieldName}_not_allowed`); return new URL(value).toString(); } ``` ### Technical Analysis The runtime attempts to restrict browser navigation to Amazon by testing hostnames with regular expressions containing `amazon.`. These tests do not verify that the hostname is an Amazon-owned registrable domain. For example, all of the following attacker-controlled hostnames satisfy at least one of the checks: - `amazon.evil.example` - `x.amazon.evil.example` - `amazon.example.org` The `amazonBase` check is additionally weaker because it accepts any hostname containing `amazon.` and permits both HTTP and HTTPS. The affected value is used to construct order and product URLs. The public dispatcher forwards user-controlled JSON properties to the runtime without enforcing the generated input schemas. This is an allowlist bypass rather than a direct disclosure of Amazon cookies: browser cookie scoping normally prevents Amazon cookies from being sent to unrelated domains. Nevertheless, the bypass moves authenticated workflo ...[truncated 1823 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace substring regular expressions with an explicit domain allowlist. 2. Compare parsed, normalized hostnames rather than the complete URL string. 3. Permit only HTTPS, including in `amazonBase`. 4. Validate the final URL immediately before every navigation. 5. Verify the URL again after redirects and abort if the final origin is not approved. 6. Consider maintaining a deliberate marketplace allowlist rather than accepting every domain containing the Amazon brand. Example hardening: ```javascript const ALLOWED_AMAZON_HOSTS = new Set([ "www.amazon.com", "amazon.com" ]); function isAllowedAmazonHost(hostname) { const host = String(hostname || "").toLowerCase().replace(/\.$/, ""); return ALLOWED_AMAZON_HOSTS.has(host); } function sanitizeAmazonUrl(raw, fieldName = "url") { const value = String(raw || "").trim(); if (!value) throw new Error(`${fieldName}_missing`); const url = new URL(value); if (url.protocol !== "https:" || !isAllowedAmazonHost(url.hostname)) { throw new Error(`${fieldName}_not_allowed`); } return url.toString(); } ``` If marketplace subdomains are required, allow them only as suffixes of a specific registrable domain: ```javascript host === "amazon.com" || host.endsWith(".amazon.com") ``` Do not use checks such as `host.includes("amazon.")`. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
skills/_easybuy_browser_runtime.js:364
Finding
Contact Flow Follows Unvalidated DOM Links and Cross-Origin Pages<![CDATA[ ## Vulnerability Details **File Location**: `skills/_easybuy_browser_runtime.js`, lines 364-421 and 988-1011 **Vulnerability Type**: Unvalidated cross-origin navigation **Risk Level**: High ### Vulnerable Code The contact-flow URL classification checks only path text and does not verify the scheme or hostname: ```javascript async function runContactFlow(initialPage, context = null, includePage = false, logger = null) { let page = initialPage; const log = []; const logEvt = typeof logger === "function" ? logger : () => {}; const isContactLikeUrl = (url) => /\/gp\/help\/contact|\/messaging|\/message-us|\/contact-us/i.test(String(url || "")); // ... const findContactUrl = async (p) => { return p.evaluate(() => { const links = Array.from(document.querySelectorAll("a[href]")); const target = links.find((a) => /\/gp\/help\/contact|contact-us|messaging/i.test(String(a.getAttribute("href") || ""))); return target ? target.href : null; }).catch(() => null); }; const maybeSwitchPage = async () => { if (!context) return; const pages = context.pages(); const target = pages.find((p) => isContactLikeUrl(p.url())) || null; if (target && target !== page) { const from = page.url(); page = target; await page.bringToFront().catch(() => {}); logEvt("contact.switch_page", { from, to: page.url() }); } }; ``` The discovered URL is subsequently navigated without passing through `sanitizeAmazonUrl`: ```javascript if (!isContactLikeUrl(page.url())) { const contactUrl = await findContactUrl(page); logEvt("contact.goto_contact_url.try", { contactUrl: contactUrl || null, currentUrl: page.url() }); if (contactUrl) { await page.goto(contactUrl, { waitUntil: "domcontentloaded" }).catch(() => {}); await wait(1400); await maybeSwitchPage(); log.push({ name: "goto contact url", ok: true, url: page.url(), ts: Date.now() }); logEvt("contact.goto_contact_url.done", { u ...[truncated 2864 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pass every DOM-derived URL through the same strict Amazon URL validator used for direct navigation. 2. Validate both hostname and scheme before calling `page.goto`. 3. Validate the current URL after every navigation, click, popup, and redirect. 4. Change `isContactLikeUrl` to require both an approved origin and an approved path. 5. Filter `context.pages()` by strict origin before selecting a new page. 6. Close or ignore untrusted popups rather than bringing them to the foreground. 7. Before typing or sending a message, perform a final origin check. 8. Consider restricting browser requests through Playwright routing so top-level navigation outside approved origins is blocked. Example: ```javascript function isTrustedContactUrl(raw) { try { const url = new URL(String(raw)); if (!isTrustedAmazonUrl(url.toString())) return false; return /\/gp\/help\/contact|\/messaging|\/message-us|\/contact-us/i.test( url.pathname ); } catch { return false; } } const findContactUrl = async (page) => { const candidate = await page.evaluate(() => { const links = Array.from(document.querySelectorAll("a[href]")); const target = links.find((a) => /\/gp\/help\/contact|contact-us|messaging/i.test( String(a.getAttribute("href") || "") ) ); return target ? target.href : null; }); return candidate && isTrustedContactUrl(candidate) ? candidate : null; }; ``` Before message entry: ```javascript if (!isTrustedContactUrl(page.url())) { throw new Error("untrusted_contact_origin"); } ``` ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
skills/_easybuy_browser_runtime.js:117
Finding
Untrusted Input Controls Browser Executable and Persistent Profile Paths<![CDATA[ ## Vulnerability Details **File Location**: `skills/_easybuy_browser_runtime.js`, lines 117-134 and 1322-1337 **Vulnerability Type**: Missing validation of security-sensitive browser configuration **Risk Level**: High ### Vulnerable Code The browser launcher directly consumes caller-controlled path values: ```javascript async function launchContext(options = {}) { const headless = options.headless !== false; const slowMo = Number(options.slowMo || 0); const timeout = Number(options.timeoutMs || 45000); const userDataDir = path.resolve(options.userDataDir || path.join(ROOT, ".browser-profile")); ensureDir(userDataDir); const launchOpts = { headless, slowMo, viewport: { width: 1400, height: 900 } }; if (options.executablePath) { launchOpts.executablePath = String(options.executablePath); } else { launchOpts.channel = options.channel || "chrome"; } const context = await chromium.launchPersistentContext(userDataDir, launchOpts); context.setDefaultTimeout(timeout); let page = context.pages()[0]; if (!page) page = await context.newPage(); return { context, page }; } ``` `runSkill` forwards the `browser` object without schema enforcement: ```javascript async function runSkill(skillName, inputText) { const args = safeJsonParse(inputText); const spec = loadSkillSpec(skillName); const nonBrowser = nonBrowserSkill(skillName, args); if (nonBrowser) return JSON.stringify(nonBrowser); const browserOptions = (args.browser && typeof args.browser === "object") ? args.browser : {}; const keepOpen = browserOptions.keepOpen === true; const debug = browserOptions.debug !== false; const logEvt = createLogger(debug, `runSkill:${skillName}`); logEvt("start", { keepOpen, browser: compact(browserOptions), input: compact(args) }); const launched = await launchContext(browserOptions); ``` ### Technical Analysis Generated skill specifications define input schemas, but `runSkill` and `runFullFlow` l ...[truncated 2995 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not accept `executablePath`, `channel`, or `userDataDir` from ordinary Skill input. 2. Configure the browser executable exclusively through trusted deployment configuration. 3. Use a fixed, application-owned profile directory. 4. Resolve the profile path and verify that it remains beneath a fixed root. 5. Validate every Skill input against its declared schema before processing it. 6. Set `additionalProperties: false` at every schema level, including nested browser options. 7. Run the browser under a sandboxed, low-privilege operating-system account. 8. Default to closing the browser context rather than leaving persistent sessions open. 9. Consider using an ephemeral profile unless persistence is strictly necessary. Example containment: ```javascript const PROFILE_ROOT = path.resolve(ROOT, ".browser-profiles"); const FIXED_PROFILE = path.join(PROFILE_ROOT, "default"); async function launchContext(options = {}) { const allowedOptions = { headless: options.headless !== false, slowMo: Math.max(0, Math.min(Number(options.slowMo || 0), 1000)), timeoutMs: Math.max(1000, Math.min(Number(options.timeoutMs || 45000), 120000)) }; ensureDir(FIXED_PROFILE); const context = await chromium.launchPersistentContext(FIXED_PROFILE, { headless: allowedOptions.headless, slowMo: allowedOptions.slowMo, viewport: { width: 1400, height: 900 }, channel: "chrome" }); context.setDefaultTimeout(allowedOptions.timeoutMs); return { context, page: context.pages()[0] || await context.newPage() }; } ``` If a configurable profile name is required, accept only a simple identifier and enforce containment: ```javascript const candidate = path.resolve(PROFILE_ROOT, validatedProfileName); if (!candidate.startsWith(PROFILE_ROOT + path.sep)) { throw new Error("profile_path_not_allowed"); } ``` ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (57)

Context-Inappropriate Capability

High
Confidence
98% confidence
Finding
runFullFlow automates opening orders, selecting an order, traversing Amazon contact workflows, typing a message, and conditionally sending it. This is an end-to-end transactional workflow operating in the user's live account session, so misuse could cause unauthorized seller contact, privacy leakage in messages, and hard-to-detect account actions.

Hidden Instructions

High
Category
Prompt Injection
Content
This wrapper proxies EasyBuy skill \"price_alert_manager\".

Input:
- Prefer a JSON object string matching dist/skills/price_alert_manager.json input_schema.
Confidence
60% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Hidden Instructions

High
Category
Prompt Injection
Content
This wrapper proxies EasyBuy skill \"price_alert_manager\".

Input:
- Prefer a JSON object string matching dist/skills/price_alert_manager.json input_schema.
Confidence
60% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Hidden Instructions

High
Category
Prompt Injection
Content
This wrapper proxies EasyBuy skill \"price_alert_manager\".

Input:
- Prefer a JSON object string matching dist/skills/price_alert_manager.json input_schema.
Confidence
60% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Hidden Instructions

High
Category
Prompt Injection
Content
This wrapper proxies EasyBuy skill \"price_alert_manager\".

Input:
- Prefer a JSON object string matching dist/skills/price_alert_manager.json input_schema.
Confidence
60% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Hidden Instructions

High
Category
Prompt Injection
Content
This wrapper proxies EasyBuy skill \"price_alert_manager\".

Input:
- Prefer a JSON object string matching dist/skills/price_alert_manager.json input_schema.
Confidence
60% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Hidden Instructions

High
Category
Prompt Injection
Content
This wrapper proxies EasyBuy skill \"price_alert_manager\".

Input:
- Prefer a JSON object string matching dist/skills/price_alert_manager.json input_schema.
Confidence
60% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Hidden Instructions

High
Category
Prompt Injection
Content
This wrapper proxies EasyBuy skill \"price_alert_manager\".

Input:
- Prefer a JSON object string matching dist/skills/price_alert_manager.json input_schema.
Confidence
60% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Hidden Instructions

High
Category
Prompt Injection
Content
This wrapper proxies EasyBuy skill \"price_alert_manager\".

Input:
- Prefer a JSON object string matching dist/skills/price_alert_manager.json input_schema.
Confidence
60% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Hidden Instructions

High
Category
Prompt Injection
Content
This wrapper proxies EasyBuy skill \"price_alert_manager\".

Input:
- Prefer a JSON object string matching dist/skills/price_alert_manager.json input_schema.
Confidence
60% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Hidden Instructions

High
Category
Prompt Injection
Content
This wrapper proxies EasyBuy skill \"price_alert_manager\".

Input:
- Prefer a JSON object string matching dist/skills/price_alert_manager.json input_schema.
Confidence
60% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Hidden Instructions

High
Category
Prompt Injection
Content
This wrapper proxies EasyBuy skill \"price_alert_manager\".

Input:
- Prefer a JSON object string matching dist/skills/price_alert_manager.json input_schema.
Confidence
60% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Hidden Instructions

High
Category
Prompt Injection
Content
This wrapper proxies EasyBuy skill \"price_alert_manager\".

Input:
- Prefer a JSON object string matching dist/skills/price_alert_manager.json input_schema.
Confidence
60% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Hidden Instructions

High
Category
Prompt Injection
Content
This wrapper proxies EasyBuy skill \"price_alert_manager\".

Input:
- Prefer a JSON object string matching dist/skills/price_alert_manager.json input_schema.
Confidence
60% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Hidden Instructions

High
Category
Prompt Injection
Content
This wrapper proxies EasyBuy skill \"price_alert_manager\".

Input:
- Prefer a JSON object string matching dist/skills/price_alert_manager.json input_schema.
Confidence
60% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Hidden Instructions

High
Category
Prompt Injection
Content
This wrapper proxies EasyBuy skill \"price_alert_manager\".

Input:
- Prefer a JSON object string matching dist/skills/price_alert_manager.json input_schema.
Confidence
60% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Rp1

Medium
Category
MCP Rug Pull
Confidence
91% confidence
Finding
The README instructs users to run `npx playwright install chromium` without pinning the Playwright package version. `npx` may resolve and execute whatever version is available at install time, which creates a supply-chain risk and can lead to unexpected code execution or behavior changes if a compromised or incompatible package version is fetched.

Context-Inappropriate Capability

Medium
Confidence
91% confidence
Finding
The README claims an after-sales workflow purpose, but the included skills extend into broader scraping, monitoring, price checking, review scraping, and case exporting capabilities. This scope expansion increases the attack surface and creates a mismatch between stated purpose and actual data-handling behavior, which can hide higher-risk collection or automation functions from reviewers and operators.

Rp1

Medium
Category
MCP Rug Pull
Confidence
92% confidence
Finding
The skill instructs users to run `npx playwright`, which resolves and executes a package from the registry without pinning an exact version. This creates a supply-chain risk: a newer compromised release or unexpected dependency change could be pulled at install time and executed in the user's environment. In this skill's context, that risk is meaningful because the package is required to enable browser automation over Amazon pages, so users are likely to follow the setup instructions directly.

Vague Triggers

Medium
Confidence
88% confidence
Finding
The manifest describes a scraper for Amazon orders and exposes inputs like a generic rootSelector plus a note that it can open the first order details link, but it does not define when the skill is allowed to run or constrain it to a verified Amazon orders context. In an agent setting, broad activation semantics can cause the skill to be invoked on unintended pages or with attacker-influenced selectors, leading to collection of sensitive purchase history or navigation to pages the user did not clearly authorize.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The description says the skill extracts order cards but omits the materially different behavior that it may open the first order details page when openFirstDetails is true. That hidden navigation can surprise users and agents, potentially exposing more detailed order information than expected or causing unintended interaction with a sensitive account page.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
This skill is designed to collect screenshots and DOM snippets, both of which can capture sensitive information such as personal data, session content, hidden UI state, or internal application details. Because the description provides no warning or usage constraint, users and downstream agents may invoke it without understanding the privacy and data-handling risk, increasing the chance of inadvertent sensitive data collection.

Whitespace Padding

Medium
Category
Prompt Injection
Content
"items":  {
                                                                         "type":  "object",
                                                                         "properties":  {
                                                                                            "selector":  {
                                                                                                             "type":  "string"
                                                                                                         },
                                                                                            "value":  {
Confidence
70% confidence
Finding
Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.

Whitespace Padding

Medium
Category
Prompt Injection
Content
"items":  {
                                                                         "type":  "object",
                                                                         "properties":  {
                                                                                            "selector":  {
                                                                                                             "type":  "string"
                                                                                                         },
                                                                                            "value":  {
Confidence
70% confidence
Finding
Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.

Whitespace Padding

Medium
Category
Prompt Injection
Content
"items":  {
                                                                         "type":  "object",
                                                                         "properties":  {
                                                                                            "selector":  {
                                                                                                             "type":  "string"
                                                                                                         },
                                                                                            "value":  {
Confidence
70% confidence
Finding
Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.

Static analysis

No suspicious patterns detected.