Back to skill

Security audit

Etsy商品查询

Security checks for vulnerabilities and agentic risk

Overview

The skill mainly performs Etsy product queries, but it also handles LinkFox login, API keys, and paid billing flows with under-scoped credential and payment handling.

Install only if you trust LinkFox with Etsy queries, account onboarding, phone/SMS login, API keys, and payment flows. Avoid endpoint override environment variables unless you control the destination, do not put API keys in shared dotfiles or logs, and require explicit user confirmation before running onboarding or order commands.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/etsy_product_query.py:35
Finding

Credential-Bearing Requests Can Be Redirected to Attacker-Controlled Origins

Content
View full analysis
str: """Gateway base address: LINKFOX_TOOL_GATEWAY takes precedence.""" return (os.environ.get("LINKFOX_TOOL_GATEWAY") or "https://tool-gateway.linkfox.com").rstrip("/") ``` ```python 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", ) ``` The onboarding script permits similar overrides: ```python 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", ) ``` Credential-bearing headers are then constructed without validating the resulting origin: ```python if access_token: h["authorization"] = access_token h["uid"] = ( _uid_header(access_token, user_id) if user_id else _LOGIN_FIXED_UID ) ``` ```python headers = {"Authorization": _api_key()} req = Request(url, method=method, data=body_bytes, headers=headers) ``` ### Te ...[truncated 2270 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/onboarding.py:450
Finding

API Key Is Exposed Through Standard Output and Plaintext Shell Profiles

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} ``` ```python 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} Successfully obtained API key " f"(source: {r['source']})", file=sys.stderr, ) return 0 return 1 ``` The onboarding documentation recommends persistent plaintext shell-profile storage: ```bash setx LINKFOX_AGENT_API_KEY "" e ...[truncated 1861 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/etsy_product_query.py:251
Finding

Unsanitized Session Identifier Allows Output Path Traversal

Content
View full analysis
str: """Prefer SESSION_ID; otherwise generate a process-stable identifier.""" env = os.environ.get("SESSION_ID") if env: return env.strip() if "_auto" not in _SESSION_CACHE: _SESSION_CACHE["_auto"] = ( time.strftime("%H%M%S", time.localtime(ts)) + "-" + secrets.token_hex(3) ) return _SESSION_CACHE["_auto"] ``` ```python def _ensure_session(ts: float) -> tuple[str, str]: """Return (linkfox_root, session_dir); session_dir always exists.""" date_str = time.strftime("%Y-%m-%d", time.localtime(ts)) sid = _session_id(ts) root = _linkfox_root() session_dir = os.path.join(root, date_str, sid) os.makedirs(session_dir, exist_ok=True) _ensure_meta(root, session_dir, date_str, sid, ts) return root, session_dir ``` The resulting path is used for response storage: ```python out_path = _resolve_output_path(ts) try: with open(out_path, "w") as f: f.write(serialized) ``` The onboarding script uses the same unsafe pattern: ```python sid = (os.environ.get("SESSION_ID") or "").strip() or ( time.strftime("%H%M%S", time.localtime(ts)) + "-" + secrets.token_hex(3) ) path = os.path.join( _linkfox_root(), time.strftime("%Y-%m-%d", time.localtime(ts)), sid, ) os.makedirs(path, exist_ok=True) ``` ### Technical Analysis `SESSION_ID` is treated as a trusted path component without validation. It may contain path separators, `..` traversal components, or an absolute path. With `os.path.join`, an absolute final component can replace preceding components. Relative traversal sequences can also escape the intended date and LinkFox roo ...[truncated 1533 chars]
Remediation
View remediation

other

Note
Location
scripts/etsy_product_query.py:63
Finding

Product Queries Transmit Unnecessary Agent Execution Identifiers

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

The request sent via urlopen includes multiple headers derived directly from environment variables, and the destination base URL is also environment-controlled via LINKFOX_TOOL_GATEWAY. In an agent/runtime context where environment variables may be influenced by untrusted orchestration or other skills, this can exfiltrate API credentials and session metadata to an attacker-controlled endpoint or enable SSRF-like outbound requests.

Content

