Back to skill

Security audit

Etsy类目搜索

Security checks for vulnerabilities and agentic risk

Overview

This skill can search Etsy categories, but it also handles LinkFox login, API keys, and payment orders in ways that deserve careful review before installation.

Install only if you are comfortable with this skill using LinkFox network services, handling API keys, and potentially guiding phone-based login and payment order creation. Prefer obtaining and storing API keys through LinkFox's official UI or a secret manager, avoid pasting keys into shared transcripts or shell profiles, and do not run payment/order commands unless you explicitly intend to buy a plan.

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_category_search.py:37
Finding

Credential Exfiltration Through Unrestricted API Endpoint Overrides

Content
View full analysis
str: """Gateway base address.""" return (os.environ.get("LINKFOX_TOOL_GATEWAY") or "https://tool-gateway.linkfox.com").rstrip("/") def get_api_url(): sys.path.insert( 0, os.path.join( os.path.dirname(os.path.abspath(__file__)), "..", "..", "_shared", ), ) return get_api_base() + API_PATH 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 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.lin ...[truncated 4702 chars]
Remediation
View remediation

other

Warning
Location
scripts/etsy_category_search.py:60
Finding

Unnecessary Transmission of Agent Session and Message Metadata

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/onboarding.py:468
Finding

API Key Disclosure Through Standard Output and Plaintext Shell Profiles

Content
View full analysis
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 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']} (does not prevent key retrieval)", 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), } def _emit(obj: dict) -> None: print(json.dumps(obj, ensure_ascii=False, indent=2)) def _cmd_login(args) -> int: r = login_ ...[truncated 2816 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Note
Location
scripts/onboarding.py:162
Finding

Unpinned Runtime Dependency Installation Guidance

