Back to skill

Security audit

亚马逊-店铺External Fulfillment

Security checks for vulnerabilities and agentic risk

Overview

This skill provides real Amazon External Fulfillment tooling, but it also includes broad credential, onboarding, payment, endpoint-override, and local data-retention behavior that users should review carefully before installing.

Install only if you are comfortable with this skill handling LinkFox/Amazon seller operations, phone-based login, API-token setup, and billing recovery from the agent. Avoid using endpoint override environment variables with real credentials, treat saved linkfox response files as sensitive business data, clean them up when no longer needed, and prefer secure credential storage over adding API keys to shell profile files.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (3)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/_spapi_ef_common.py:22
Finding

Credentials and Restricted Fulfillment Data Can Be Redirected to Arbitrary Hosts

Content
View full analysis
dict: api_key = get_api_key() data = json.dumps(params).encode("utf-8") req = Request( endpoint, data=data, headers={ "Authorization": api_key, "Content-Type": "application/json", "User-Agent": "LinkFox-Skill/1.0", "SESSION_ID": os.environ.get("SESSION_ID", ""), "MESSAGE_ID": os.environ.get("MESSAGE_ID", ""), "MODE_ID": os.environ.get("MODE_ID", ""), "APP_NAME": os.environ.get("APP_NAME", ""), }, method="POST", ) try: with urlopen(req, timeout=150) as response: return json.loads(response.read().decode("utf-8")) except HTTPError as e: body = e.read().decode("utf-8") if e.fp else "" return {"error": f"HTTP {e.code}: {e.reason}", "details": body} except URLError as e: return {"error": f"Connection failed: {e.reason}"} def get_store_tokens(seller_id: str, region: str) -> dict: return call_api(STORE_TOKENS_ENDPOINT, {"sellerId": seller_id, "region": region}) ``` The onboarding workflow has equivalent configurable endpoints: ```python def _ag ...[truncated 4977 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/_spapi_ef_common.py:215
Finding

Complete Restricted Fulfillment Responses Are Persisted in Plaintext Without Explicit Access Controls or Retention

Content
View full analysis
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(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 ``` Every result is serialized in full and stored using ordinary file creation governed only by the process umask: ```python def emit_result(result, slug=SLUG, inline=False): """Write the full response to the session data directory.""" serialized = json.dumps(result, ensure_ascii=False, indent=2) ts = time.time() date_str = time.strftime("%Y-%m-%d", 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.p ...[truncated 3320 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/onboarding.py:454
Finding

SMS Login Credentials and Generated API Keys Are Exposed Through Process Arguments, Standard Output, and Shell Configuration

Content
View full analysis
dict: hdr = _headers( "agent-linkfox-web", "ai.linkfox.com", access_token=access_token, user_id=user_id, group_id=group_id, ) for path, source in ( ("/group/getApiToken", "existing"), ("/group/generateApiToken", "generated"), ): resp = _http_post( f"{_agent_user_base()}{path}", {"id": group_id}, hdr, ) if "_error" in resp: return { "error": f"{path.rsplit('/', 1)[-1]}: " f"{resp.get('_body') or resp['_error']}" } tok = _extract_token(resp) if tok: return {"api_key": tok, "source": source} return { "error": f"generateApiToken: no token returned: " f"{json.dumps(resp, ensure_ascii=False)}" } 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: {phone}", "phone": masked, } if not re.fullmatch(r"\d{4,8}", code): return { "error": f"login: invalid verification code: {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: ...[truncated 4549 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • System Prompt LeakageDirect Leakage, Indirect Extraction, Tool-Based Exfiltration
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
Findings (34)

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

Critical
Category
Data Flow
Confidence
90% confidence
Finding

The request sent to urlopen includes multiple HTTP headers sourced directly from environment variables, and the destination base URL is also environment-controlled. This creates a data-exfiltration and SSRF-style trust-boundary issue: a compromised runtime can redirect authenticated requests, along with session metadata and API keys, to an attacker-controlled endpoint.

Content

Scanner excerpt · scripts/_spapi_ef_common.py (reported line 97)May include surrounding context.

python
method="POST",
    )
    try:
        with urlopen(req, timeout=150) as response:
            return json.loads(response.read().decode("utf-8"))
    except HTTPError as e:
        body = e.read().decode("utf-8") if e.fp else ""

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

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/onboarding.py (reported line 196)May include surrounding context.

python
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 = ""

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

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/onboarding.py (reported line 246)May include surrounding context.

python
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

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

声明描述的是一个业务型 External Fulfillment 技能,核心能力应围绕库存、货件、包裹、面单、发票、退货等亚马逊外部履约操作。而实际代码只是一个支持性脚本,用于检查认证依赖技能 linkfox-amazon-store-auth 是否已安装。虽然依赖检查可能是该技能内部的辅助实现,但当前提供的代码块本身并未实现声明中的任何主要业务能力,且其主要目的与声明的主要用途明显不同,因此应判定为描述与代码行为不匹配。

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

声明描述的是亚马逊外部履约业务能力,重点应是库存、货件、包裹、面单、发票、退货等运营数据处理;但代码完全没有实现任何亚马逊 External Fulfillment 相关操作,也没有出现与亚马逊卖家履约、库存 location、shipment/package 更新等相符的接口调用。相反,代码的核心用途是 LinkFox 平台的账号开通与付费购买流程,包括短信登录、团队信息获取、API token 获取、套餐下单、支付二维码渲染和订单支付查询。这属于与声明完全不同的主目的和资源访问对象,触发条件也不一致,因此应判定为明显不匹配。

Content

No source excerpt is available for this finding.

Direct Prompt Extraction

High
Category
System Prompt Leakage
Confidence
85% confidence
Finding

Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Content

Scanner excerpt · SKILL.md (reported line 114)May include surrounding context.

md
---

## Display Rules

1. 先看网关 **`developerProxy.errcode` / `httpStatus`**,再解析脚本附加字段(如 **`batchInventory`**、**`shipments`**、**`invoice`**)。
2. **batchInventory** 成功时常为 **207** Multi-Status;逐条看 `responses[].status`。

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The file instructs the agent to handle account onboarding, login recovery, and billing purchase flows that are unrelated to an External Fulfillment inventory/shipment skill. This expands the skill’s authority into credential handling and payment enablement, increasing the risk of social engineering, unauthorized account creation, and misuse of the agent to collect sensitive data outside its stated purpose.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
96% confidence
Finding

Embedding registration and subscription purchase capabilities in a fulfillment-management skill violates least privilege and creates an unjustified path for the agent to solicit phone numbers, process login codes, and guide payments. In context, this is more dangerous because users invoking a logistics skill would not reasonably expect identity onboarding or billing transactions, making phishing-like abuse easier.

Content

No source excerpt is available for this finding.

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

High
Category
YARA Match
Confidence
75% confidence
Finding

YARA rule matched a known malware signature (reverse shell, backdoor, ransomware, C2 framework, or info stealer).

Content

Scanner excerpt · references/onboarding.md (reported line 14)May include surrounding context.

md
示 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

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The file implements LinkFox onboarding, SMS login, API-key retrieval, package purchase, and payment workflows, which are unrelated to the declared Amazon External Fulfillment skill purpose. In this context, the mismatch is dangerous because it can trick users into disclosing phone numbers, login codes, and payment actions under a false operational pretense.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The code lists paid packages, creates orders, queries payment status, and renders payment QR codes, which are outside the scope of Amazon External Fulfillment management. In this skill context, hidden commerce flows are dangerous because they can induce unauthorized purchases or social-engineer users into paying for unrelated services.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The skill can send SMS codes, log users in, and generate or retrieve API tokens, none of which are justified by an External Fulfillment inventory/shipment management skill. In context, these actions enable credential capture and account takeover-adjacent behavior by collecting OTPs and minting long-lived access material unrelated to the promised functionality.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding

The skill documents capabilities that use environment variables, local file writes, network access, and shell execution, but it does not declare any explicit tool scope or allowed-tools boundary. Without an explicit permission contract, an agent may invoke broader-than-expected capabilities, increasing the chance of unintended file/system access or outbound requests.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The guidance provides a required user-facing reply entirely in Chinese and does not mention any option to match the user's preferred language or locale. This is a natural-language policy issue because it effectively imposes a specific language on responses without user opt-in.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The instructions explicitly tell the operator to ask for a user phone number and use it in a script-based registration/login flow, but provide no privacy notice, consent language, retention limits, or handling safeguards. This creates unnecessary collection of personal data and OTP-related sensitive information, which could be misused or exposed.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/_spapi_ef_common.py (reported line 46)May include surrounding context.

python
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,

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

This code builds a local archival system with session directories, metadata files, and an index of activity that is not necessary for making External Fulfillment API calls. Such behavior expands the skill's data-handling surface and creates an additional inventory of sensitive workflow artifacts that could be read by other local users, tools, or later processes.

Content

No source excerpt is available for this finding.

Ssd 3

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The session output layer stores full responses and indexes them with human-readable metadata such as session identifiers, timestamps, skill names, and file paths. This creates a durable local data-retention trail that makes sensitive fulfillment data easier to enumerate, correlate, and leak, especially in shared or weakly secured environments.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The helper unconditionally serializes and stores full API responses to local disk. External fulfillment responses may contain seller operational data, shipment details, return data, and other sensitive business information, so broad persistence increases exposure and retention risk beyond the stated API-call purpose.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

API responses are written to disk automatically without any visible consent or warning, even though the responses may include seller or account-related data. Silent persistence undermines least surprise and can lead to unintentional disclosure through shared workspaces, backups, or later inspection of saved files.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/onboarding.py (reported line 196)May include surrounding context.

python
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 = ""

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
85% confidence
Finding

The code performs account-login and API-token issuance actions without any in-file user-facing confirmation, risk notice, or consent checkpoint. That is especially risky here because the skill context is unrelated to account provisioning, so users may not realize they are authorizing sensitive authentication and token operations.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

This code performs a network call to Amazon's external fulfillment inventory endpoint and transmits sellerId plus inventory request data, including SKU, location, and possibly quantity. Although the module docstring describes the endpoint, there is no explicit user-facing warning, confirmation, or disclosure in the execution flow that inventory data will be sent externally.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
72% confidence
Finding

The natural-language content of the file is entirely Chinese, and the document does not indicate that language selection is optional or that the skill is intentionally restricted to Chinese-speaking users for a documented regional reason. Per SQP-3, forcing a specific language without user opt-in can constitute a locale policy violation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
80% confidence
Finding

This markdown documents state-changing operations such as inventory updates, shipment confirmation/rejection, package updates, invoice generation, and shipping-label generation, but it does not include a clear warning that these actions may modify seller data or trigger operational effects in Amazon systems. Under the markdown-specific SQP-2 criteria, descriptions of behaviors affecting user data or system integrity should disclose those risks.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.