Back to skill

Security audit

Etsy店铺查询

Security checks for vulnerabilities and agentic risk

Overview

This Etsy store-query skill also handles LinkFox login, API keys, billing, payment orders, and credential setup in ways users should review carefully before installing.

Install only if you are comfortable letting this skill interact with LinkFox account, billing, and payment-order flows. Prefer using the official LinkFox site for login and key management, avoid entering OTPs as command arguments, do not store API keys in shell history or shared profiles, and do not set endpoint override environment variables unless you fully trust the destination.

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 (4)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/etsy_store_query.py:37
Finding

Credential-bearing requests can be redirected to arbitrary hosts

Content
View full analysis
str: """Gateway base address: env LINKFOX_TOOL_GATEWAY takes priority.""" return (os.environ.get("LINKFOX_TOOL_GATEWAY") or "https://tool-gateway.linkfox.com").rstrip("/") ``` ```python # scripts/etsy_store_query.py:60-80 def call_api(params): api_url = get_api_url() api_key = get_api_key() data = json.dumps(params).encode("utf-8") headers = { "Authorization": api_key, "Content-Type": "application/json", "User-Agent": "LinkFox-Skill/2.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", ""), } req = Request( api_url, data=data, headers=headers, method="POST", ) try: with urlopen(req, timeout=150) as response: return json.loads(response.read().decode("utf-8")) ``` ```python # scripts/onboarding.py:70-85 def _env_base(name: str, default: str, *fallbacks: str) -> str: for n in (name, *fallbacks): v = os.environ.get(n) if v: return v.rstrip("/") return default.rstrip("/") def _agent_base() -> str: return _env_base("LINKFOX_AGENT_API_URL", "https://tool-gateway.linkfox.com", "LINKFOX_TOOL_GATEWAY") def _login_base() -> str: return _env_base("LINKFOX_LOGIN_API_URL", "https://api.linkfox.com") def _agent_user_base() -> str: return _env_base("LINKFOX_AGENT_USER_API_URL", "https://agent-api.linkfox.com") ``` ```python # scripts/onboarding.py:190-225 d ...[truncated 3568 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/onboarding.py:470
Finding

Sensitive credentials are exposed through process arguments, standard output, and plaintext shell profiles

Content
View full analysis
` - After receiving the code: `python scripts/onboarding.py login ` - After obtaining `api_key`, provide these configurations: - Windows PowerShell: `setx LINKFOX_AGENT_API_KEY ""` - macOS zsh: `echo 'export LINKFOX_AGENT_API_KEY=""' >> ~/.zshrc && source ~/.zshrc` - Linux bash: `echo 'export LINKFOX_AGENT_API_KEY=""' >> ~/.bashrc && source ~/.bashrc` ``` ```python # scripts/onboarding.py:470-493 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: 手机号格式不正确: {phone}", "phone": masked} if not re.fullmatch(r"\d{4,8}", code): return {"error": f"login: 验证码格式不正确: {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']}(不影响拿 key)", 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 ...[truncated 3054 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
scripts/onboarding.py:160
Finding

Onboarding recommends installing unpinned third-party dependencies at runtime

Content
View full analysis
dict: try: import qrcode except ImportError: err = "缺少 qrcode 依赖,请运行: pip install qrcode pillow" print(f"{TAG} render_qr: {err}", file=sys.stderr) return {"png_path": None, "ascii_qr": None, "error": err} ``` ```python # scripts/onboarding.py:183-187 def _require_requests() -> None: if requests is None: raise RuntimeError( "缺少 requests 依赖,请运行: pip install requests") ``` ### Technical Analysis The script directs users to install `qrcode`, `pillow`, and `requests` without version constraints, integrity hashes, a lockfile, or an isolated environment. Consequently, the exact code installed is determined by the package index at installation time rather than by the reviewed Skill package. These package names correspond to legitimate projects, and the audit found no evidence that the Skill intentionally requests a known malicious or typosquatted package. The weakness is the absence of reproducible dependency controls. A compromised upstream release, account takeover, malicious index configuration, or future unsafe version could introduce code not covered by this audit. ### Attack Path 1. The victim runs an onboarding function on a system where one of the optional packages is absent. 2. The script displays an instruction to run an unrestricted `pip install` command. 3. The victim executes the command using the current package-index configuration. 4. `pip` resolves and installs the latest available package and its transitive dependencies without project-supplied integrity verification. 5. A compromised package artifact or dependency executes installation or runtime code with the victim's user privileges. ### ...[truncated 511 chars]
Remediation
View remediation

other

Note
Location
scripts/etsy_store_query.py:60
Finding

Undocumented Agent and session metadata is transmitted to the external gateway

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • 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
  • YARA SignaturesMalware Match, Webshell Match, Cryptominer Match
Findings (18)

