Back to skill

Security audit

Amazon 竞品特性矩阵

Security checks for vulnerabilities and agentic risk

Overview

This skill connects to ARI for Amazon review and competitor analysis, but it exposes broader paid and persistent account actions than its narrow feature-matrix description suggests.

Install only if you trust this ARI integration and are comfortable with a local API key, authenticated network calls, possible credit-consuming analyses under account autoconfirm rules, and persistent monitoring or confirmation-setting changes. Keep autoconfirm set to ask every time for agent use, avoid custom ARI_BASE_URL values, and use exports only with safe output paths.

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)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/ari.py:1474
Finding
Arbitrary File Overwrite Through the Export Destination## Vulnerability Details **File Location**: `scripts/ari.py:1474-1475`, with attacker-controlled destination selection at `scripts/ari.py:1582-1597` **Vulnerability Type**: Arbitrary file overwrite and symbolic-link following **Risk Level**: Medium ### Vulnerable Code ```python with open(dest, "wb") as fh: fh.write(body) ``` The destination is derived directly from the command-line `--out` argument: ```python def cmd_export(args): if args.report_id: fmt = args.format or "md" dest = args.out or ("ari_report_%d.%s" % ( args.report_id, "html" if fmt == "html" else "md" )) emit(request_download( "/api/v1/export/reports/%d" % args.report_id, {"format": fmt}, dest ), args.compact) return if not args.asin: emit(error_obj( "ARI_VALIDATION_ERROR", 0, "An ASIN or report ID is required." ), args.compact) return dest = args.out or ("ari_reviews_%s.csv" % args.asin.upper()) emit(request_download( "/api/v1/export/reviews", {"asin": args.asin.upper(), "site": args.site}, dest ), args.compact) ``` ### Technical Analysis The `--out` argument accepts an unrestricted path and passes it to `open(dest, "wb")`. Opening a file in `wb` mode truncates an existing file before writing. The implementation does not: - Restrict output to a dedicated export directory. - Reject absolute paths or parent-directory traversal. - Check whether the destination already exists. - Reject symbolic links. - Use an exclusive or no-follow file creation mode. - Require separate confirmation before replacing an existing file. Export functionality legitimately requires local write access, but unrestricted destructive write access exceeds the minimum filesystem privileges necessary for this task. ### Attack P ...[truncated 1130 chars]
Remediation
## Remediation Suggestions 1. Create a dedicated export directory and resolve every destination relative to it. 2. Reject absolute paths, parent-directory components, and destinations whose resolved path escapes the export directory. 3. Refuse to overwrite existing files by default. 4. Require explicit user confirmation before replacing an existing export. 5. Open new files atomically with exclusive creation, such as `os.open()` with `O_WRONLY | O_CREAT | O_EXCL`. 6. Where supported, add `O_NOFOLLOW` to prevent symbolic-link traversal. 7. Validate both the parent directory and final destination after canonical path resolution. 8. Write to a securely created temporary file in the destination directory and atomically rename it after the download has been fully validated. 9. Apply conservative file permissions, such as `0600`, when exported reports may contain account or review information.

T05 · Unauthorized Access and Privilege Escalation

Note
Location
scripts/ari.py:1169
Finding
Specialized Workflow Restrictions Can Be Bypassed Through CLI Overrides## Vulnerability Details **File Location**: `scripts/ari.py:1169-1187`, with override arguments registered at `scripts/ari.py:1643-1650` **Vulnerability Type**: Specialized-scope and least-privilege bypass **Risk Level**: Low ### Vulnerable Code User-controlled values take precedence over the fixed specialized defaults: ```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() request_id = ( getattr(args, "request_id", None) or "" ).strip() or str(uuid.uuid4()) return { "requestId": request_id, "workflow": workflow, "focus": focus, "asin": args.asin.upper(), "site": args.site or defaults.get("defaultSite") or "amz_us", "competitorAsin": ( getattr(args, "competitor", None) or "" ).upper(), }, None ``` The specialized CLI also exposes the overriding arguments: ```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="") if confirm: parser.add_argument("--confirm", action="store_true") ``` ### Technical Analysis The package metadata and specialized workflow documentation define the Skill as limited to the fixed `page_compare` workflow and `features` focus. However, `operation_payload()` prioritizes command-line values over `skill-defaults.json`. The later capability check only determines whether the server and account support the selected workf ...[truncated 1676 chars]
Remediation
## Remediation Suggestions 1. Remove `--workflow` and `--focus` from the argument parser in specialized builds. 2. Always read the workflow and focus from `skill-defaults.json` for this package. 3. Reject execution when supplied arguments conflict with the fixed values rather than silently accepting or overriding them. 4. Validate the final payload against `_meta.json` or `skill-defaults.json` immediately before both quote and run requests. 5. Ensure the quote response and confirmed run use the same fixed workflow, focus, and request identifier. 6. If the codebase must support both generic and specialized distributions, introduce an explicit build mode and enforce separate parsers and policy checks for each mode. 7. Add regression tests proving that alternate workflow and focus values are rejected in the `competitor-features` package.
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • 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
Findings (35)

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
72% confidence
Finding
The export download path sends the Bearer API key to base_url(), and base_url() can be redirected by environment variables when ARI_ALLOW_CUSTOM_BASE=1 is present. In an agent or shared-shell environment, that opt-in may still be attacker-influenced, causing authenticated requests and exported data to be sent to an untrusted host.

