Back to skill

Security audit

Temu商品查询

Security checks for vulnerabilities and agentic risk

Overview

This Temu product-query skill is mostly understandable, but it also handles account login, API keys, payments, and local response storage in ways that need careful review before installation.

Install only if you trust LinkFox and are comfortable with the agent using a LinkFox API key, sending Temu research queries to LinkFox services, and guiding account or billing recovery. Before use, avoid custom LINKFOX_* endpoint overrides unless they are trusted HTTPS LinkFox hosts, do not put OTPs or API keys in shared logs, rotate keys that may have been exposed, and review or delete the local linkfox cache/session files after sensitive searches.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/temu_product_query.py:36
Finding

API Key Disclosure Through an Unrestricted Gateway Override

Content
View full analysis
str: """Gateway base address: environment variable first, production address by default.""" 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 get_api_key(): key = ( os.environ.get("LINKFOX_AGENT_API_KEY") or os.environ.get("LINKFOXAGENT_API_KEY") ) if not key: print("API Key is not configured", file=sys.stderr) sys.exit(1) return key 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", ""), "MODE_ID": os.environ.get("MODE_ID", ""), "APP_NAME": os.environ.get("APP_NAME", ""), } req = Request( api_url, data=data, headers=headers, method="POST", ) ``` ### Technical Analysis The product-query destination is taken directly from `LINKFOX_TOOL_GATEWAY`. The script does not require HTTPS, validate the hostname, restrict ports, or compare the destination against a trusted-host allowlist. The API key is subsequently placed in the `Authorization` header and sent to that destination. Product-query parameters and host metadata—including `SESSION_ID`, `MODE_ID`, and `APP_NAME`—are transmitted in the same request. This network access is necessa ...[truncated 1396 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/onboarding.py:70
Finding

Authentication Tokens and SMS Credentials Can Be Redirected to Arbitrary API Hosts

Content
View full analysis
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_URL", "https://agent-api.linkfox.com", ) ``` ```python def _http_post(url: str, body: dict, headers: dict, timeout: int = 30) -> dict: try: _require_requests() 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 = "" resp = getattr(e, "response", None) if resp is not None: try: body_text = resp.text[:500] except Exception: pass return {"_error": str(e), "_body": body_text} def _headers( source: str, origin_host: str, *, access_token: str = "", user_id: str = "", group_id: str = "", ) -> dict: h = { "Accept": "application/json, text/plain, */*", "Content-Type": "application/json;charset=UTF-8", "Origin": f"https://{origin_host}", "Referer": f"https://{origin_host}/", "source": source, "User-Agent": UA, } if access_token: h["authorizat ...[truncated 3854 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/onboarding.py:480
Finding

SMS Verification Codes and Generated API Keys Are Exposed Through Command-Line and Plaintext Output Channels

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: {code}", "phone": masked, } lg = _login_v3(phone, code, channel) if "error" in lg: return {"error": lg["error"], "phone": masked} # Additional onboarding operations omitted. 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), } ``` ```python def _emit(obj: dict) -> 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} successfully obtained API key " f"(source: {r['source']})", file=sys.stderr, ) return 0 return 1 ``` ```python p = sub.add_parser("login", help="Log in with a verification code") p.add_argument("phone") p.add_argument("code", help="SMS verification code") p.add_argument( "--channel", default="skill", help="Channel; defaults to skill", ) ``` The associated instructions direct users to run: ```bash python scripts/onboarding.py l ...[truncated 2029 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
scripts/onboarding.py:162
Finding

Unpinned Runtime Dependency Installation Creates a Supply-Chain Risk

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) ``` ```python def _require_requests() -> None: if requests is None: raise RuntimeError( "Missing requests dependency; run: pip install requests" ) ``` ### Technical Analysis The code instructs users to install `qrcode`, `pillow`, and `requests` without exact versions, hashes, a lockfile, or a specified trusted package index. Package resolution therefore depends on mutable external repository state and the user's pip configuration. A compromised package release, malicious configured index, dependency-confusion condition, or future incompatible version could introduce arbitrary code into the environment. Python packages can execute code during build or installation, and imported packages execute module initialization code. The risk is not limited to the functionality used by this Skill. ### Attack Path 1. The user runs onboarding in an environment where one or more dependencies are absent. 2. The script tells the user to execute an unpinned `pip install` command. 3. Pip resolves packages and transitive dependencies from the ...[truncated 806 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/temu_product_query.py:206
Finding

Unvalidated Session Identifier Permits Output-Path Escape and Insecure Data Persistence

Content
View full analysis
str: cached = _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")) import tempfile candidates.append( os.path.join(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) _SESSION_CACHE["_root"] = root return root ``` ```python def _session_id(ts: float) -> str: 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"] def _ensure_session(ts: float) -> tuple[str, str]: 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 ``` ```python result = call_api(params) serialized = json.dumps( result, ...[truncated 2552 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: '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 onboarding data, login tokens, and API-token workflow traffic to those endpoints via requests.post. In a skill setting, environment variables are part of the trust boundary; if an attacker or compromised host overrides these values, credentials, SMS login artifacts, and account context can be exfiltrated to an arbitrary server.

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 helper composes outbound URLs from environment-derived base addresses and then performs urlopen requests with the API key in the Authorization header. If those environment variables are attacker-controlled, the skill will disclose API credentials and potentially place authenticated requests against malicious infrastructure, enabling token theft and abuse of the linked account.

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

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

Critical
Category
Data Flow
Confidence
96% confidence
Finding

The script allows the destination host to be overridden by the LINKFOX_TOOL_GATEWAY environment variable and then sends the API key plus request payload and session/app metadata to that URL. In an agent environment where env vars may be influenced by a wrapper, workspace config, or untrusted execution context, this creates a credential exfiltration and sensitive-data egress path to an attacker-controlled endpoint.

Content

Scanner excerpt · scripts/temu_product_query.py (reported line 79)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 ""

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The declared purpose is product filtering, but the detected behavior extends into SMS OTP delivery, phone-based login, API key issuance, account/team access, subscription listing, payment order creation, QR-code payment flows, and payment-status checks. This is a serious trust-boundary violation because a user invoking a shopping/query skill would not reasonably expect identity, credential, billing, or payment operations to occur under the same skill surface.

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
证码后:`python scripts/onboarding.py login <phone> <code>`(workbuddy 宿主加 `--channel workbuddy`)
   - 拿到 `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

