Back to skill

Security audit

Amazon 特性利益点表达

Security checks for vulnerabilities and agentic risk

Overview

The skill is a real Amazon review-analysis integration, but it can spend account credits, change account approval settings, and run broader workflows than its narrow feature-benefit description suggests.

Install only if you are comfortable connecting an ARI account and letting the skill manage review-analysis workflows. Before using it, set auto-confirm to always ask if you do not want credits spent automatically, verify the Amazon site and ASIN before paid work, avoid broad requests that could trigger non-feature-benefit workflows, and use safe export paths that do not point at existing configuration or important files.

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

Warning
Location
scripts/ari.py:1171
Finding
Specialized Workflow Restrictions Can Be Overridden Through Command-Line Arguments<![CDATA[ ## Vulnerability Details **File Location**: `scripts/ari.py:1171-1175` and `scripts/ari.py:1654-1655` **Vulnerability Type**: Specialized authorization and least-privilege boundary bypass **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 会内置固定值。") ``` The corresponding command-line options are exposed here: ```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 The specialized Skill declares a fixed `listing/benefits` workflow in `skill-defaults.json` and states that callers must not change the workflow or focus. The implementation does not enforce that boundary. In `operation_payload()`, caller-controlled `args.workflow` and `args.focus` take precedence over the packaged defaults. The specialized CLI also explicitly exposes `--workflow` and `--focus`. Consequently, the supposedly immutable specialization values can be replaced at runtime. The subsequent capability check limits execution to workflow/focus combinations supported by the remote account, so this does not grant arbitrary server permissions. It nevertheless bypasses the Skill-level least-privilege boundary and may allow other account-enabled operational analyses or paid workflows to be invoked through a Skill advertised as being restricted to feature-to-bene ...[truncated 1586 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove `--workflow` and `--focus` from specialized builds. 2. Always load the workflow and focus from `skill-defaults.json`: ```python workflow = str(defaults.get("workflow") or "").strip() focus = str(defaults.get("focus") or "").strip() ``` 3. Reject runtime overrides explicitly, even if the parser is later modified: ```python if getattr(args, "workflow", None) or getattr(args, "focus", None): return None, error_obj( "ARI_FIXED_WORKFLOW_OVERRIDE", 403, "This specialized Skill does not permit workflow or focus overrides." ) ``` 4. Assert immediately before both quote and run requests that the payload exactly matches the packaged fixed values. 5. Have the server bind specialized Skill channels to an allowed workflow/focus pair instead of trusting client-supplied values. 6. Include the fixed workflow and focus in a server-verifiable specialization identifier, and reject mismatches server-side. 7. Add regression tests confirming that alternative workflow or focus values cannot reach either the quote or run endpoint. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/ari.py:1444
Finding
Export Destination Allows Arbitrary File Truncation and Symlink Following<![CDATA[ ## Vulnerability Details **File Location**: `scripts/ari.py:1444-1475` and `scripts/ari.py:1929` **Vulnerability Type**: Unrestricted file write, unsafe overwrite, and symlink following **Risk Level**: Medium ### Vulnerable Code ```python def request_download(path, params, dest): """下载非 JSON 响应(CSV / HTML / Markdown)到本地文件。 服务端在计划限制、参数错误等情况下仍返回 JSON 错误信封——先看 Content-Type, JSON 一律按信封透传,不落盘。CSV 流式导出中途出错时响应头已发出,服务端只能 在文件末尾追加「# export error:」注释行,这里嗅探出来转成显式错误。 """ query = {"method": "GET", "path": path, "params": {k: v for k, v in (params or {}).items() if v not in (None, "")}, "payload": None} url = base_url() + path if query["params"]: url += "?" + urllib.parse.urlencode(query["params"], doseq=True) 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() if "application/json" in ctype: out = json.loads(body.decode("utf-8", errors="replace")) if isinstance(out, dict): out["_query"] = query return out tail = body[-300:].decode("utf-8", errors="replace") if "# export error:" in tail: return error_obj("ARI_EXPORT_ERROR", 200, tail.split("# export error:", 1)[1].strip(), "导出中途失败,文件不完整,未落盘。", query) with open(dest, "wb") as fh: fh.write(body) ``` The destination is directly caller-controlled: ```python p.add_argument("--out", help="输出文件路径,默认当前目录自动命名") ``` ### Technical Analysis The `--out` value is passed directly to `open(dest, "wb")`. Opening a path in `wb` mode truncates ...[truncated 2454 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Default all exports to a dedicated directory such as `~/ARI/exports`. 2. Canonicalize the requested destination and verify that it remains within the approved directory. 3. Reject symbolic links in every destination path component. 4. Create new files with exclusive and no-follow semantics where supported: ```python flags = os.O_WRONLY | os.O_CREAT | os.O_EXCL if hasattr(os, "O_NOFOLLOW"): flags |= os.O_NOFOLLOW fd = os.open(dest, flags, 0o600) ``` 5. Refuse to overwrite existing files by default. Require a separate explicit `--overwrite` option and user confirmation if overwriting is necessary. 6. Write the response to a securely created temporary file in the same destination directory, flush and validate it, and then use an atomic replacement only after authorization. 7. Validate the expected content type and file extension before writing. 8. Apply reasonable response-size limits to prevent unexpectedly large exports from exhausting memory or disk space. 9. Add tests covering absolute paths, parent-directory traversal, existing files, symbolic links, broken symbolic links, and concurrent destination creation. ]]>
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • 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 (19)

Lp3

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding
The skill declares no explicit permissions, yet the instructions direct use of shell execution, network/API access, environment variable secrets, and local file writes. This mismatch weakens least-privilege controls and user visibility, making it easier for the skill to perform sensitive actions without clear permission gating.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The documented purpose is narrowly framed as feature-to-benefit evidence mapping, but the skill actually authorizes a much broader operational surface: paid report generation, monitoring setup, competitor management, exports, key setup, and account/billing interactions. This misleading scope can cause users or orchestrators to invoke a high-risk operational skill under the assumption that it is a limited analysis-only tool.

Vague Triggers

Medium
Confidence
83% confidence
Finding
The natural-language trigger is broad enough to match ordinary review-analysis requests, while the skill also contains instructions to run external commands and potentially paid workflows. Overbroad activation increases the chance of unintended invocation and accidental execution of networked or billable operations based on casual user phrasing.

Natural-Language Policy Violations

Medium
Confidence
90% confidence
Finding
The documentation states that if the user does not specify a site, the skill will default to the US marketplace. In a commerce and paid-analysis context, implicit geographic selection can cause the skill to act on the wrong marketplace, producing misleading analysis, querying the wrong product corpus, or consuming credits under the wrong assumptions without clear user intent.

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
94% confidence
Finding
This section instructs the agent to run `voc` by default, and to accept server-side `autoConfirmed: true` as sufficient to generate paid output without obtaining a fresh user confirmation in-session. That creates a path for autonomous execution of billable external actions, reducing meaningful user consent and increasing the chance of unwanted charges or data collection.

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
92% confidence
Finding
The workflow allows execution of `voc ... --confirm` after minimal confirmation handling and notes that the command may automatically perform collection, waiting, generation, and archival. Bundling multiple external and billable side effects behind one confirmation increases the risk of overbroad consent and unintended downstream actions.

Autonomous Decision Making

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

**确认与扣点**
- 报价返回 `autoConfirm: true` 时直接生成,不要再问「要不要」。生成后一句话交代:本次扣了多少、
  还剩几次免确认(或「免费版小额不问」)。策略由服务端决定:免费版小额不问;付费版前几次不问,之后先问。
- 用户说「以后别问了 / 50 以内直接做」→ 运行 `autoconfirm 50`;说「以后每次先问我」→ `autoconfirm off`;
  说「恢复默认」→ `autoconfirm default`。这是唯一需要你代用户设置的东西,设完复述一句当前规则。
Confidence
95% confidence
Finding
The skill explicitly says that when `autoConfirm: true` is returned, it should generate immediately and not ask the user again. This is dangerous because it normalizes autonomous spending or external action based on service-side policy rather than current user intent, undermining informed consent.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
**确认与扣点**
- 报价返回 `autoConfirm: true` 时直接生成,不要再问「要不要」。生成后一句话交代:本次扣了多少、
  还剩几次免确认(或「免费版小额不问」)。策略由服务端决定:免费版小额不问;付费版前几次不问,之后先问。
- 用户说「以后别问了 / 50 以内直接做」→ 运行 `autoconfirm 50`;说「以后每次先问我」→ `autoconfirm off`;
  说「恢复默认」→ `autoconfirm default`。这是唯一需要你代用户设置的东西,设完复述一句当前规则。
- 报价需要确认时,只说两个数:这次多少积点、余额多少,然后等用户一个「好」。采集是**固定单价**:直接说「15 积点/页 × 3 页 = 45 积点」,不要说成「预计 / 最多」——价格不会浮动;商品评论不够这么多页时只收实际采到的页数,差额自动退回(`pricingNote` 已写好这句)。不要罗列参数。
Confidence
90% confidence
Finding
The same line also permits `autoconfirm off/default` policy changes through natural-language interpretation, which means the agent can mutate account-level safety settings. Persistent control-plane changes are more sensitive than a one-time action and should not be inferred loosely from dialogue.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
**确认与扣点**
- 报价返回 `autoConfirm: true` 时直接生成,不要再问「要不要」。生成后一句话交代:本次扣了多少、
  还剩几次免确认(或「免费版小额不问」)。策略由服务端决定:免费版小额不问;付费版前几次不问,之后先问。
- 用户说「以后别问了 / 50 以内直接做」→ 运行 `autoconfirm 50`;说「以后每次先问我」→ `autoconfirm off`;
  说「恢复默认」→ `autoconfirm default`。这是唯一需要你代用户设置的东西,设完复述一句当前规则。
- 报价需要确认时,只说两个数:这次多少积点、余额多少,然后等用户一个「好」。采集是**固定单价**:直接说「15 积点/页 × 3 页 = 45 积点」,不要说成「预计 / 最多」——价格不会浮动;商品评论不够这么多页时只收实际采到的页数,差额自动退回(`pricingNote` 已写好这句)。不要罗列参数。
Confidence
90% confidence
Finding
The same line also permits `autoconfirm off/default` policy changes through natural-language interpretation, which means the agent can mutate account-level safety settings. Persistent control-plane changes are more sensitive than a one-time action and should not be inferred loosely from dialogue.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
voc B0... --site amz_us 是完整 VOC 的入口:先取得报价,已有足够评论时使用当前分析价格;
数据不足时合并采集与分析费用。符合服务端免确认规则且总额不超过上限时可能直接生成,
返回 autoConfirmed。否则返回 confirmationRequired,取得用户同意后追加 --confirm,
自动完成必要采集、等待、分析和归档。只读询价应使用 quote / collect 报价入口。

`collect --asin B0... --site amz_us --pages 3` 只返回报价;确认后追加
Confidence
77% confidence
Finding
This section documents that `voc` may directly generate chargeable work and complete collection, waiting, analysis, and archiving when server-side auto-confirm rules match. In an agent skill context, that creates a real risk of the agent initiating paid actions without contemporaneous user approval, especially because the file normalizes automatic progression from quote to execution under certain conditions.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
先调用 `quote --type ...`。报价字段:
`type, basePrice, price, sampledReviews, totalReviews, balance, sufficient`,
另有(1.4.5):`autoConfirm`(true = 服务端首次体验策略允许免确认直接生成)、
`autoConfirmMaxCredits`(免确认单次上限,采集 + 报告合计)、`autoConfirmRemaining`(还剩几次)、
`autoConfirmNote`、`webUrl`(该产品的网页报告页)。`sampleCap` / `degraded` 表示 Free 样本封顶与轻量模型。
`voc` / `analyze` 在 autoConfirm 命中时会直接生成,返回 `autoConfirmed: true` 与 `autoConfirmNote`,
Confidence
79% confidence
Finding
This line introduces quote fields including `autoConfirm`, which signals that subsequent analysis may proceed without a fresh user confirmation. In an autonomous agent setting, exposing and potentially honoring this flag can lead to unauthorized spend or unintended execution if the skill interprets eligibility as permission.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
先调用 `quote --type ...`。报价字段:
`type, basePrice, price, sampledReviews, totalReviews, balance, sufficient`,
另有(1.4.5):`autoConfirm`(true = 服务端首次体验策略允许免确认直接生成)、
`autoConfirmMaxCredits`(免确认单次上限,采集 + 报告合计)、`autoConfirmRemaining`(还剩几次)、
`autoConfirmNote`、`webUrl`(该产品的网页报告页)。`sampleCap` / `degraded` 表示 Free 样本封顶与轻量模型。
`voc` / `analyze` 在 autoConfirm 命中时会直接生成,返回 `autoConfirmed: true` 与 `autoConfirmNote`,
并附 `web.report` / `web.product` 网页链接。
Confidence
79% confidence
Finding
This is a duplicate hit on the same line, but the underlying issue is the same: the reference endorses metadata that may be used to automate paid execution. In isolation it's documentation, yet in the context of an agent skill handling API keys and remote operations, it represents a meaningful unsafe pattern if followed naively.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
先调用 `quote --type ...`。报价字段:
`type, basePrice, price, sampledReviews, totalReviews, balance, sufficient`,
另有(1.4.5):`autoConfirm`(true = 服务端首次体验策略允许免确认直接生成)、
`autoConfirmMaxCredits`(免确认单次上限,采集 + 报告合计)、`autoConfirmRemaining`(还剩几次)、
`autoConfirmNote`、`webUrl`(该产品的网页报告页)。`sampleCap` / `degraded` 表示 Free 样本封顶与轻量模型。
`voc` / `analyze` 在 autoConfirm 命中时会直接生成,返回 `autoConfirmed: true` 与 `autoConfirmNote`,
并附 `web.report` / `web.product` 网页链接。
Confidence
79% confidence
Finding
This is a duplicate hit on the same line, but the underlying issue is the same: the reference endorses metadata that may be used to automate paid execution. In isolation it's documentation, yet in the context of an agent skill handling API keys and remote operations, it represents a meaningful unsafe pattern if followed naively.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
`type, basePrice, price, sampledReviews, totalReviews, balance, sufficient`,
另有(1.4.5):`autoConfirm`(true = 服务端首次体验策略允许免确认直接生成)、
`autoConfirmMaxCredits`(免确认单次上限,采集 + 报告合计)、`autoConfirmRemaining`(还剩几次)、
`autoConfirmNote`、`webUrl`(该产品的网页报告页)。`sampleCap` / `degraded` 表示 Free 样本封顶与轻量模型。
`voc` / `analyze` 在 autoConfirm 命中时会直接生成,返回 `autoConfirmed: true` 与 `autoConfirmNote`,
并附 `web.report` / `web.product` 网页链接。
Confidence
82% confidence
Finding
This line explicitly states that `voc` / `analyze` will directly generate when `autoConfirm` is hit and return `autoConfirmed: true`. In an AI agent workflow, that is a concrete autonomous-action risk because a chargeable remote operation may be triggered without a human's fresh authorization, potentially consuming credits or creating archived reports unexpectedly.

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
The analysis flow can set confirm=True automatically when the server returns autoConfirm and sufficient, causing a paid analysis to run without an explicit per-operation user confirmation. In an agent setting, this weakens the expected consent boundary for billable actions and could let upstream policy or server-side toggles trigger unintended charges.

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 branch records that the operation was auto-confirmed after the code decides to bypass interactive confirmation. In a tool callable by agents, that means billable work may execute from ambient policy rather than fresh user intent, increasing risk of unauthorized spending.

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 decision point trusts q_data.autoConfirm from the remote service to determine whether to proceed with a chargeable action. Delegating consent semantics to server response data is dangerous in agent workflows because it blurs who authorized the spend and when.

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 workflow can automatically combine collection and analysis into a billable end-to-end operation when the server advertises autoConfirm and the total fits within a threshold. Because collection plus analysis may consume credits without a fresh explicit approval, an agent could trigger real charges under reduced-friction logic rather than deliberate consent.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
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"))
                      and sufficient and total_credits <= auto_max)
    if not args.confirm and not auto_confirmed:
Confidence
94% confidence
Finding
This condition uses remote autoConfirm state plus sufficiency checks to decide whether to skip the normal quote-only path. In security-sensitive agent contexts, cost-incurring actions should not depend solely on server hints and ambient preferences because that undermines user-in-the-loop billing control.

Static analysis

No suspicious patterns detected.