Back to skill

Security audit

Shopee-店铺FBS

Security checks for vulnerabilities and agentic risk

Overview

The skill performs the advertised Shopee Brazil FBS queries, but it also includes sensitive account onboarding, API-key generation, billing/order flows, and unsafe credential/storage handling that users should review before installing.

Install only if you trust LinkFox with Shopee shop data, LinkFox account credentials, phone/SMS onboarding, and possible billing/order actions. Use a clean environment with official LinkFox endpoint variables only, avoid running payment/order commands unless you explicitly intend to buy credits, and treat saved response files and printed API keys as sensitive secrets.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/_shopee_fbs_common.py:18
Finding

Credential-Bearing Requests Can Be Redirected to Untrusted Endpoints

Content
View full analysis

Vulnerability Details

File Location: scripts/_shopee_fbs_common.py:18-20, 71-88; scripts/onboarding.py:68-85, 190-222, 225-246, 365-421, 454-461
Vulnerability Type: Unvalidated credential endpoint configuration
Risk Level: High

Vulnerable Code

scripts/_shopee_fbs_common.py:18-20, 71-88:

python
API_BASE_URL = os.environ.get("LINKFOX_TOOL_GATEWAY") or os.environ.get("SHOPEE_API_BASE_URL") or "https://tool-gateway.linkfox.com"
STORE_TOKENS_ENDPOINT = f"{API_BASE_URL.rstrip('/')}/shopee/storeTokens"
DEVELOPER_PROXY_ENDPOINT = f"{API_BASE_URL.rstrip('/')}/shopee/developerProxy"

def call_api(endpoint: str, params: dict) -> dict:
    api_key = get_api_key()
    data = json.dumps(params).encode("utf-8")
    req = Request(
        endpoint,
        data=data,
        headers={
            "Authorization": api_key,
            "Content-Type": "application/json",
            "User-Agent": "LinkFox-Skill/1.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", ""),
        },
        method="POST",
    )
    try:
        with urlopen(req, timeout=150) as response:
            return json.loads(response.read().decode("utf-8"))

scripts/onboarding.py:68-85, 190-222:

python
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.linkfox.com")