The file implements LinkFox account onboarding, SMS login, plan listing, order creation, payment QR rendering, and order querying, which is materially unrelated to the declared Temu product-query skill. This mismatch is dangerous because it expands the skill from data querying into account acquisition and payment operations, creating an opportunity for credential harvesting and unauthorized monetization under a misleading skill description.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The skill creates paid orders and renders payment QR codes, functionality unrelated to searching or filtering Temu products. This is dangerous because a user invoking a product-query skill would not reasonably expect purchase and payment initiation, increasing the risk of deceptive billing, social engineering, or unauthorized charges.

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 send SMS verification codes, log a user in with the received code, and obtain or generate an API key for the user's account. In the context of a Temu product-query skill, this capability is unjustified and highly dangerous because it enables account takeover-like flows, credential bootstrapping, and privilege-bearing token issuance outside the user’s expected task.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
84% confidence
Finding

The skill declares no explicit tool scope even though it appears to require environment access, file writing, and network access. Without least-privilege restrictions, a Temu product-query skill can gain broader execution capabilities than users would reasonably expect, increasing the blast radius if the skill is modified, compromised, or mis-triggered.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The activation conditions are broad enough to trigger on many ordinary Temu-related shopping requests, which raises the chance that this skill will run in contexts where the user did not intend to invoke it. In combination with the skill's broader-than-advertised capabilities and dynamic billing notes, over-triggering increases the risk of unintended network actions, account flows, or surprise point consumption.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The documentation instructs the skill to send user-supplied Temu search/filter data and an API key to an external LinkFox gateway, but it does not explicitly warn that these queries leave the local system and are transmitted to a third-party service. In agent contexts, users may provide commercially sensitive product research terms, store IDs, or business intelligence without realizing it will be disclosed externally, creating a privacy and data-handling risk.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The Feedback API sends free-form content to a separate external service, yet the documentation does not warn that user intent, outcomes, or other narrative details may be transmitted outside the primary tool flow. Because feedback text can easily contain personal data, confidential business context, or excerpts of prior conversations, the lack of an explicit privacy notice increases the chance of unintended disclosure.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The onboarding instructions direct the operator to collect and process a user's phone number and one-time verification code via a local script, but provide no privacy, consent, storage, masking, or least-retention guidance. In an agent setting, this creates a real risk of mishandling sensitive authentication data and can enable account takeover or privacy violations if logs, transcripts, or terminal history capture the values.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

This Python file uses Chinese-only natural-language descriptions, help text, and user-facing messages throughout the module docstring and CLI interface, which effectively imposes a specific language on all users. The file does not offer a language choice or explain that the skill is intentionally restricted to a Chinese-speaking or China-specific audience.

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

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The docstring promises that writing to /tmp is forbidden and that an unwritable current directory will cause an error, but the implementation silently falls back to the home directory or temporary directory. This mismatch can cause sensitive API responses to be persisted in locations with weaker isolation or broader accessibility than the operator expects, undermining data-handling guarantees.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The script sends user-supplied query parameters together with SESSION_ID, MODE_ID, and APP_NAME to a remote service without an execution-time disclosure or consent boundary. In this skill context, users may provide commercially sensitive product research criteria, and the extra metadata increases traceability and data exposure if the remote service or route is not fully trusted.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
82% confidence
Finding

All user-facing guidance in the file is presented only in Chinese, and there is no indication that the skill is region-specific or that users may choose another language. Under the stated policy, forcing a specific language without opt-in can be a natural-language policy violation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
81% confidence
Finding

The script reads LINKFOX_AGENT_API_KEY or LINKFOXAGENT_API_KEY from the environment and uses the value as an Authorization header. While this is functionally expected for authenticated API access, the file lacks a clear user-facing warning that running the script depends on and will use credentials from the environment.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
80% confidence
Finding

Beyond querying and returning Temu product data, the script persists request-derived cache files under linkfox/.cache and maintains session metadata structures such as _meta.json and index.jsonl. That local session/catalog bookkeeping is not reflected in the manifest's user-facing description of a multi-filter product query skill.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.