Back to skill

Security audit

Amazon 市场进入对照简报

Security checks for vulnerabilities and agentic risk

Overview

The skill is not clearly malicious, but it gives the agent broader ARI account powers than the advertised market-entry brief, including spending credits, changing monitoring/settings, and exporting data.

Review this skill carefully before installing. It requires an ARI API key and can affect your ARI account, credits, monitoring state, and local exports. Use it only if you are comfortable with server-side auto-confirm billing rules, and prefer turning auto-confirm off or using quote-only flows when you want per-action approval.

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

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
scripts/ari.py:1168
Finding
Specialized Workflow Boundary Can Be Overridden## Vulnerability Details **File Location**: `scripts/ari.py:1168-1170` and `scripts/ari.py:1643-1646` **Vulnerability Type**: Least-privilege and scope-enforcement failure **Risk Level**: Medium ### Vulnerable Code ```python def operation_payload(args): defaults = operation_defaults() workflow = (getattr(args, "workflow", None) or defaults.get("workflow") or "").strip() focus = (getattr(args, "focus", None) or defaults.get("focus") or "").strip() if not workflow or not focus: return None, error_obj( "ARI_VALIDATION_ERROR", 0, "运营工作流缺少 workflow/focus", "通用 Skill 请显式传 --workflow 和 --focus;专属 Skill 会内置固定值。") ``` ```python def add_operation_args(parser, confirm=False): parser.add_argument("--asin", required=True) parser.add_argument("--site", default="amz_us", choices=SITES) parser.add_argument("--workflow") parser.add_argument("--focus") parser.add_argument("--competitor") parser.add_argument("--request-id", default="") ``` ### Technical Analysis This package declares a specialized, immutable operations contract of `page_compare/entry`. The contract is documented in `SKILL.md:235-242` and `references/operation-workflow.md:3`, which state that the workflow and focus must come from `skill-defaults.json` and must not be changed to another focus or arbitrary workflow. The implementation does not enforce that boundary. In `operation_payload`, command-line values take precedence over the packaged defaults: ```python getattr(args, "workflow", None) or defaults.get("workflow") ``` The same precedence applies to `focus`. Because both values are exposed as command-line arguments, a caller can replace the specialized values before the request is submitted. The subsequent capability check only verifies that the selected workflow and focus are enabled for the ARI account. It does not verify that they are authorized for this particular s ...[truncated 2182 chars]
Remediation
## Remediation Suggestions 1. Remove `--workflow` and `--focus` from specialized builds. The specialized CLI should load these values exclusively from `skill-defaults.json`. 2. If the arguments must remain for a shared implementation, reject any values that differ from the packaged contract: ```python defaults = operation_defaults() fixed_workflow = str(defaults.get("workflow") or "").strip() fixed_focus = str(defaults.get("focus") or "").strip() supplied_workflow = str(getattr(args, "workflow", None) or "").strip() supplied_focus = str(getattr(args, "focus", None) or "").strip() if supplied_workflow and supplied_workflow != fixed_workflow: return None, error_obj( "ARI_SPECIALIZED_WORKFLOW_OVERRIDE_BLOCKED", 403, "This specialized Skill does not permit workflow overrides." ) if supplied_focus and supplied_focus != fixed_focus: return None, error_obj( "ARI_SPECIALIZED_FOCUS_OVERRIDE_BLOCKED", 403, "This specialized Skill does not permit focus overrides." ) ``` 3. Distinguish specialized packages from a generic CLI using an explicit immutable build flag or package type. Permit workflow/focus arguments only in verified generic builds. 4. Include the package slug, channel, fixed workflow, fixed focus, and expected output template in quote and execution requests. Enforce the same contract server-side so a modified local client cannot broaden the package scope. 5. Validate that the quote response and execution request retain the exact fixed workflow, focus, request ID, and output template. Abort if any field differs. 6. Add regression tests confirming that: - Omitted values resolve to `page_compare/entry`. - Alternate `--workflow` values are rejected. - Alternate `--focus` values are rejected. - Quote and run requests use identical fixed contract fields. - Account-level ...[truncated 83 chars]
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (27)