Lp3

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding
The skill instructs use of shell, network access, environment variables, and local file writes to perform API setup and persist an ARI API key, yet it declares no permissions or trust boundaries. This creates hidden capability expansion: a caller may invoke a seemingly narrow analysis skill that can actually modify local state and exfiltrate or consume external resources.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The metadata presents this as a narrow static competitor feature matrix skill, but the body defines a broad operational agent with billing actions, data collection, scheduling, monitoring, exports, autoconfirm settings, and multiple analysis workflows. This mismatch is dangerous because users, reviewers, or policy layers may grant access based on the benign description while the actual behavior performs materially broader and potentially charge-incurring actions.

Description-Behavior Mismatch

High
Confidence
96% confidence
Finding
The skill metadata claims a static competitor feature-matrix purpose, but the code implements much broader monitoring, alerts, operational workflows, rankings, exports, and ongoing analysis. This scope mismatch is dangerous because an agent may invoke capabilities the user did not authorize, leading to surveillance, paid actions, and business-intelligence collection beyond the declared use case.

Context-Inappropriate Capability

High
Confidence
97% confidence
Finding
The generic product-operations workflow machinery accepts workflow/focus combinations and executes server-side operations unrelated to a static comparison matrix. In an agent setting, this creates an overly broad action surface that could be used to trigger unintended paid analyses or operational tasks under the cover of a narrowly described skill.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
Watch creation, recurring schedules, digests, and event retrieval add persistent monitoring behavior that is inconsistent with a static comparison tool. This increases risk of silent ongoing data collection and user surprise, especially in an agent environment where recurring actions are more sensitive than one-off reads.

Context-Inappropriate Capability

Medium
Confidence
93% confidence
Finding
Trend, benchmark, radar, leaderboard, and related analytics exceed the manifest's 'static-only' positioning and can support broader market intelligence use cases. The security issue is not code execution but capability overreach: an agent may lawfully access functions that users and reviewers would not expect from the declared skill purpose.

Vague Triggers

Medium
Confidence
86% confidence
Finding
The natural-language trigger is broad enough to capture generic review-analysis requests and then route them into this skill's much wider operational logic. Overbroad invocation increases the chance of unintended tool use, credential checks, billing-related actions, or access to external systems when the user only asked for a simple summary.

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 instruction authorizes paid report generation when the service returns autoConfirmed=true, explicitly telling the agent not to seek contemporaneous user approval. Even if the backend permits it, the skill is enabling autonomous spend and side-effectful execution based on a prior platform rule rather than an explicit action-specific consent from the user in the current interaction.

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
94% confidence
Finding
The workflow directs the agent to proceed from quote to collection and report generation with --confirm once it interprets user agreement, while also allowing automatic completion of preparatory steps. This concentrates billing and external actions behind minimal confirmation semantics and raises the risk of accidental charges or unintended data processing.

Autonomous Decision Making

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

**确认与扣点**
- 报价返回 `autoConfirm: true` 时直接生成,不要再问「要不要」。生成后一句话交代:本次扣了多少、
  还剩几次免确认(或「免费版小额不问」)。策略由服务端决定:免费版小额不问;付费版前几次不问,之后先问。
- 用户说「以后别问了 / 50 以内直接做」→ 运行 `autoconfirm 50`;说「以后每次先问我」→ `autoconfirm off`;
  说「恢复默认」→ `autoconfirm default`。这是唯一需要你代用户设置的东西,设完复述一句当前规则。
