T01 · Skill Instruction Hijacking
- Location
SKILL.md:123- Finding
Silent Transmission of Conversation-Derived Feedback
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This appears to be a real LinkFox Mercado Libre data-query skill, but it needs Review because it also handles credentials, account onboarding, payment orders, local storage, and automatic feedback reporting with weak safeguards.
Install only if you trust LinkFox with your Mercado research queries, account usage data, phone-based onboarding data, and billing workflow. Before use, avoid custom LINKFOX_* endpoint overrides, treat generated API keys as secrets, do not paste keys into shell history or shared logs, review any payment order before paying, and periodically delete local linkfox response/cache files if they may contain sensitive business data.
SKILL.md:123Silent Transmission of Conversation-Derived Feedback
scripts/linkfox_mercado_product_selection.py:38Credentials and Session Metadata Can Be Redirected to Arbitrary Endpoints
scripts/onboarding.py:486Generated API Key Is Exposed Through Standard Output and Shell Configuration Guidance
scripts/linkfox_mercado_product_selection.py:250Unsanitized Session Identifier Allows Path Traversal and Writes Outside the Intended Directory
scripts/linkfox_mercado_product_selection.py:96Complete API Responses Are Persisted in Insecure Cache and Temporary Locations
scripts/onboarding.py:163Runtime Guidance Installs Unpinned Third-Party Dependencies
The request destination is influenced by environment-controlled configuration via LINKFOX_TOOL_GATEWAY, and the request also includes sensitive headers such as the API key and session metadata. In an agent/runtime context, environment variables are often externally supplied, so a poisoned gateway value can redirect authenticated traffic to an attacker-controlled host and exfiltrate credentials or user data.
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 ""
The POST destination is derived from environment-controlled base URLs, and this code sends sensitive data including phone numbers, SMS codes, access tokens, refresh tokens, and generated API keys to those endpoints. In a skill/runtime environment where environment variables may be influenced by a packager, wrapper, or compromised host, this enables silent credential exfiltration and redirection to attacker-controlled services.
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 = ""
The gateway URL is also built from environment-controlled configuration and used with an Authorization header carrying the user's API key. If an attacker can influence LINKFOX_AGENT_API_URL or fallback variables, requests can be redirected to a malicious server and the API key plus subsequent account/order operations can be captured.
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
The skill is described as a data-query tool, but the detected behavior includes authentication, API key lifecycle actions, account/team queries, package purchase flows, payment initiation, QR rendering, and order/payment status checks. These undisclosed account and payment capabilities materially expand the trust boundary and could expose users to unauthorized transactions, credential misuse, or sensitive account operations under the guise of analytics.
The skill is described as a data-query tool, but the detected behavior includes authentication, API key lifecycle actions, account/team queries, package purchase flows, payment initiation, QR rendering, and order/payment status checks. These undisclosed account and payment capabilities materially expand the trust boundary and could expose users to unauthorized transactions, credential misuse, or sensitive account operations under the guise of analytics.
Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.
On PowerShell, wrap the JSON in single quotes the same way; if quoting is troublesome, write the payload to a file and pass it via `--inline` after loading, or use `ConvertTo-Json` to build the argument.
## Display Rules
1. Present the returned data clearly without inventing unsupported business conclusions.
2. Preserve the meaning and important field names from results; translate labels only when it improves readability.
YARA rule matched a known malware signature (reverse shell, backdoor, ransomware, C2 framework, or info stealer).
示 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
This file implements SMS login, token acquisition, plan listing, ordering, and payment QR generation, which materially exceeds the declared skill purpose of Mercado product-selection data query and analysis. Scope expansion is dangerous because users invoking an analytics skill would not reasonably expect account onboarding, credential issuance, and commerce flows, increasing the chance of social engineering and unauthorized sensitive actions.
The code can create orders and render payment QR codes, enabling billing actions unrelated to a product-selection analytics skill. In context, that makes the skill more dangerous because it can steer a user from benign data analysis into real financial transactions under the same trust boundary.
The skill declares capabilities that imply environment access, filesystem writes, and network access, but it does not define an explicit tool scope such as permissions or allowed-tools. That omission weakens least-privilege controls and makes it harder for reviewers or enforcement layers to constrain what the skill can access if the implementation changes or is misused.
The activation text uses broad, common shopping-analysis phrases that may cause the skill to trigger unintentionally in unrelated conversations. Overbroad triggering can lead to unnecessary network calls, paid API consumption, and unexpected handling of user data in contexts where the user did not intend to invoke this skill.
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.
## Core Concepts
- Call only `${LINKFOX_TOOL_GATEWAY}/mercado/productSelection`. Do not call the upstream XP-MCP server directly, and do not ask the user for upstream `secret-key` / `X-API-Key` — upstream credentials are owned by the backend.
- The request body is always `{"toolName":"...","arguments":{...}}`. The script takes this whole object as a single JSON argument.
- Field names inside `arguments` must match `references/mercado-tool-reference.md` exactly, including camelCase names such as `siteId`, `itemId`, `productId`, `categoryId`, `runDate`, `runMonth`, `pageNo`, `pageSize`.
- Read `data` first when presenting results. Read `contentText` when `data` is text or ambiguous. Show `rawResponse` only when the user asks for raw diagnostics.
The skill instructs persistent storage of full API responses into the project directory but does not clearly warn users about local retention or privacy implications. Persisting potentially sensitive commercial, account, or usage data without prominent disclosure increases the risk of unintended exposure to other tools, collaborators, backups, or source control.
Mandating persistent local storage of complete responses in a session-organized directory creates a built-in data retention surface that can leak information over time. Even if the API data is not inherently secret, session grouping and raw response retention can reveal user interests, usage patterns, account details, and other metadata to anyone with filesystem access.
标题与整体说明直接以中文“参考”“调用规范”等形式呈现,未说明这是可选语言,也未提供其他语言选项。根据语言/locale 政策,若技能文档或指引默认强制特定语言而无用户 opt-in,属于自然语言层面的策略风险。
The documentation states that responses are automatically written to disk and cached for 24 hours, with small responses fully printed and larger ones summarized, but it does not require sanitization, encryption, access controls, or operator warnings. Because API responses may contain business-sensitive query results, comments, usage information, or other user-supplied content, local persistence can create unintended data exposure on shared hosts, developer machines, or CI environments.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
输出策略:响应体 ≤ 8 KB 时落盘后全量打印;> 8 KB 时落盘后只打印摘要(顶层字段、total/costToken 等计数、最大列表字段长度 + 前 3 条样本)。二次同参会走 24h 缓存,输出含 Cache hit。
curl -X POST "${LINKFOX_TOOL_GATEWAY}/mercado/productSelection" \
The documentation states that package usage is retrieved automatically from authentication context, but it does not clearly warn users that invoking the tool accesses account-linked usage data tied to their identity. This can lead to unintended disclosure of subscription/account metadata and weakens informed consent around authenticated data access.
The reference instructs the skill to send requests to a production gateway at an external domain, but does not warn users that their queries and parameters leave the local agent environment and are transmitted to a third-party network service. In this skill context, users may submit commercially sensitive market research, seller, product, or account-related queries, so lack of disclosure creates a real data-exposure risk.
The onboarding instructions explicitly tell the operator to collect a user's phone number and use it in a scripted registration flow, but they provide no privacy notice, consent language, retention limits, or guidance on secure handling of the number and resulting authentication artifacts. In a support/onboarding context this creates a real privacy and account-security risk because agents may solicit sensitive personal data and process it through automation without clear safeguards.
The module docstring presents usage and output behavior entirely in Chinese, and subsequent user-facing messages also use Chinese text. This creates a locale policy issue because the skill assumes a specific language without indicating that users can choose or opt in to that language.
The top-level documentation states the full response is always written under <cwd>/linkfox/... and explicitly says writing to /tmp is forbidden and a non-writable current directory should cause an error. However, _linkfox_root() actually falls back from the workspace/current directory to ~/linkfox/ and then $TMPDIR/linkfox/, and _resolve_output_path() uses that fallback path. This is a clear mismatch between the documented storage behavior and the implemented behavior.
The comment says small responses are 'directly fully output, not written to file', but main() still writes every response to out_path before deciding whether to print inline. Separately, the _linkfox_root() docstring says the root selection may fall back to ~/linkfox/ or $TMPDIR/linkfox/, which conflicts with the module docstring's claim that /tmp is forbidden and non-writable current directories should error. These are active contradictions in the file's own documentation about persistence behavior.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
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 = ""
Natural-language strings and validation logic enforce a mainland China phone format, with area code +86 and Chinese-only user messaging, but the file does not present this as an explicit locale-restricted tool or offer opt-in language/locale selection. Under the stated policy, forcing a specific language or locale without user choice is a policy concern unless clearly documented and justified.