Tainted flow: 'req' from os.environ.get (line 1459, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Content
headers = {"Authorization": "Bearer " + require_key(), "User-Agent": user_agent()}
    try:
        req = urllib.request.Request(url, headers=headers, method="GET")
        with urllib.request.urlopen(req, timeout=TIMEOUT_SEC) as resp:
            note_release(resp.headers)
            ctype = resp.headers.get("Content-Type", "")
            body = resp.read()
Confidence
62% confidence
Finding
request_download() sends authenticated requests and writes server-controlled response bodies directly to an attacker-chosen filesystem path via --out. While the custom base is guarded, a user or wrapper invoking the skill with a sensitive path can cause arbitrary file overwrite in the current user's context, which is a real local integrity risk for an API-driven agent skill.

Lp3

Medium
Category
MCP Least Privilege
Confidence
96% confidence
Finding
The skill invokes a local CLI, performs network access to an external API, stores API credentials locally, and can export files, yet no explicit permissions or capability boundaries are declared. This creates an overly broad trust surface where a caller may not understand that the skill can access environment variables, write local state, and trigger external actions with billing side effects.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The published description frames the skill as a narrow pre-entry research tool, but the body grants much broader powers: account configuration, paid collection, monitoring management, competitor management, exports, alerts handling, and other operational workflows. This mismatch can mislead users and hosting platforms into authorizing a tool with materially greater reach than expected, increasing the risk of unauthorized state changes, spending, and data export.

Description-Behavior Mismatch

High
Confidence
97% confidence
Finding
The skill metadata describes a narrow pre-entry market-entry brief, but the CLI exposes broad ongoing monitoring, exports, leaderboard analytics, workbench actions, operations workflows, and account state mutation. In an agent setting, this scope mismatch is dangerous because a caller expecting read-only pre-entry research may unknowingly trigger persistent monitoring, paid analytics, or operational changes outside the declared trust boundary.

Context-Inappropriate Capability

High
Confidence
96% confidence
Finding
The product-operations quote/run/status workflow can execute server-side operational analyses beyond the manifest's stated purpose of page-difference and review-evidence research. This materially expands what an agent can do with the user's account and credits, creating a hidden capability escalation if the skill is invoked under the assumption of limited research-only behavior.

Context-Inappropriate Capability

Medium
Confidence
94% confidence
Finding
Watch creation, pause/resume, delete, digest, and events establish persistent monitoring relationships and background tracking unrelated to a one-time market-entry brief. In an agent context, this can silently create durable account state and recurring data collection that exceeds user expectations and the declared scope.

Context-Inappropriate Capability

Medium
Confidence
94% confidence
Finding
These commands modify account and product state by changing schedules, adding/removing competitors, marking alerts read, and changing workbench statuses. Such write actions are out of scope for pre-entry research and can alter downstream monitoring, dashboards, or team workflows without the user realizing this skill is not read-only.

Description-Behavior Mismatch

Medium
Confidence
89% confidence
Finding
Benchmark and leaderboard features move beyond page-difference and user-question research into broader category and commercial intelligence, which the manifest explicitly says is out of scope. This mismatch can mislead users and orchestrators about the type of analysis being performed and the charges or business sensitivity involved.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
1. 运行 `check`,确认账户、邮箱验证状态和可用积点。
2. 用户要 VOC / 评论分析报告时,默认运行 `voc <ASIN> --site <站点>`。
   **返回里有 `autoConfirmed: true` 就说明已经直接生成了**(1.4.5 起:服务端对前几次小额
   付费操作免确认,用户先拿到结果再谈钱),此时把报告讲给用户,并转述 `autoConfirmNote`
   (本次扣了多少、还剩几次免确认、之后会先问)。**不要在拿到结果后再补问「要不要生成」。**
3. 返回 `confirmationRequired: true` 才需要用户确认:报出 `totalCredits` 与余额,
Confidence
95% confidence
Finding
This flow permits paid report generation to proceed automatically when the server marks the request as auto-confirmed, and instructs the agent not to seek explicit approval first. Even if the backend allows it, the skill is authorizing billable side effects based on service policy rather than fresh user consent in-session, which can cause unexpected charges.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
1. 运行 `check`,确认账户、邮箱验证状态和可用积点。
2. 用户要 VOC / 评论分析报告时,默认运行 `voc <ASIN> --site <站点>`。
   **返回里有 `autoConfirmed: true` 就说明已经直接生成了**(1.4.5 起:服务端对前几次小额
   付费操作免确认,用户先拿到结果再谈钱),此时把报告讲给用户,并转述 `autoConfirmNote`
   (本次扣了多少、还剩几次免确认、之后会先问)。**不要在拿到结果后再补问「要不要生成」。**
3. 返回 `confirmationRequired: true` 才需要用户确认:报出 `totalCredits` 与余额,
   用户同意后运行 `voc <ASIN> --site <站点> --confirm`。该命令会自动补齐采集、等待任务完成、
Confidence
95% confidence
Finding
The workflow defaults to running a potentially paid VOC operation before a confirmation-required response is known, meaning the initial command itself may already create a chargeable report under service-side rules. This delegates spending control to backend behavior instead of ensuring the user deliberately initiated a paid action.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
用户只说自然语言。网页是补充视图(图表、分享链接、海报),不是把人送走的地方。

**确认与扣点**
- 报价返回 `autoConfirm: true` 时直接生成,不要再问「要不要」。生成后一句话交代:本次扣了多少、
  还剩几次免确认(或「免费版小额不问」)。策略由服务端决定:免费版小额不问;付费版前几次不问,之后先问。
- 用户说「以后别问了 / 50 以内直接做」→ 运行 `autoconfirm 50`;说「以后每次先问我」→ `autoconfirm off`;
  说「恢复默认」→ `autoconfirm default`。这是唯一需要你代用户设置的东西,设完复述一句当前规则。
Confidence
94% confidence
Finding
The skill explicitly instructs the agent to generate paid outputs immediately when autoConfirm is returned, bypassing a contemporaneous approval step. This is dangerous because it normalizes autonomous spending and can surprise users who asked for analysis but did not intend to authorize charges under hidden service-side exceptions.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
**确认与扣点**
- 报价返回 `autoConfirm: true` 时直接生成,不要再问「要不要」。生成后一句话交代:本次扣了多少、
  还剩几次免确认(或「免费版小额不问」)。策略由服务端决定:免费版小额不问;付费版前几次不问,之后先问。
- 用户说「以后别问了 / 50 以内直接做」→ 运行 `autoconfirm 50`;说「以后每次先问我」→ `autoconfirm off`;
  说「恢复默认」→ `autoconfirm default`。这是唯一需要你代用户设置的东西,设完复述一句当前规则。
- 报价需要确认时,只说两个数:这次多少积点、余额多少,然后等用户一个「好」。采集是**固定单价**:直接说「15 积点/页 × 3 页 = 45 积点」,不要说成「预计 / 最多」——价格不会浮动;商品评论不够这么多页时只收实际采到的页数,差额自动退回(`pricingNote` 已写好这句)。不要罗列参数。
Confidence
93% confidence
Finding
The same instruction block authorizes the agent to disable confirmations or restore defaults through natural-language interpretation, which increases the chance of ambiguous consent leading to account policy changes. Because this setting affects future billable operations, mistakes here can have persistent financial impact.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
**确认与扣点**
- 报价返回 `autoConfirm: true` 时直接生成,不要再问「要不要」。生成后一句话交代:本次扣了多少、
  还剩几次免确认(或「免费版小额不问」)。策略由服务端决定:免费版小额不问;付费版前几次不问,之后先问。
- 用户说「以后别问了 / 50 以内直接做」→ 运行 `autoconfirm 50`;说「以后每次先问我」→ `autoconfirm off`;
  说「恢复默认」→ `autoconfirm default`。这是唯一需要你代用户设置的东西,设完复述一句当前规则。
- 报价需要确认时,只说两个数:这次多少积点、余额多少,然后等用户一个「好」。采集是**固定单价**:直接说「15 积点/页 × 3 页 = 45 积点」,不要说成「预计 / 最多」——价格不会浮动;商品评论不够这么多页时只收实际采到的页数,差额自动退回(`pricingNote` 已写好这句)。不要罗列参数。
Confidence
93% confidence
Finding
The same instruction block authorizes the agent to disable confirmations or restore defaults through natural-language interpretation, which increases the chance of ambiguous consent leading to account policy changes. Because this setting affects future billable operations, mistakes here can have persistent financial impact.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
说「恢复默认」→ `autoconfirm default`。这是唯一需要你代用户设置的东西,设完复述一句当前规则。
- 报价需要确认时,只说两个数:这次多少积点、余额多少,然后等用户一个「好」。采集是**固定单价**:直接说「15 积点/页 × 3 页 = 45 积点」,不要说成「预计 / 最多」——价格不会浮动;商品评论不够这么多页时只收实际采到的页数,差额自动退回(`pricingNote` 已写好这句)。不要罗列参数。

**新手(`check` 返回 `autoConfirm.mode` 为 `first_runs` / `free_small`,或问"然后呢")**
- 报告讲完只推一个下一步,附接口返回的成本,不写死月费用。用户同意再 `schedule --set weekly`。
- 不解释命令名,不列功能清单。用户问「还能做什么」时按他的产品状态给一条建议,不超过三句。
Confidence
86% confidence
Finding
After finishing a report, the skill tells the agent to proactively propose enabling weekly scheduled collection with a returned cost, then execute on user agreement. This is less severe than silent execution, but it still pushes an account-affecting recurring paid setting from within a research skill, increasing the chance of consent fatigue or accidental enablement.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
}


