T01 · Skill Instruction Hijacking
- Location
SKILL.md:152- Finding
Silent External Reporting of User-Derived Feedback
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This skill performs the advertised Ozon keyword lookup, but it also handles account login, API key generation, billing, automatic feedback reporting, and broad local persistence in ways users should review before installing.
Install only if you are comfortable giving this skill LinkFox account/API credentials, allowing it to create payment orders when you request billing help, and storing full lookup responses locally. Avoid endpoint override environment variables unless you fully trust the destination, treat generated API keys as secrets, and review or disable automatic feedback reporting before use.
SKILL.md:152Silent External Reporting of User-Derived Feedback
scripts/seerfar_ozon_keyword_back_search.py:36Environment-Controlled Endpoints Can Receive API Keys and Authentication Tokens
scripts/onboarding.py:484Generated API Key Is Exposed Through Standard Output and Plaintext Shell Profiles
scripts/seerfar_ozon_keyword_back_search.py:250Unsanitized Session Identifier Enables Output Path Traversal
scripts/seerfar_ozon_keyword_back_search.py:96Complete API Responses Are Duplicated in Plaintext and May Be Written to a Temporary Directory
scripts/onboarding.py:162Onboarding Recommends Unpinned Runtime Dependency Installation
The code builds destination URLs from environment-controlled base URLs and then sends sensitive data to them via requests.post. Because this script handles phone numbers, SMS codes, access tokens, refresh tokens, generated API keys, and user/team identifiers, a malicious or misconfigured environment can redirect authentication traffic to an attacker-controlled server and exfiltrate credentials.
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 request path uses a Request/urlopen flow where the base URL is also taken from environment variables, while attaching the Authorization API key header. This creates an SSRF/credential-exfiltration primitive: an attacker controlling the runtime environment can redirect paid account, package, and order requests to an arbitrary server and capture the API key and business data.
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 request headers and destination are influenced by environment variables, including LINKFOX_TOOL_GATEWAY and multiple metadata headers, and the code sends the API key to whatever base URL is configured. In an agent/runtime context where environment variables may be attacker-controlled or less trusted than hardcoded configuration, this can exfiltrate the credential and request data to an arbitrary endpoint via SSRF-like redirection.
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 documented purpose is SKU-based Ozon keyword reverse lookup, but the skill also describes account login, SMS verification, API key generation, subscription management, payment order creation, payment-status polling, and QR-code file generation. This is a major capability expansion into authentication and billing flows, creating risk of credential handling, unauthorized purchases, privacy exposure, and user deception because the real behavior is materially broader than advertised.
Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.
3. **Split organic vs ad with `type`**: pass `["0"]` or `["1"]` to focus a listing-optimization pass (organic) or an ads pass (ad), then bound `naturalRank` / `adRank` to qualify positioning — these filter on the values surfaced in each row's `dimension`.
4. **Use `includeKeywords` / `excludeKeywords` to steer**: force in must-have modifiers and strip noise without running a second query.
## Display Rules
1. **Present data only**: show reverse-looked-up keyword metrics in a clear table without subjective advice.
2. **Lead with keyword columns**: `query` / `queryCn` (Chinese translation), then `searchVolume`, `count30GrowthRate`, `productCount`, `sellers`, `avgPrice`; show `dimension.naturalRank` and `dimension.type` (organic/ad) to convey how the SKU ranks for each term.
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
The file implements an onboarding, login, token-issuance, and billing CLI even though the declared skill is for Ozon SKU reverse keyword search. This mismatch is dangerous because it expands the skill's privilege and data-collection scope far beyond user expectations, increasing the risk of credential harvesting and unauthorized account/payment actions under the guise of unrelated functionality.
This code actively performs SMS login, retrieves user/team metadata, generates API tokens, and supports ordering and payment flows instead of keyword analysis. In the context of a search-analytics skill, these capabilities are unjustified and materially increase the chance of deceptive credential collection, token minting, and unauthorized monetization workflows.
The skill appears to require environment access, file writes, and network calls but declares no explicit tool scope or permissions boundary. In an agent setting, missing scope declarations weakens least-privilege controls and can allow a nominally narrow analytics skill to access broader local or remote resources than users expect.
The skill instructs the agent to always persist full API responses to local session-organized files by default, and the schema explicitly includes user-linked fields such as uId and memberId. Default full-response logging increases the chance of retaining sensitive business data, identifiers, or account-linked metadata longer than necessary, especially when written into the working directory where other tools or users may access it.
The display rules explicitly require showing queryCn as a Chinese translation and frame output behavior around Chinese-language presentation, while the document as a whole mixes languages. There is no opt-in or user-choice mechanism for language/locale, which can violate a policy requiring language selection rather than forcing one locale.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
}
## curl 示例
```bash
curl -X POST https://tool-gateway.linkfox.com/seerfar/ozon/keywordBackSearch \
The onboarding flow explicitly instructs the agent to collect a user's phone number and use a local script to send verification codes and register/log in, but it provides no privacy notice, consent language, retention limits, or handling safeguards for that personal data. This creates a real privacy and security risk because users may be prompted to disclose sensitive contact information to an agent-mediated workflow without clear disclosure of how the number is used, stored, or protected.
The module docstring and all user-facing CLI help/messages are written in Chinese, which imposes a specific language on users. The file does not offer any language selection, fallback, or justification that this is a China-specific or Chinese-only tool.
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 = ""
Embedding order creation, payment URL handling, and QR-code rendering in a keyword reverse-search skill is not justified by the declared business purpose. This creates an unnecessary payment surface that could be abused for deceptive charging, phishing-like payment redirection, or social engineering, especially when paired with the broader skill-purpose mismatch.
The documentation explicitly says writing to /tmp is forbidden and an unwritable current directory should cause an error, but the implementation falls back to home and temporary directories. This mismatch can cause sensitive API results and session metadata to be written into less controlled locations, including shared temporary storage, undermining operator expectations and data-handling guarantees.
The manifest describes a skill for reverse-looking up Ozon/Wildberries search keywords by SKU and returning market-profile data. Lines L260-L280 document an additional POST capability to submit feedback to a different external endpoint, which is not necessary to perform keyword back search itself and represents an extra network-facing capability outside the stated user-facing purpose.
The script persistently writes full API responses, cache entries, and session metadata to local storage even though the skill description is focused on keyword reverse-search and does not disclose durable local retention. These responses may contain commercially sensitive search intelligence, user query data, identifiers, or account-scoped results, creating unnecessary data-at-rest exposure.
The comment for SMALL_THRESHOLD says responses at or below the threshold are output directly and not written to a file. In main, the script always resolves an output path and writes the serialized response before deciding whether to print full JSON or only a summary.
_resolve_output_path documents a fixed <cwd>/linkfox/... destination, yet it delegates to resolve_data_path, which uses _linkfox_root; that function may choose ACPX_WORKSPACES, the home directory, or the temp directory instead. This is an active contradiction about where data is stored.