Tainted flow: 'req' from os.environ.get (line 73, 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/etsy_store_query.py (reported line 80)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
95% confidence
Finding

The code builds request destinations from environment-controlled base URLs and then sends sensitive data such as phone numbers, SMS codes, access tokens, refresh tokens, and generated API keys to those endpoints. If an attacker can influence environment variables, they can redirect authentication traffic to attacker-controlled infrastructure and capture credentials or tokens; in this skill, that risk is amplified because the script handles account onboarding and token issuance unrelated to the declared Etsy functionality.

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
95% confidence
Finding

The gateway request path uses environment-derived base URLs with an Authorization header containing the API key, then performs outbound requests via urllib. An attacker who can set or poison the environment can exfiltrate the API key and payment/order data to a malicious host, creating credential theft and account abuse risk; the mismatch with the Etsy store-query skill makes this especially suspicious and unnecessary.

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

The declared purpose is Etsy store querying, but the referenced behavior includes SMS login, API key generation, account/team information access, plan listing, payment order creation, QR-code payment initiation, and order status checks. This is a major scope expansion into authentication, credential handling, account access, and payments, which can expose sensitive user data and enable unauthorized transactional actions if triggered under the guise of a store-search skill.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The file embeds authentication recovery, account registration, and billing/payment onboarding logic inside a skill whose declared purpose is Etsy store querying. This is a significant scope mismatch that can enable unnecessary credential handling, payment redirection, and collection of sensitive user data under the guise of a search/analytics feature. In this context, the unrelated onboarding content makes the skill more dangerous because users invoking an Etsy analysis tool would not reasonably expect account provisioning or payment flows.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The documentation explicitly instructs the agent to collect a user's phone number, perform login/registration by script, and initiate plan purchases and payment method selection. Those capabilities are not justified by the stated Etsy store analysis purpose and create opportunities for unauthorized account creation, sensitive data collection, and payment abuse. The skill context increases risk because it disguises identity and billing operations as routine support for a commerce-analysis tool.

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's entire purpose is LinkFox account onboarding, login, API-key retrieval, package listing, ordering, and payment handling, which is unrelated to the advertised Etsy store query/filter capability. This functionality expands the attack surface to credential harvesting and unauthorized billing flows under the guise of an Etsy-analysis skill, making the context materially more dangerous.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The script can create orders, query order status, and render payment QR codes for LinkFox packages despite being presented as an Etsy store-query tool. Embedding billing and payment collection in an unrelated skill can mislead users into making purchases they did not expect and exposes them to fraudulent or unauthorized charges.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The code implements SMS verification, login, token exchange, team enumeration, and API-token generation even though the skill claims to search and filter Etsy stores. Collecting phone numbers and one-time codes inside an unrelated skill is a classic credential-capture pattern and provides a path to unauthorized account access and token issuance.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding

The skill declares no explicit tool scope or allowed-tools despite requiring environment access, file write capability, and network access. This violates least-privilege and makes it harder to constrain execution, increasing the risk that a triggered skill can access sensitive data or perform side effects beyond what users expect.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The activation text is overly broad and says the skill should trigger even when the user does not mention the tool name, for general Etsy store search, filtering, or performance analysis. Broad trigger conditions increase the chance of unintended invocation of a skill that, per the mismatch finding, may also lead users into authentication or billing-related flows.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The markdown instructs asking the user for a phone number and then using it in a script-driven registration/login flow, but provides no privacy warning, data minimization guidance, or safeguards for handling OTPs and personal data. This can lead to unnecessary collection of sensitive identifiers and social-engineering risk, especially when embedded in a skill unrelated to identity onboarding. The mismatch with the Etsy-query use case makes the request more suspicious and more likely to mislead users.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The module docstring, usage guidance, and operational descriptions are written entirely in Chinese, and additional user-facing errors and status messages elsewhere in the file also assume Chinese output. For a general-purpose script, this imposes a fixed language/locale without opt-in, which matches the policy category for language or locale violations.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The documentation promises that output is always written under the current working directory and explicitly forbids /tmp, but the implementation silently falls back to home and temporary directories. In a tool that handles potentially sensitive API responses, this discrepancy can cause data to be stored in less expected or less controlled locations, increasing the risk of inadvertent disclosure, cross-session leakage, or policy bypass.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The user-facing docstring and later validation logic describe login only in terms of SMS to an 11-digit domestic phone number, and the implementation fixes the area code to +86. This imposes a specific locale/language-region constraint without offering opt-in or explaining that the skill is intentionally China-only.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
88% confidence
Finding

The code transmits user-supplied and security-sensitive data to external services through requests.post, including phone numbers, verification codes, tokens, and device metadata. External transmission is expected for API clients, but here it is risk-relevant because the transmissions support unrelated onboarding/token flows and can expose sensitive data beyond the declared Etsy-query function.

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

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The comment says responses under the threshold are 'directly output, not written to file', but main() always resolves an output path and writes the serialized response before deciding whether to print inline or summarize. This is an active contradiction between code commentary and implementation.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.