def cmd_autoconfirm(args):
    """免确认阈值:不带参数=查看;`autoconfirm 50`=50 积点以内不问;`autoconfirm off`=每次都问;`autoconfirm default`=恢复默认。"""
    value = (args.value or "").strip().lower()
    if value:
Confidence
81% confidence
Finding
The skill exposes a command to alter the user's auto-confirm threshold, which can enable future paid operations to execute without per-action confirmation. In an agent context, changing this setting is sensitive because it weakens spending safeguards beyond the immediate request and persists at the account level.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
def cmd_autoconfirm(args):
    """免确认阈值:不带参数=查看;`autoconfirm 50`=50 积点以内不问;`autoconfirm off`=每次都问;`autoconfirm default`=恢复默认。"""
    value = (args.value or "").strip().lower()
    if value:
        if value in ("off", "ask", "0"):
Confidence
81% confidence
Finding
This branch interprets user input to disable or reset confirmation protections, enabling later autonomous paid actions. The danger is not code execution but persistent reduction of approval friction for future credit-consuming operations.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
def cmd_autoconfirm(args):
    """免确认阈值:不带参数=查看;`autoconfirm 50`=50 积点以内不问;`autoconfirm off`=每次都问;`autoconfirm default`=恢复默认。"""
    value = (args.value or "").strip().lower()
    if value:
        if value in ("off", "ask", "0"):