Confidence
95% confidence
Finding
The skill explicitly tells the agent to generate results immediately when autoConfirm is returned, without asking the user. This is a classic autonomous decision-making pattern for billable and externally executed actions, increasing financial and operational risk if triggered by ambiguous requests.

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 permits agent-mediated modification of spending controls using short natural-language cues like '以后别问了'. Such terse triggers are vulnerable to misinterpretation or prompt-injection through quoted text, causing persistent authorization changes the user did not truly intend.

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 permits agent-mediated modification of spending controls using short natural-language cues like '以后别问了'. Such terse triggers are vulnerable to misinterpretation or prompt-injection through quoted text, causing persistent authorization changes the user did not truly intend.

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
84% confidence
Finding
Using autoConfirm mode from check output to classify users and shape next-step recommendations increases the chance that less experienced users are funneled into additional paid or persistent actions with minimal friction. In context, the skill combines profiling of account state with proactive monetized workflow progression.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
emit(balance, args.compact)
        return
    # 免确认策略(1.4.5):告诉 agent 当前用户是「小额直接生成」还是「每次先问」
    auto = request_json("GET", "/api/v1/user/autoconfirm")
    emit({"success": True, "data": {
        "skillVersion": VERSION,
        "release": release,
Confidence
90% confidence
Finding
The skill explicitly supports an auto-confirm mode for paid operations, meaning an agent can learn that some billable actions may proceed without per-action user confirmation. In a delegated agent context, this weakens transaction consent boundaries and can lead to unintended charges or analyses being run automatically.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
"release": release,
        "user": data_of(me),
        "balance": data_of(balance),
        "autoConfirm": data_of(auto) if ok(auto) else None,
    }, "links": links()}, args.compact)
Confidence
90% confidence
Finding
Surfacing autoConfirm status to the caller helps an agent determine whether it can initiate paid actions without another user prompt. In an environment where the skill is supposed to remain narrowly scoped and user-mediated, this increases the chance of autonomous spending.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
}, "links": links()}, args.compact)


AUTOCONFIRM_MODE_NOTE = {
    "always_ask": "每次付费操作都会先报价、等你确认。",
    "user_limit": "{limit} 积点以内的操作直接生成,超过才问你。",
    "free_small": "免费版 {max} 积点以内的操作直接生成(用的是赠送积点)。",
Confidence
88% confidence
Finding
The AUTOCONFIRM_MODE_NOTE definitions are part of a feature set that normalizes bypassing interactive confirmation for charges. While not dangerous in a standalone CLI used directly by an informed user, it is risky in an agent setting because it encourages autonomous execution of billable actions.

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
91% confidence
Finding
The autoconfirm command allows direct manipulation of billing confirmation thresholds. This enables a caller to weaken future safeguards by setting low-friction or no-confirm spending behavior, which is inappropriate for a narrowly scoped agent skill.

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
91% confidence
Finding
This logic accepts values like off/default/numeric limits and applies them to account confirmation policy, directly affecting whether future paid actions proceed automatically. In an agent context, changing this policy creates a durable reduction in consent controls beyond the current task.

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
91% confidence
Finding
This logic accepts values like off/default/numeric limits and applies them to account confirmation policy, directly affecting whether future paid actions proceed automatically. In an agent context, changing this policy creates a durable reduction in consent controls beyond the current task.

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
91% confidence
Finding
This logic accepts values like off/default/numeric limits and applies them to account confirmation policy, directly affecting whether future paid actions proceed automatically. In an agent context, changing this policy creates a durable reduction in consent controls beyond the current task.

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
91% confidence
Finding
The PUT to /api/v1/user/autoconfirm persists account-level automation settings. An attacker or over-permissive agent could use this to silently enable future autonomous spending or analysis generation without repeated user consent.

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
91% confidence
Finding
The PUT to /api/v1/user/autoconfirm persists account-level automation settings. An attacker or over-permissive agent could use this to silently enable future autonomous spending or analysis generation without repeated user consent.

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
91% confidence
Finding
The PUT to /api/v1/user/autoconfirm persists account-level automation settings. An attacker or over-permissive agent could use this to silently enable future autonomous spending or analysis generation without repeated user consent.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
"用法:autoconfirm 50(50 积点以内不问)/ autoconfirm off(每次都问)/ autoconfirm default(恢复默认)"),
                     args.compact)
                return
        out = request_json("PUT", "/api/v1/user/autoconfirm", {"limit": limit})
    else:
        out = request_json("GET", "/api/v1/user/autoconfirm")
    if ok(out) and isinstance(data_of(out), dict):
Confidence
89% confidence
Finding
Even the read path for autoconfirm contributes to exploitability because it reveals whether autonomous paid execution is possible. That information meaningfully lowers barriers for an agent deciding whether to proceed with billable operations.

Static analysis

No suspicious patterns detected.