Back to skill

Security audit

MPSTATS-Ozon品牌商品查询

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly performs the advertised Ozon analytics task, but it also includes sensitive onboarding, payment, credential handling, persistent storage, and automatic feedback reporting that need human review before installation.

Review this skill before installing. Use it only if you are comfortable sending Ozon brand queries and account credentials to LinkFox services, paying for credits through its onboarding flow, and storing returned analytics data locally. Avoid endpoint override environment variables unless you control the runtime, and prefer secure secret storage over putting API keys in shell startup files.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • 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)

T01 · Skill Instruction Hijacking

Error
Location
SKILL.md:164
Finding

Automatic External Feedback Submission Without Explicit User Consent

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/mpstats_ozon_brand_products.py:40
Finding

Sensitive Credentials Can Be Redirected to Arbitrary Endpoints

Content
View full analysis
str: """网关基础地址:env LINKFOX_TOOL_GATEWAY 优先,缺省回退正式地址。""" 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 ``` ```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 client similarly permits unrestricted overrides: ```python 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") ``` Sensitive tokens are then sent to the selected origin: ```python def _login_by_token(access_token: str, refresh_token: str) -> dict: """新用户送算力。失败不阻断。""" resp = _http_post(f"{_agent_user_base()}/account/loginByToken", { "token": access_token, "refreshToken": refresh_token, "device": {"aid": "3026344186", "did": "", "type": "Wi ...[truncated 2300 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/onboarding.py:491
Finding

API Key Is Printed to Standard Output and Recommended for Plaintext Persistence

Content
View full analysis
None: print(json.dumps(obj, ensure_ascii=False, indent=2)) 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} 成功获取 API key(来源: {r['source']})", file=sys.stderr) return 0 return 1 ``` The onboarding guide recommends plaintext persistence: ```bash setx LINKFOX_AGENT_API_KEY "" echo 'export LINKFOX_AGENT_API_KEY=""' >> ~/.zshrc && source ~/.zshrc echo 'export LINKFOX_AGENT_API_KEY=""' >> ~/.bashrc && source ~/.bashrc ``` ### Technical Analysis Standard output is frequently captured by Agent transcripts, terminal scrollback, CI logs, process wrappers, debugging systems, and support tooling. Returning the complete API key through stdout therefore creates multiple unintended copies of a long-lived credential. The recommended shell commands introduce further exposure: - The secret may be retained in shell history. - Startup files store the key in plaintext. - Startup files may be included in backups or diagnostic archives. - Other processes running under the same user may read environment variables. - Overly permissive file modes may expose the key to other local users. The account onboarding workflow legitimately needs ...[truncated 1132 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/mpstats_ozon_brand_products.py:235
Finding

Unsanitized Session Identifier Permits Output Path Traversal