Confidence
81% confidence
Finding
This branch interprets user input to disable or reset confirmation protections, enabling later autonomous paid actions. The danger is not code execution but persistent reduction of approval friction for future credit-consuming operations.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
def cmd_autoconfirm(args):
    """免确认阈值:不带参数=查看;`autoconfirm 50`=50 积点以内不问;`autoconfirm off`=每次都问;`autoconfirm default`=恢复默认。"""
    value = (args.value or "").strip().lower()
    if value:
        if value in ("off", "ask", "0"):
Confidence
81% confidence
Finding
This branch interprets user input to disable or reset confirmation protections, enabling later autonomous paid actions. The danger is not code execution but persistent reduction of approval friction for future credit-consuming operations.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
limit = int(value)
            except ValueError:
                emit(error_obj("ARI_BAD_ARGUMENT", 0, "参数不对",
                               "用法:autoconfirm 50(50 积点以内不问)/ autoconfirm off(每次都问)/ autoconfirm default(恢复默认)"),
                     args.compact)
                return
        out = request_json("PUT", "/api/v1/user/autoconfirm", {"limit": limit})
Confidence
84% confidence
Finding
The PUT /api/v1/user/autoconfirm call actively changes the account's spending-confirmation behavior. In a skill advertised for pre-entry research, persistent account-level spending automation is an unjustified expansion that can lead to unintended charges and reduced user control.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
limit = int(value)
            except ValueError:
                emit(error_obj("ARI_BAD_ARGUMENT", 0, "参数不对",
                               "用法:autoconfirm 50(50 积点以内不问)/ autoconfirm off(每次都问)/ autoconfirm default(恢复默认)"),
                     args.compact)
                return
        out = request_json("PUT", "/api/v1/user/autoconfirm", {"limit": limit})