def _agent_user_base() -> str:
    return _env_base("LINKFOX_AGENT_USER_API
...[truncated 3899 chars]
Remediation
View remediation

Remediation Suggestions

  1. Require https for every credential-bearing endpoint.
  2. Allowlist exact production hostnames such as tool-gateway.linkfox.com, api.linkfox.com, and agent-api.linkfox.com.
  3. Reject URLs containing embedded credentials, unexpected ports, fragments, or nonempty user-information components.
  4. Resolve and validate the final destination after redirects, or disable redirects for requests carrying credentials.
  5. Remove production endpoint overrides unless they are operationally necessary.
  6. If custom development endpoints are required, require an explicit development-mode flag and separate test credentials. Do not forward production credentials by default.
  7. Avoid sending SESSION_ID, MESSAGE_ID, MODE_ID, and APP_NAME unless each field is required by the server.
  8. Add tests proving that HTTP URLs, unapproved hosts, malformed URLs, and redirects to unapproved hosts are rejected before any sensitive request is sent.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/_shopee_fbs_common.py:216
Finding

Unsanitized SESSION_ID Enables Path Traversal and Writes Outside the Intended Storage Root

Content
View full analysis

Vulnerability Details

File Location: scripts/_shopee_fbs_common.py:216-223, 315-329; scripts/onboarding.py:153-159
Vulnerability Type: Path traversal and arbitrary-location file write
Risk Level: High

Vulnerable Code

scripts/_shopee_fbs_common.py:216-223, 315-329:

python
def _lf_session_id(ts: float) -> str:
    env = os.environ.get("SESSION_ID")
    if env:
        return env.strip()
    if "_auto" not in _LF_SESSION_CACHE:
        _LF_SESSION_CACHE["_auto"] = (
            _lf_time.strftime("%H%M%S", _lf_time.localtime(ts)) + "-" + _lf_secrets.token_hex(3)
        )
    return _LF_SESSION_CACHE["_auto"]

def emit_result(result, slug=SLUG, inline=False):
    serialized = json.dumps(result, ensure_ascii=False, indent=2)
    ts = _lf_time.time()
    date_str = _lf_time.strftime("%Y-%m-%d", _lf_time.localtime(ts))
    sid = _lf_session_id(ts)
    root = _lf_root()
    session_dir = os.path.join(root, date_str, sid)
    os.makedirs(session_dir, exist_ok=True)
    _lf_ensure_meta(root, session_dir, date_str, sid, ts)
    data_dir = os.path.join(session_dir, "data")
    os.makedirs(data_dir, exist_ok=True)
    out = os.path.join(data_dir, f"{slug}-{int(ts * 1_000_000)}.json")
    try:
        with open(out, "w", encoding="utf-8") as f:
            f.write(serialized)

scripts/onboarding.py:153-159:

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 comes from the process environment. It is passed directly to os.path.join without rejecting absolute paths, parent ...[truncated 2131 chars]

Remediation
View remediation

Remediation Suggestions

  1. Validate SESSION_ID against a strict bounded pattern, for example [A-Za-z0-9_-]{1,64}.
  2. Reject empty values, dots, path separators, drive prefixes, absolute paths, control characters, and parent-directory components.
  3. Resolve the intended root and final session path with Path.resolve().
  4. Verify that the resolved session path is a descendant of the resolved root before creating directories or files.
  5. Apply the same validation helper in both _shopee_fbs_common.py and onboarding.py.
  6. Avoid following symbolic links when creating sensitive output where supported, and reject an existing session path if it is a symbolic link.
  7. Create session directories with restrictive permissions and output files with mode 0600.
  8. Add security tests for absolute Unix paths, Windows drive paths, UNC paths, ../ traversal, nested traversal, encoded separators, long values, and symbolic-link escape attempts.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/_shopee_fbs_common.py:187
Finding

Sensitive API Responses May Be Persisted in Undocumented Home or Temporary Directories

Content
View full analysis

Vulnerability Details

File Location: scripts/_shopee_fbs_common.py:187-205, 315-330; documentation conflict at SKILL.md:17
Vulnerability Type: Unsafe sensitive-data storage and documentation mismatch
Risk Level: Medium

Vulnerable Code

scripts/_shopee_fbs_common.py:187-205:

python
def _lf_root() -> str:
    cached = _LF_SESSION_CACHE.get("_root")
    if cached:
        return cached
    candidates = []
    acpx = (os.environ.get("ACPX_WORKSPACES") or "").strip()
    if acpx:
        acpx = acpx.split(os.pathsep)[0].strip()
        if acpx:
            candidates.append(os.path.join(acpx, "linkfox"))
    candidates.append(os.path.join(os.getcwd(), "linkfox"))
    candidates.append(os.path.join(os.path.expanduser("~"), "linkfox"))
    candidates.append(os.path.join(_lf_tempfile.gettempdir(), "linkfox"))
    for root in candidates:
        try:
            os.makedirs(root, exist_ok=True)
            probe = os.path.join(root, ".write_probe")
            with open(probe, "w", encoding="utf-8") as f:
                f.write("")
            os.remove(probe)
        except OSError:
            continue
        root = os.path.abspath(root)
        _LF_SESSION_CACHE["_root"] = root
        return root

scripts/_shopee_fbs_common.py:315-330:

python
def emit_result(result, slug=SLUG, inline=False):
    """落盘完整响应到 linkfox/<date>/<session>/data/<slug>-<ts>.json;大响应只打印摘要。无缓存。"""
    serialized = json.dumps(result, ensure_ascii=False, indent=2)
    ts = _lf_time.time()
    date_str = _lf_time.strftime("%Y-%m-%d", _lf_time.localtime(ts))
    sid = _lf_session_id(ts)
    root = _lf_root()
    session_dir = os.path.join(root, date_str, sid)
    os.makedirs(session_dir, exist_ok=True)
    _lf_ensure_meta(root, session_dir, date_str, sid, ts)
    data_dir = os.path.join(session_dir, "data")
    os.makedirs(data_dir, exist_ok=True)
    out = os.path.
...[truncated 2469 chars]
Remediation
View remediation

Remediation Suggestions

  1. Enforce the documented current-working-directory-only storage policy and fail closed if that directory is not writable.
  2. If fallback locations are required, disclose them clearly and require explicit user consent before storing sensitive responses there.
  3. Do not use the system temporary directory for persistent complete API responses.
  4. Create directories with restrictive permissions and files with mode 0600, independent of the ambient umask where possible.
  5. Add configurable retention limits and a secure cleanup command.
  6. Minimize stored data by removing authorization material, unnecessary raw proxy fields, and sensitive fields not required for the declared output.
  7. Provide an option to disable persistence or to store only a redacted summary.
  8. Report the selected storage root before the request is made, rather than only after data has been written.
  9. Align SKILL.md with actual behavior and add tests ensuring that prohibited fallback paths are never selected.
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
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
Findings (28)

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

Critical
Category
Data Flow
Confidence
90% confidence
Finding

The code sends sensitive headers derived from environment variables, including an API key and session metadata, to a network endpoint whose base URL is also taken from environment variables. If LINKFOX_TOOL_GATEWAY or SHOPEE_API_BASE_URL is tampered with, the skill can exfiltrate credentials and session identifiers to an attacker-controlled server.

Content

Scanner excerpt · scripts/_shopee_fbs_common.py (reported line 88)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 sends authentication tokens and other sensitive request data to URLs whose base hosts are taken directly from environment variables. If those variables are altered in the runtime environment, the skill can be redirected to attacker-controlled endpoints, causing API keys, login tokens, phone numbers, SMS codes, and account metadata to be exfiltrated. This is more dangerous in this skill because it already handles onboarding and credential-generation flows unrelated to the declared Shopee FBS read-only 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 request path uses a Request built from a base URL derived from environment variables and attaches the LinkFox API key in the Authorization header. An attacker who can influence the environment can redirect these requests to an arbitrary server and harvest the API key or manipulate downstream commerce/account actions. In the context of a Shopee FBS status-query skill, this hidden generic gateway behavior is especially unjustified and expands the blast radius.

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

If the linked behavior truly includes SMS login, API key issuance, account lookup, plan purchase, payment order creation, and QR rendering, that is a major expansion beyond a Shopee FBS status-query skill. Such hidden account-management and payment capabilities can lead to unauthorized billing actions, credential issuance, and handling of sensitive user identity/payment data under misleading pretenses.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

If the linked behavior truly includes SMS login, API key issuance, account lookup, plan purchase, payment order creation, and QR rendering, that is a major expansion beyond a Shopee FBS status-query skill. Such hidden account-management and payment capabilities can lead to unauthorized billing actions, credential issuance, and handling of sensitive user identity/payment data under misleading pretenses.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding

If the linked behavior truly includes SMS login, API key issuance, account lookup, plan purchase, payment order creation, and QR rendering, that is a major expansion beyond a Shopee FBS status-query skill. Such hidden account-management and payment capabilities can lead to unauthorized billing actions, credential issuance, and handling of sensitive user identity/payment data under misleading pretenses.

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 file implements account onboarding, SMS login, API key issuance, package discovery, ordering, and payment support, none of which are necessary for the manifest's narrow Shopee FBS query function. Such capability mismatch is a strong sign of over-privileged or deceptive behavior: users invoking a store-status skill could unknowingly trigger credential collection and unrelated account operations. The mismatch makes the skill materially more dangerous because the hidden functionality touches authentication and billing surfaces.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The code creates orders and renders payment QR codes, introducing real commerce actions into a skill that should only query Shopee FBS enrollment/block/invoice status. This creates an unauthorized path for charging users or steering them into unrelated purchases, which is highly suspicious given the declared read-only business purpose. The context sharply increases severity because there is no legitimate reason for a Shopee FBS query helper to contain payment workflows.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The skill performs SMS-based login and API token generation for LinkFox accounts, which is outside the manifest's stated Shopee FBS query-only scope. This behavior collects sensitive authentication factors and returns newly generated API keys, creating a direct credential-harvesting and privilege-enablement path unrelated to the advertised functionality. In this context, the mismatch is a major red flag rather than an implementation detail.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
86% confidence
Finding

The skill advertises shell, network, environment-variable access, and file writes, but does not declare any explicit tool scope such as allowed-tools or permissions. That creates an authority gap where the runtime may grant broader capabilities than users or reviewers expect, increasing the chance of unintended data access, local file modification, or outbound requests during routine use.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The trigger conditions are broad enough to fire on general Shopee Brazil shop-status discussions even when the user did not intend to query this specific FBS skill. Overbroad invocation can cause unnecessary access to authorized shop data, accidental API calls, or execution of scripts with file/network side effects in contexts where they are not needed.

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 39)May include surrounding context.