Scanner excerpt · scripts/etsy_product_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 lets environment variables override the base URLs for login and agent-user APIs, then sends sensitive data such as phone numbers, SMS codes, access tokens, refresh tokens, and generated API tokens to those endpoints via requests.post. In an agent or plugin environment where skill configuration can be influenced by a package author or wrapper, this becomes an SSRF/exfiltration path that can silently redirect credentials to attacker-controlled infrastructure.

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

The gateway URL is also derived from environment variables and used by urllib.request.urlopen with the bearer API key in the Authorization header. If an attacker can control the runtime environment, requests intended for the LinkFox gateway can be redirected to an arbitrary host, leaking the API key and enabling unauthorized actions or SSRF to internal services.

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 product filtering, but the referenced behavior extends into account authentication, token generation, user/team info access, subscription discovery, payment order creation, QR-code generation, and payment-status polling. This is a serious trust-boundary violation because a user invoking a product-query skill could be funneled into credential handling and billing actions they did not explicitly request.

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

This skill is described as an Etsy product-query tool, but the file implements a LinkFox onboarding, login, API-key generation, plan listing, order placement, and payment QR workflow. That mismatch is a strong indicator of deceptive functionality: users invoking an Etsy search capability may instead be funneled into account creation, credential submission, and billing actions unrelated to the declared purpose.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The code contains subscription and payment capabilities, including order creation and QR-code rendering for WeChat/Alipay, which are unjustified for an Etsy listing query skill. In this context, embedded billing functionality materially increases risk of unauthorized purchases, deceptive upsells, or social engineering under the guise of normal skill operation.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
80% confidence
Finding

The skill advertises no explicit tool scope or permission boundaries, yet its content indicates access to environment variables, file writes, and network operations. Without declared restrictions, an orchestrator may grant broader capabilities than users expect, increasing the risk of secret access, unintended external requests, or local artifact creation.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The trigger conditions are extremely broad, stating the skill should fire even when the user does not mention the tool name as long as the conversation is about Etsy products, sales, pricing, tags, or sourcing. Overbroad triggering raises the chance of unintended activation of a skill that, per the broader context, may also initiate onboarding, credential, or billing-related flows.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill is for Etsy product querying, but this file adds unrelated account onboarding, API key setup, and billing/payment workflows. Expanding scope in this way can cause an agent to handle secrets, registration, and purchases that users did not expect, increasing the chance of credential exposure, social engineering, and unauthorized transactional actions.

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 ask the user to provide a phone number so a script can send codes and log in on the user's behalf, but they provide no privacy notice, consent language, data handling limits, or warning about sharing personal data and one-time codes. In the context of an Etsy query skill, this is especially risky because it normalizes collection of sensitive information unrelated to the core function and could facilitate account takeover or misuse of OTP-based authentication.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The module docstring and usage/output instructions are entirely in Chinese, and the script also emits Chinese messages to users. For a general-purpose product-query skill, this imposes a specific language on users without opt-in or justification, which matches the locale-policy violation criteria.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The docstring promises that data will not be written to /tmp and that failure to write to the current directory will raise an error, but the implementation silently falls back to home and temporary directories. For a tool handling potentially sensitive API responses, this behavior can cause data to be stored in less protected or unexpected locations, undermining operator assumptions and weakening data handling guarantees.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The module docstring and CLI help/messages are presented entirely in Chinese, and the code consistently emits Chinese-only user-facing text. This enforces a specific language experience without offering the user a choice or documenting a justified region-specific constraint.

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

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The skill sends SMS verification codes and performs LinkFox login to obtain API keys, none of which are required for querying Etsy product listings. Collecting phone numbers, one-time codes, and issuing tokens in a mismatched skill context creates a credential-harvesting risk and broadens the blast radius if the surrounding environment is compromised.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The order command renders a payment QR code and saves it to a PNG file in a session directory, which is a filesystem write affecting local user data. Although the code logs operational status elsewhere, there is no explicit user disclosure or confirmation at the point of this write explaining that a file will be created on disk.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
93% confidence
Finding

The comment at SMALL_THRESHOLD says small responses are output directly and 'not written to file', which contradicts the actual main flow. In main, the script always resolves an output path and writes the serialized response to disk before deciding whether to print the full response or a summary.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.