Confidence
84% confidence
Finding
The PUT /api/v1/user/autoconfirm call actively changes the account's spending-confirmation behavior. In a skill advertised for pre-entry research, persistent account-level spending automation is an unjustified expansion that can lead to unintended charges and reduced user control.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
limit = int(value)
            except ValueError:
                emit(error_obj("ARI_BAD_ARGUMENT", 0, "参数不对",
                               "用法:autoconfirm 50(50 积点以内不问)/ autoconfirm off(每次都问)/ autoconfirm default(恢复默认)"),
                     args.compact)
                return
        out = request_json("PUT", "/api/v1/user/autoconfirm", {"limit": limit})
Confidence
84% confidence
Finding
The PUT /api/v1/user/autoconfirm call actively changes the account's spending-confirmation behavior. In a skill advertised for pre-entry research, persistent account-level spending automation is an unjustified expansion that can lead to unintended charges and reduced user control.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
if not ok(quote):
        return quote
    q_data = data_of(quote) or {}
    # 首次体验免确认(服务端策略 skill.autoConfirm):前几次小额直接生成,不再多问一轮。
    auto_confirmed = False
    if not confirm and q_data.get("autoConfirm") and q_data.get("sufficient"):
        confirm = True
Confidence
93% confidence
Finding
run_analysis() upgrades a quote-only invocation into a paid confirmed execution when the server returns autoConfirm and sufficient balance, even when the caller did not pass --confirm. In an agent environment, that means analysis can consume credits without a fresh explicit approval at the time of action, which weakens an important financial safety boundary.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
return quote
    q_data = data_of(quote) or {}
    # 首次体验免确认(服务端策略 skill.autoConfirm):前几次小额直接生成,不再多问一轮。
    auto_confirmed = False
    if not confirm and q_data.get("autoConfirm") and q_data.get("sufficient"):
        confirm = True
        auto_confirmed = True
Confidence
93% confidence
Finding
This line sets the local state that a non-confirmed request should proceed as confirmed. It directly enables autonomous credit consumption based on account policy rather than immediate user intent.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
q_data = data_of(quote) or {}
    # 首次体验免确认(服务端策略 skill.autoConfirm):前几次小额直接生成,不再多问一轮。
    auto_confirmed = False
    if not confirm and q_data.get("autoConfirm") and q_data.get("sufficient"):
        confirm = True
        auto_confirmed = True
    if not confirm:
Confidence
93% confidence
Finding
The conditional makes server-side autoConfirm sufficient to convert an unconfirmed request into an execution path. That is risky in a tool exposed to higher-level agents because they may expect quote-only semantics when not supplying --confirm.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
if plan is not None and plan["balance"]["note"]:
        combined_quote["siteNote"] = plan["balance"]["note"]
    combined_quote["webUrl"] = analysis_quote.get("webUrl")
    # 首次体验免确认:服务端 autoConfirm=true 且「采集 + 报告」合计不超过单次上限时,直接跑完。
    # 在聊天里多问一句「确认吗」,很多用户就不回了——先让他拿到结果。
    auto_max = int(analysis_quote.get("autoConfirmMaxCredits") or 0)
    auto_confirmed = (not args.confirm and bool(analysis_quote.get("autoConfirm"))
Confidence
94% confidence
Finding
The VOC command computes an auto-confirm path for a combined paid workflow that may include both collection and analysis, expanding the impact of autonomous execution. Because this skill can both gather data and spend credits in one step, bypassing explicit confirmation is more dangerous here than for a single read-only action.

Static analysis

No suspicious patterns detected.