Content
View full analysis
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, } os.makedirs(out_dir, exist_ok=True) png_path = os.path.join( out_dir, f"qr-{int(time.time() * 1_000_000)}.png", ) qr = qrcode.QRCode(border=1) qr.add_data(content) qr.make(fit=True) qr.make_image( fill_color="black", back_color="white", ).save(png_path) buf = io.StringIO() qr.print_ascii(out=buf, invert=True) return { "png_path": png_path, "ascii_qr": buf.getvalue(), } def _require_requests() -> None: if requests is None: raise RuntimeError( "Missing requests dependency; run: pip install requests" ) ``` ### Technical Analysis When optional modules are unavailable, the script instructs users to install `qrcode`, `pillow`, and `requests` directly from pip without versions, hashes, a lockfile, or a documented trusted package index. This does not prove that the named packages are malicious. The risk is that dependency resolution is mutable and environment-dependent. Future compromised releases, an untrusted package index, index substitution, or unexpected incompatible versions could introduce code that executes with the user's privileges during installation or import. Because package installation and imports can execute package-controlled code, dependency provenance should be treated as part of the Skill's trusted computing base. ### Attack Path 1. The user invokes an onboard ...[truncated 1052 chars]
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 (20)

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

Critical
Category
Data Flow
Confidence
95% confidence
Finding

The request sent via urlopen includes multiple headers populated directly from environment variables, including Authorization and session metadata, and the destination host is partially controllable through LINKFOX_TOOL_GATEWAY. This creates a real exfiltration risk: if the environment or runtime configuration is influenced by an attacker, sensitive credentials and identifiers can be sent to an attacker-controlled endpoint.

Content

Scanner excerpt · scripts/etsy_category_search.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 POST target URL is derived from environment-controlled base URLs, so a caller can redirect authentication and user data flows to an attacker-controlled endpoint. Because this script sends phone numbers, SMS codes, access tokens, refresh tokens, and generated API tokens over these requests, misuse can result in credential theft and account compromise. The mismatch between the skill's Etsy category-search purpose and this onboarding/login behavior makes the risk more suspicious and less justifiable.

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

The gateway request URL is built from environment variables and then opened with urllib, allowing network requests containing the agent API key to be sent to an attacker-chosen host. This can leak the API key and expose account, package, and order operations to interception or abuse. In the context of an Etsy category lookup skill, this external payment/account control path is unjustified and increases concern.

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

This is a significant description-behavior mismatch: a skill presented as a harmless category search also appears to support SMS verification, phone-based login, API key retrieval, account/team queries, package listing, payment order creation, QR code generation, and payment-status checks. Hidden authentication and payment flows are dangerous because they can collect credentials, expose account data, or initiate commercial actions under the guise of a benign lookup 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
97% confidence
Finding

The skill description says it should search a locally synced Etsy category database, but the code instead performs a remote API call to a gateway service. This mismatch is security-relevant because users and operators may assume data stays local, while queries, credentials, and session metadata are actually transmitted off-box to an external service.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The file implements LinkFox account onboarding, login, package purchase, and payment workflows, which are unrelated to the declared Etsy category-search skill. This indicates a hidden capability mismatch: a user invoking a benign category lookup skill could instead be prompted into account, credential, or payment actions they did not expect. Such deceptive scope expansion is dangerous because it enables unauthorized collection of sensitive data under false pretenses.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The code can create purchase orders and render payment QR codes, enabling monetary transactions from within a skill that should only search Etsy categories. This creates a direct path to unexpected financial operations and social-engineering of users into making payments unrelated to the advertised purpose. The context makes this especially dangerous because users would not reasonably expect billing behavior from a taxonomy lookup tool.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The script performs SMS-based login, token exchange, team discovery, and API token generation despite the skill being described as an Etsy category search utility. This enables collection of phone numbers, verification codes, access tokens, and API keys under an unrelated cover story, which can lead to account takeover and persistent access. The skill-context mismatch materially increases the likelihood of deceptive use.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding

The skill declares only a simple Etsy category lookup purpose, yet static analysis detected access to environment variables, file writing, and network operations without any explicit tool-scope restrictions. In an agent setting, missing permission boundaries increases the chance the skill can access secrets, write local artifacts, or make outbound requests beyond what users would reasonably expect from a category search function.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The trigger language is overly broad, including activation whenever a user wants to find category IDs from a local synced Etsy category library even without naming the tool. Overbroad triggers can cause the skill to activate in unrelated conversations, increasing the chance that its broader hidden capabilities are invoked unexpectedly or that it intercepts prompts intended for safer tools.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The onboarding flow explicitly instructs the agent to collect a user's phone number and use it for script-based registration, but provides no privacy notice, consent language, retention limits, or handling restrictions. Because this is an authentication recovery path inside a skill, the context increases risk: the agent may solicit sensitive personal data during troubleshooting without clear safeguards, creating privacy, compliance, and trust issues.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This code file contains natural-language descriptions and CLI messaging entirely in Chinese, including the module docstring that defines usage and behavior. Under the language/locale policy rule, forcing a specific language without user opt-in is a policy concern unless the locale restriction is explicitly justified, which is not present here.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The script persistently writes full API responses to local files by default, which exceeds the narrow lookup behavior described for a category-search skill. Even if the expected data is category metadata, full responses can contain unexpected fields, identifiers, or operational metadata, creating unnecessary local data retention and possible cross-session exposure on shared systems.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The documentation explicitly states that writing to /tmp is forbidden and that an unwritable current directory should cause an error, but the implementation silently falls back to the home directory and then a temp directory. This discrepancy can place persisted API data into less controlled locations, increasing the chance of unintended disclosure, especially on multi-user or ephemeral systems.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The module docstring openly describes a self-contained LinkFox onboarding CLI, contradicting the declared Etsy category-search metadata. This inconsistency is a strong indicator that the packaged skill does something materially different from what users and reviewers are told, undermining informed consent and trust boundaries. While the docstring itself is not exploit code, it signals deceptive functionality that amplifies the risk of the associated credential and payment behaviors.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The module docstring and CLI help text are entirely in Chinese, and the workflow is also fixed to Chinese phone format and +86 area code elsewhere in the file. This enforces a specific language/locale experience without offering user opt-in or documenting a justified region-specific constraint.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
84% confidence
Finding

This code externally transmits sensitive user-supplied and derived data via HTTP POST, including phone numbers, SMS codes, and tokens depending on the caller path. External transmission is expected for remote services, but here the destination can be influenced by environment configuration and the entire behavior is unrelated to the stated Etsy category-search function. That combination makes the transmission materially risky rather than routine.

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

The skill generates or retrieves an API token and returns it in output without an explicit warning, redaction, or secure handling guidance. Exposing a live credential in normal skill output increases the chance of accidental disclosure through logs, transcripts, clipboard sharing, or downstream tooling. Because this token issuance is unrelated to Etsy category search, the exposure is less defensible and more dangerous.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

该 API 参考全文以中文撰写,未说明这是面向特定中文用户群体的区域性文档,也未提供其他语言选项或用户选择机制。根据语言/locale 政策,若技能内容默认强制单一语言而无用户选择,可能构成自然语言层面的策略违规。

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.