Back to skill

Security audit

亚马逊-店铺目录

Security checks for vulnerabilities and agentic risk

Overview

This catalog lookup skill includes account login, API-key creation, billing, order creation, payment QR flows, and broad local response storage that need careful review before use.

Install only if you are comfortable letting this skill handle LinkFox account setup and billing recovery in addition to catalog lookup. Avoid entering SMS codes in shared terminals, do not persist API keys in shell profiles on shared machines, verify any payment order before scanning a QR code, and check where full response files are written and retained.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
scripts/onboarding.py:507
Finding
Authentication Secrets Exposed Through Command-Line Arguments and Standard Output<![CDATA[ ## Vulnerability Details **File Location**: `scripts/onboarding.py`, lines 467-493, 507-510, and 574-579 **Vulnerability Type**: Exposure of authentication secrets through process arguments and output channels **Risk Level**: High ### Vulnerable Code ```python def login_and_get_key(phone: str, code: str, channel: str) -> dict: masked = _mask_phone(phone) if not re.fullmatch(r"\d{11}", phone): return {"error": f"login: Invalid phone number format: {phone}", "phone": masked} if not re.fullmatch(r"\d{4,8}", code): return {"error": f"login: Invalid verification code format: {code}", "phone": masked} lg = _login_v3(phone, code, channel) if "error" in lg: return {"error": lg["error"], "phone": masked} if lg.get("is_new_user"): lbt = _login_by_token(lg["access_token"], lg["refresh_token"]) if "error" in lbt: print(f"{TAG} {lbt['error']}", file=sys.stderr) info = _fetch_user_info_v3(lg["access_token"], lg["user_id"]) if "error" in info: return {"error": info["error"], "phone": masked} tok = _get_or_generate_api_token( lg["access_token"], lg["user_id"], info["group_id"] ) if "error" in tok: return {"error": tok["error"], "phone": masked} return { "api_key": tok["api_key"], "phone": masked, "group_id": info["group_id"], "member_id": info["member_id"], "source": tok["source"], "nick_name": lg.get("nick_name", ""), "team_name": info.get("team_name", ""), "is_new_user": lg.get("is_new_user", False), } ``` ```python def _cmd_login(args) -> int: r = login_and_get_key(args.phone.strip(), args.code.strip(), args.channel) _emit(r) if "api_key" in r: print(f"{TAG} API key obtained successfully", file=sys.stderr) return 0 return 1 ``` ```python p = sub.add_parser("login", help="Log in using a verification code and obtain an API key") p.add_argument ...[truncated 2415 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Read the SMS verification code using a non-echoing interactive prompt such as `getpass.getpass()` or accept it through standard input rather than a command-line argument. 2. Do not include the complete API key in stdout JSON. Return only a masked fingerprint, such as the first and last four characters. 3. Store the API key directly in an operating-system credential manager or a file created with mode `0600`. 4. If machine-readable secret output is unavoidable, require an explicit opt-in flag and write the secret to a caller-specified file descriptor rather than ordinary stdout. 5. Add prominent documentation warning that credentials must not be entered into shared terminals, chat transcripts, or CI command lines. 6. Ensure error messages never serialize complete authentication responses containing access tokens, refresh tokens, API keys, or verification codes. 7. Review the server-side key scope and issue a least-privilege key limited to the catalog operations required by this Skill. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/_spapi_catalog_common.py:235
Finding
Full Catalog Responses May Be Written to Undocumented Temporary Locations with Default Permissions<![CDATA[ ## Vulnerability Details **File Location**: `scripts/_spapi_catalog_common.py`, lines 235-258 and 369-386 **Vulnerability Type**: Unsafe fallback storage and insufficiently restrictive file permissions **Risk Level**: Medium ### Vulnerable Code ```python def _lf_root() -> str: cached = _LF_SESSION_CACHE.get("_root") if cached: return cached candidates = [] acpx = (os.environ.get("ACPX_WORKSPACES") or "").strip() if acpx: acpx = acpx.split(os.pathsep)[0].strip() if acpx: candidates.append(os.path.join(acpx, "linkfox")) candidates.append(os.path.join(os.getcwd(), "linkfox")) candidates.append(os.path.join(os.path.expanduser("~"), "linkfox")) candidates.append(os.path.join(_lf_tempfile.gettempdir(), "linkfox")) for root in candidates: try: os.makedirs(root, exist_ok=True) probe = os.path.join(root, ".write_probe") with open(probe, "w", encoding="utf-8") as f: f.write("") os.remove(probe) except OSError: continue root = os.path.abspath(root) _LF_SESSION_CACHE["_root"] = root return root fallback = os.path.abspath(candidates[-1]) _LF_SESSION_CACHE["_root"] = fallback return fallback ``` ```python def emit_result(result, slug=SLUG, inline=False): serialized = json.dumps(result, ensure_ascii=False, indent=2) ts = _lf_time.time() date_str = _lf_time.strftime("%Y-%m-%d", _lf_time.localtime(ts)) sid = _lf_session_id(ts) root = _lf_root() session_dir = os.path.join(root, date_str, sid) os.makedirs(session_dir, exist_ok=True) _lf_ensure_meta(root, session_dir, date_str, sid, ts) data_dir = os.path.join(session_dir, "data") os.makedirs(data_dir, exist_ok=True) out = os.path.join(data_dir, f"{slug}-{int(ts * 1_000_000)}.json") try: with open(out, "w", encoding="utf-8") as f: f.write(serialized) ...[truncated 2502 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove the home-directory and system-temporary-directory fallbacks when they conflict with the documented workspace-only policy. 2. Fail closed with a clear error if the required workspace output directory is not writable. 3. Create session directories with mode `0700` and response files with mode `0600`, independently of the user's umask. 4. Use atomic file creation with exclusive-create semantics to prevent overwriting or following attacker-controlled paths. 5. Resolve and validate the final path before writing, ensuring that it remains beneath the approved workspace root. 6. Reject symbolic links in the output hierarchy or use secure directory-descriptor-based APIs where available. 7. Add a retention policy and a cleanup command for stored response data. 8. If temporary storage is operationally required, create a unique private directory with `tempfile.mkdtemp()` and restrictive permissions rather than using a shared predictable `/tmp/linkfox` directory. 9. Update documentation and implementation together so users can accurately determine where complete responses are retained. ]]>

T08 · Insecure Dependencies

Warning
Location
scripts/onboarding.py:163
Finding
Onboarding Recommends Installation of Unpinned Third-Party Dependencies<![CDATA[ ## Vulnerability Details **File Location**: `scripts/onboarding.py`, lines 163-187 **Vulnerability Type**: Unpinned package installation guidance **Risk Level**: Medium ### Vulnerable Code ```python def render_qr(content: str, out_dir: str) -> dict: try: import qrcode except ImportError: err = "Missing qrcode dependency; run: pip install qrcode pillow" print(f"{TAG} render_qr: {err}", file=sys.stderr) return {"png_path": None, "ascii_qr": None, "error": err} ``` ```python def _require_requests() -> None: if requests is None: raise RuntimeError( "Missing requests dependency; run: pip install requests" ) ``` ### Technical Analysis The onboarding script directs users to install `qrcode`, `pillow`, and `requests` without pinned versions, package hashes, a lock file, or an explicitly trusted package index. The packages are well-known names, and the audit found no evidence that the Skill intentionally references a malicious or typosquatted package. Nevertheless, the installation commands resolve mutable artifacts from the environment's configured pip index. A compromised package release, malicious mirror, dependency-confusion configuration, or future incompatible version could introduce attacker-controlled code. Python packages may execute code during build or installation, and imported packages execute module initialization code at runtime. ### Attack Path 1. A user invokes onboarding functionality on a system where one of the optional dependencies is absent. 2. The script displays an instruction to run an unpinned `pip install` command. 3. The user executes the command using the active Python package-index configuration. 4. A compromised index, malicious mirror, dependency-confusion source, or compromised future release supplies attacker-controlled package code. 5. Installation hooks or later imports execute that code with the privileges of the user running pip or the Skill. # ...[truncated 468 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Provide a reviewed dependency manifest or lock file containing exact versions. 2. Supply cryptographic hashes and install with `pip --require-hashes`. 3. Specify the trusted package index and prohibit untrusted extra indexes in deployment instructions. 4. Prefer an isolated virtual environment rather than installation into the system interpreter. 5. Document the verified package names, versions, maintainers, and expected hashes. 6. Run dependency vulnerability and provenance checks as part of release validation. 7. Consider removing the `requests` dependency by using the already imported standard-library HTTP client consistently, reducing supply-chain surface. 8. Treat QR rendering as optional and allow payment URLs to be displayed without requiring additional packages. ]]>
Vulnerability Patterns
  • 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
  • System Prompt LeakageDirect Leakage, Indirect Extraction, Tool-Based Exfiltration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (32)

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

Critical
Category
Data Flow
Content
method="POST",
    )
    try:
        with urlopen(req, timeout=timeout) as response:
            return json.loads(response.read().decode("utf-8"))
    except HTTPError as e:
        body = e.read().decode("utf-8") if e.fp else ""
Confidence
90% confidence
Finding
The request sent via urlopen includes multiple headers sourced directly from environment variables and posts to an endpoint whose base URL can also be overridden by environment variables. In a hostile or multi-tenant runtime, this enables untrusted environment data to influence outbound network destinations and exfiltrate API keys, session identifiers, or sensitive catalog/token responses to an attacker-controlled gateway.

Tainted flow: 'url' from os.environ.get (line 235, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Content
except RuntimeError as e:
        return {"_error": str(e)}
    try:
        r = requests.post(url, json=body or {}, headers=headers, timeout=timeout)
        return r.json()
    except Exception as e:
        body_text = ""
Confidence
95% confidence
Finding
The script builds request destinations from environment variables and then sends sensitive data such as phone numbers, SMS codes, access tokens, refresh tokens, and generated API keys to those endpoints. In a hostile or misconfigured runtime, an attacker can override the base URLs and redirect these secrets to attacker-controlled infrastructure, creating an SSRF-style exfiltration path.

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

Critical
Category
Data Flow
Content
headers["Content-Type"] = "application/json"
        req = Request(url, method=method, data=body_bytes, headers=headers)
        try:
            with urlopen(req, timeout=30) as resp:
                return json.loads(resp.read().decode())
        except urllib.error.HTTPError as e:
            status = e.code
Confidence
95% confidence
Finding
The gateway URL is also derived from environment configuration and used with an Authorization header containing the agent API key. If the environment is attacker-influenced, requests can be redirected to an arbitrary host, leaking credentials and enabling unauthorized actions under the victim's account.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
If the skill actually includes SMS login, API key generation, subscription browsing, payment-order creation, and QR-code payment flows, that is far outside the declared purpose of a read-only Amazon catalog query skill. Such hidden account-management and payment functionality materially increases the attack surface, can manipulate billing state, and may trick users into credential or payment actions under the guise of product lookup.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
If the skill actually includes SMS login, API key generation, subscription browsing, payment-order creation, and QR-code payment flows, that is far outside the declared purpose of a read-only Amazon catalog query skill. Such hidden account-management and payment functionality materially increases the attack surface, can manipulate billing state, and may trick users into credential or payment actions under the guise of product lookup.

Direct Prompt Extraction

High
Category
System Prompt Leakage
Content
---

## Display Rules

1. 先看 **`developerProxy.errcode` / `httpStatus`**,再读 **`categories`** / **`catalogItems`** / **`catalogItem`**。
2. **listCatalogCategories** 使用 v0 查询键 **`MarketplaceId`**(单数),与 search/get 的 **`marketplaceIds`** 不同。
Confidence
85% confidence
Finding
Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

YARA rule 'backdoor_persistence': Backdoor persistence with malicious payloads (shell commands, SSH key injection, hidden root users) [malware]

High
Category
YARA Match
Content
示 JSON 里的 phone/agreements
   - 收到验证码后:`python scripts/onboarding.py login <phone> <code>`
   - 拿到 `api_key` 后把下面三平台配置转发给用户,提示重启会话生效:
     - Windows PowerShell(永久):`setx LINKFOX_AGENT_API_KEY "<key>"`
     - macOS zsh:`echo 'export LINKFOX_AGENT_API_KEY="<key>"' >> ~/.zshrc && source ~/.zshrc`
     - Linux bash:`echo 'export LINKFOX_AGENT_API_KEY="<key>"' >> ~/.bashrc && source ~/.bashrc`
     - 变量名 `LINKFOX_AGENT_API_KEY`(主推)或 `LINKFOXAGENT_API_KEY`(老规范)任一即可

**billing 场景**:`errcode=402` 或消息含 `算力/余额/quota/insufficient/充值/套餐到期`。
- `python scripts/onboarding.py list-plans` → 有 AskUserQuestion 就弹菜单,否则输出编号清单让用户选
- 校验 `plan_id` ∈ 清单、支付方式 ∈ 该套餐 `available_methods`(通常 `wechat/alipay`)
- `python scripts/onboarding.py order <plan_id> <method>` → 展示优先级 PNG
Confidence
75% confidence
Finding
YARA rule matched a known malware signature (reverse shell, backdoor, ransomware, C2 framework, or info stealer).

Description-Behavior Mismatch

High
Confidence
99% confidence
Finding
This file implements account onboarding, SMS login, API key retrieval, package listing, ordering, and payment QR generation, which are materially unrelated to an Amazon catalog lookup skill. That scope mismatch is dangerous because it introduces credential handling and monetization capabilities that users would not reasonably expect from a catalog-query tool, increasing the chance of deceptive collection of secrets and unintended account actions.

Context-Inappropriate Capability

High
Confidence
98% confidence
Finding
The order-creation and payment flow allows the skill to initiate purchases and produce payment QR codes, capabilities unrelated to catalog-item queries. In this context, that materially elevates risk because a user invoking a product-search skill would not expect transaction initiation, enabling surprise charges or social engineering into payment.

Context-Inappropriate Capability

High
Confidence
99% confidence
Finding
The code performs SMS-based login, fetches user/team information, and generates or retrieves API tokens, which is far beyond the stated purpose of catalog querying. In this skill context, collecting authentication factors and minting long-lived credentials is especially dangerous because it creates a hidden privilege-escalation and credential-harvesting surface under the guise of a benign lookup capability.

Lp3

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding
Without declared permissions the skill's intent is opaque and cannot be validated.

Vague Triggers

Medium
Confidence
92% confidence
Finding
L003 说明“即使未明确说‘Catalog’,只要希望查询亚马逊全站目录中的商品基础资料而不是卖家自己的 Listing,也应触发此技能”,将触发范围扩展到较宽泛的自然语言意图,但没有给出明确边界或反例。这种描述容易与常见的‘查商品’类日常请求重叠,导致技能在用户未明确指定 Catalog Items 场景时被误触发。

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
L112 给出了固定中文回复模板“可回复:‘为保护您的亚马逊店铺安全……’”,未说明应根据用户语言偏好调整,也未提供多语言或用户选择机制。这属于自然语言层面的语言/locale 强制,可能违反要求按用户语言或经用户同意后再切换语言的组织政策。

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The onboarding instructions explicitly tell the agent to ask for and process a user's phone number in order to register/login via a helper script, but they provide no privacy notice, consent language, data minimization guidance, or handling restrictions. In an agent context, this increases the chance that sensitive personal data and one-time codes are collected, displayed, logged, or forwarded insecurely during support flows.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The markdown instructs permanently storing an API key in shell profile files or Windows user environment variables without warning about persistence, local exposure, or safer alternatives. This can cause long-lived credential leakage through shared accounts, backups, dotfile sync, terminal history, or accidental disclosure when users inspect or share their shell configuration.

Context-Inappropriate Capability

Medium
Confidence
83% confidence
Finding
A catalog-items helper would be expected to validate inputs and call the relevant API, but ensure_auth_skill_available() executes another Python script via subprocess.run(). Launching subprocesses is a broader execution capability than needed for searching or fetching catalog data, and the manifest does not indicate such behavior.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
print(f"DEPENDENCY_MISSING: {json.dumps(payload, ensure_ascii=False)}", file=sys.stderr)
        sys.exit(DEPENDENCY_EXIT_CODE)
    try:
        result = subprocess.run(
            [sys.executable, str(checker)],
            capture_output=True,
            text=True,
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Natural-Language Policy Violations

Medium
Confidence
98% confidence
Finding
The docstring and related user-facing error text are written in Chinese, including instructions and status output, with no indication that language is configurable or intentionally region-scoped. This can violate language or locale policy when a skill imposes a single language without user opt-in.

Description-Behavior Mismatch

Medium
Confidence
97% confidence
Finding
emit_result writes full API responses to local disk under several possible directories, including the current working directory, the user's home directory, or a temp directory. Catalog and token-adjacent responses may contain sensitive business data, and indiscriminate persistence increases exposure through local compromise, shared workspaces, backups, or later unintended access.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The helper silently saves full responses to disk and only prints a save-path message after doing so; there is no prior warning, consent, or indication that queried data will be persisted. In a query-oriented catalog skill, this expands data handling beyond user expectations and can expose sensitive response contents to other local users, logs, backups, or incident responders.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
This Python file contains user-facing natural-language text in Chinese in the module docstring, and additional Chinese-only messaging later in the payload. Under the policy, forcing a specific language without user opt-in is a locale/language policy violation unless the constraint is explicitly justified or optional.

Natural-Language Policy Violations

Medium
Confidence
97% confidence
Finding
The missing-dependency reason returned to users is hardcoded in Chinese, with no indication that the user can choose another language or that the skill is region-specific. This creates a language policy issue because the skill imposes a locale on user-facing output.

Natural-Language Policy Violations

Medium
Confidence
89% confidence
Finding
The natural-language description mixes English API identifiers with Chinese explanatory text and presents the skill as using a Chinese default ('默认') without offering a language choice. Under the language/locale policy, forcing or assuming a specific language without user opt-in is a policy concern unless explicitly justified.

Natural-Language Policy Violations

Medium
Confidence
91% confidence
Finding
The module docstring and all user-facing help/messages are written exclusively in Chinese, which imposes a language choice on users. The file does not offer language selection or explain that the skill is intentionally limited to a Chinese-speaking or China-region context.

Context-Inappropriate Capability

Medium
Confidence
90% confidence
Finding
The skill creates session directories and persists QR code PNG files locally, even though local storage is not needed for catalog-item lookups. While not inherently malicious, this broadens the data footprint and can expose payment-related artifacts or session metadata to other local users, backup systems, or later processes.

Static analysis

No suspicious patterns detected.