curl 示例

bash
curl -X POST https://tool-gateway.linkfox.com/shopee/developerProxy \

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

This markdown skill description forces a specific language for all instructions and examples, which can violate language/locale policy when no user opt-in or justification is provided. Although the API concerns Brazil enrollment status, the file does not state that Chinese is required or offer alternative language support.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The skill explicitly instructs collection of a user's phone number and use of a script to send the number and later a verification code for account registration, but it does not require a clear user-facing privacy notice, consent flow, or data-handling disclosure. This creates privacy and compliance risk because users may be prompted to disclose personal data to an automated workflow without being told what is transmitted, stored, or retained.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The skill's stated purpose is to query Shopee Brazil FBS enrollment, invoice-error, and block-status information through a proxy API. In addition to that, the helper launches another local script with subprocess.run to verify a dependency skill. Spawning a subprocess is not an obvious or declared requirement for an API-query skill and introduces extra execution capability unrelated to the user-facing FBS query intent.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/_shopee_fbs_common.py (reported line 37)May include surrounding context.

python
print(f"DEPENDENCY_MISSING: {json.dumps(payload, ensure_ascii=False)}", file=sys.stderr)
        sys.exit(DEPENDENCY_EXIT_CODE)
    try:
        result = subprocess.run(
            [sys.executable, str(checker)],
            capture_output=True,
            text=True,

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The helper persistently writes full API responses to local disk under a session directory, which exceeds the stated purpose of making FBS status queries. Those responses may contain shop/account details, operational data, or tokens returned by upstream APIs, creating unnecessary data retention and local disclosure risk.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

emit_result serializes and stores complete API responses to disk without filtering sensitive content or warning the user. Because this skill interacts with token resolution and developer proxy flows, saved payloads may include access tokens, shop identifiers, invoice/error data, or other account-linked information that can later be read from the filesystem.

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

The natural-language help and validation logic restrict the workflow to 11-digit domestic phone numbers and force area code +86. This imposes a locale-specific constraint without user opt-in or documented justification in the file, which matches the language/locale policy-violation category.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The login command emits the generated API key directly to stdout as JSON. In agent, CI, terminal-history, orchestration, or logging environments, stdout is commonly captured, persisted, or exposed to other tools, which can leak reusable credentials without the user's awareness. This is more dangerous here because the skill is already performing unjustified credential generation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
64% confidence
Finding

The natural-language description repeatedly constrains the skill to Brazil/BR contexts, including automatic triggering for Shopee Brazil store queries. While region-specific behavior can be acceptable, the file does not explicitly frame this as a user-selected or compliance-justified locale restriction.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

This markdown file presents all operational instructions and API descriptions in Chinese only. Under the language/locale policy rule, forcing a single language without user opt-in can be a natural-language policy issue when no justification or alternative is provided.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

Natural-language strings and docstrings are written in Chinese, including operational guidance for authentication handling, with no indication that another language is available. This can violate a language/locale policy when a skill imposes a specific language on users without opt-in or documented regional justification.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.