Content
View full analysis
str: """优先 env SESSION_ID;缺省按 HHMMSS-<6 hex> 生成(同一进程内稳定)。""" 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"] ``` It is then joined into a writable path without containment validation: ```python def _ensure_session(ts: float) -> tuple[str, str]: """返回 (linkfox_root, session_dir);session_dir 一定存在。""" 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 onboarding script has the same pattern: ```python def session_dir() -> str: ts = time.time() 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) return path ``` ### Technical Analysis `SESSION_ID` is treated as a trusted directory name even though it originates from the process environment. Values containing `..`, path separators, or an absolute path can cause `os.path.join` and path normalization to escape the intended `linkfox//` hierarchy. Files subsequently placed under this directory can include: - `_meta.json` - ...[truncated 1503 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • System Prompt LeakageDirect Leakage, Indirect Extraction, Tool-Based Exfiltration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
Findings (23)

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

Critical
Category
Data Flow
Confidence
91% confidence
Finding

The outbound request includes multiple environment-derived headers and, more importantly, allows the destination base URL to be overridden via LINKFOX_TOOL_GATEWAY. That creates a server-side request/data exfiltration path: in a hostile or misconfigured runtime, sensitive metadata and the API key can be sent to an attacker-controlled endpoint instead of the intended gateway. In this skill context, the tool handles marketplace analytics but also carries authentication material, so redirectable egress is more dangerous than a normal API client pattern.

Content

Scanner excerpt · scripts/mpstats_ozon_brand_products.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 ""

Description-Behavior Mismatch

Critical
Category
Not specified by scanner
Confidence
99% confidence
Finding

The file implements a LinkFox onboarding, login, API-token generation, package purchase, and payment QR workflow, while the skill is described as Ozon brand-product analytics. This severe capability mismatch is dangerous because a user or orchestrator expecting marketplace analytics may instead be induced to disclose phone numbers, SMS codes, and payment actions to unrelated infrastructure.

Content

No source excerpt is available for this finding.

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, API keys, and payment/order data to those endpoints. If an attacker can influence the environment, this becomes credential exfiltration or SSRF-to-attacker infrastructure, and the risk is amplified because this file is an onboarding/payment flow unrelated to the advertised MPSTATS analytics purpose.

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 URL is derived from environment variables and used in urllib requests with the Authorization header populated from the agent API key. An attacker who controls the runtime environment can redirect these requests to a malicious host and capture the API key or force requests to unintended internal/external services; the mismatch with the declared skill intent makes this especially suspicious.

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

The skill is presented as product analytics, yet static analysis indicates additional account and payment workflows such as SMS login, API key generation, package listing, order creation, and payment QR generation/status checks. Hidden authentication and payment capabilities are highly sensitive because they can collect user phone numbers, initiate billing flows, or manipulate credentials far beyond the user's apparent intent.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The skill is presented as product analytics, yet static analysis indicates additional account and payment workflows such as SMS login, API key generation, package listing, order creation, and payment QR generation/status checks. Hidden authentication and payment capabilities are highly sensitive because they can collect user phone numbers, initiate billing flows, or manipulate credentials far beyond the user's apparent intent.

Content

No source excerpt is available for this finding.

Direct Prompt Extraction

High
Category
System Prompt Leakage
Confidence
85% confidence
Finding

Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Content

Scanner excerpt · SKILL.md (reported line 119)May include surrounding context.

}

text

## Display Rules

1. **Compact brand table** — key columns: `productId`, `title`, `price`, `monthlySalesUnits`, `monthlySalesRevenue`, `rating`, `reviewCount`, `balance`, `turnoverDays`, `lostProfit`.
2. **Revenue share context** — `revenueSharePercent` is the SKU's share **within this brand result set**, 0-100; clarify the base when presenting.

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

Intent-Code Divergence

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The docstring promises writes only under the current working directory and explicitly forbids /tmp, but the implementation silently falls back to home-directory and temporary-directory storage. That mismatch is security-relevant because operators and higher-level agents may rely on the documented storage boundary, while actual behavior can place sensitive API output in less controlled or unexpected locations, increasing accidental disclosure risk.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The module docstring openly states that this is a self-contained account/environment onboarding CLI with commands for login, plan listing, ordering, and payment status, which directly contradicts the manifest’s Ozon analytics intent. That contradiction is a strong indicator of deceptive packaging and raises the likelihood that the skill could trick users or the platform into running unrelated sensitive workflows.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

This section performs SMS login, token exchange, user-info retrieval, API key generation, and related account bootstrap actions that are unrelated to brand-product analytics. In the context of a data-analysis skill, such credential and payment-enablement logic creates a high-risk phishing/provisioning vector and expands the blast radius from analytics to full account compromise and monetized actions.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding

The skill exposes capabilities to read environment variables, write files, and access the network without declaring any explicit tool scope or permission boundaries. In an agent setting, this weakens least-privilege controls and makes it harder for reviewers and policy systems to constrain what the skill can do, increasing the chance of secret access or unintended persistence.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The trigger rules are broad enough to activate the skill even when the user does not explicitly request MPSTATS or this specific integration. Over-broad invocation can cause unintended external calls, unnecessary cost, and disclosure of user queries to a third-party service when a narrower or different tool would have been more appropriate.

Content

No source excerpt is available for this finding.

Ssd 3

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The skill instructs the agent to always write full API responses into a session-scoped directory under the current project. Persistent storage of complete responses can retain sensitive business data, query context, and identifiers beyond the immediate task, and writing into the project workspace can expose that data to other tools, users, commits, or later sessions.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% 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 · references/api.md (reported line 130)May include surrounding context.

| 402 | 算力或余额不足 | HTTP 402:按 SKILL.md 的 ## 解决认证和算力问题 处理。 | | 其他 | 业务异常 | 查看 errmsg;常见为 brandName 拼写错误、日期越过昨日等 |

curl 示例

bash
curl -X POST https://tool-gateway.linkfox.com/mpstats/ozon/brandProducts \

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The onboarding flow instructs users to provide a phone number to a local script and to persist the returned API key in shell startup files, but it does not disclose the privacy and security implications of either action. This can lead to unintended collection/exposure of personal data and long-lived credential leakage via plaintext shell profiles, backups, shared accounts, or diagnostic logs.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The script caches and persists full API responses to local files, including session-associated analytics data and possibly error bodies or account-scoped information. This expands the data exposure surface beyond the stated read-only analytics behavior and can leak sensitive business intelligence to other local users, logs, backups, or later processes with filesystem access.

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

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill enforces an 11-digit phone number format and always submits areaCode '+86', which forces a specific locale/region behavior. There is no opt-in, alternate locale handling, or documented justification in this file that would exempt this restriction.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The login flow exchanges a phone number and SMS code for access tokens and then retrieves or generates an API key via multiple network calls. Although the module docstring describes the commands, this file does not include an in-code warning, confirmation, or explicit user-facing disclosure that sensitive authentication data and resulting credentials will be transmitted to remote services.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
79% confidence
Finding

This line directs a specific language/locale behavior for outputs: original Russian titles must be preserved unless the user asks for translation. That is a language-policy constraint embedded in natural language and does not explicitly offer a default user choice at presentation time.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

This limitation requires the agent to keep content in Russian unless the user specifically requests translation. Because it hard-codes a locale behavior rather than offering a language choice, it matches the language/locale policy concern described by SQP-3.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
82% confidence
Finding

The QR rendering path creates a PNG file on disk in a session directory, which is a file write affecting the local system. While the command name mentions QR rendering, the code does not provide an explicit warning or disclosure that a persistent file will be created under a workspace/home/temp path.

Content

No source excerpt is available for this finding.