Back to skill

Security audit

社媒热搜助手

Security checks for vulnerabilities and agentic risk

Overview

The skill appears purpose-built for social-media hot-search analysis, but it automatically contacts a remote proxy, creates a persistent machine-linked identity, and allows implicit invocation without strong user control.

Install only if you are comfortable with social-media queries and topic terms being sent to the listed remote proxy, and with the skill creating a persistent local identity tied to a hash of your username and hostname. Avoid using it for confidential brand, PR, legal, or internal research terms unless the proxy operator and retention policy are acceptable to you.

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

other

Warning
Location
scripts/social_client.py:39
Finding

Stable Host Fingerprint Is Unnecessarily Collected and Repeatedly Transmitted

Content
View full analysis
str: raw = f"{getpass.getuser()}@{socket.gethostname()}" return hashlib.sha256(raw.encode("utf-8")).hexdigest()[:24] ``` ```python def ensure_user() -> dict[str, Any]: """Load or create user_id. Returns full user record from server.""" cached = load_user() fp = machine_fingerprint() resp = _post_json("/v1/register", {"machine_fingerprint": fp}) user_id = resp["user_id"] record = { "user_id": user_id, "machine_fingerprint": fp, "is_new": resp.get("is_new", False), } save_user(record) return {**record, **resp} ``` ### Technical Analysis The Skill reads the current operating-system username and hostname and combines them into a persistent machine fingerprint. Although the resulting value is hashed, usernames and hostnames often have limited entropy and predictable formats. An operator with candidate values may therefore enumerate likely combinations and compare their truncated SHA-256 hashes. This collection exceeds the minimum local access required to query social-media data. Quota management could instead use a cryptographically random identifier generated locally without inspecting host identity information. The implementation also loads the cached registration record but never uses it. Consequently, every normal tool invocation calls `ensure_user()`, regenerates the fingerprint, and sends it to the external `/v1/register` endpoint even when registration has already occurred. The fingerprint permits calls from the same username-host combination to be correlated over time. Only the hash is transmitted by the audited code; there is no evidence that the raw username or hostname is sent directly. ### Attack Path 1. A user invokes `que ...[truncated 1256 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Note
Location
scripts/social_client.py:129
Finding

Bearer-Style User Identifier Is Persisted Without Enforced File Permissions

Content
View full analysis
None: USER_FILE.parent.mkdir(parents=True, exist_ok=True) USER_FILE.write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding="utf-8") ``` The persisted identifier is later used as a bearer authorization value: ```python record = { "user_id": user_id, "machine_fingerprint": fp, "is_new": resp.get("is_new", False), } save_user(record) ``` ```python def get_usage(user_id: str) -> dict[str, Any]: return _get("/v1/usage", headers={"Authorization": f"Bearer {user_id}"}) ``` ```python req.add_header("Authorization", f"Bearer {user_id}") ``` ### Technical Analysis The server-provided `user_id` is written to `~/.config/social-hotsearch/user.json` using ordinary directory and file creation. The code does not explicitly enforce owner-only permissions, verify ownership, reject symbolic links, or use atomic creation. The same value is subsequently placed in the HTTP `Authorization: Bearer` header. It therefore functions as an authorization credential, even though it is named `user_id`. Actual file permissions depend on the process umask and existing filesystem state. Under a permissive umask or in an incorrectly configured home directory, another local user may be able to read the file. The non-atomic write and lack of symbolic-link protection can also expose or redirect the stored record in a locally hostile environment. ### Attack Path 1. The Skill registers with the remote proxy and receives a `user_id`. 2. `save_user()` writes the identifier and fingerprint to `~/.config/social-hotsearch/user.json`. 3. The resulting access permissions are determined by the ambient umask because the code does not explicitly set mode `0600`. 4. A local attacker with fi ...[truncated 929 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (17)

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

Critical
Category
Data Flow
Confidence
93% confidence
Finding

The destination base URL is controlled by SOCIAL_PROXY_BASE, allowing requests and any attached data to be sent to an arbitrary host. In this file, that means a caller can redirect traffic to an attacker-controlled endpoint and receive machine fingerprints, registration data, or later identifiers, which is effectively SSRF-like exfiltration via untrusted configuration.

Content

Scanner excerpt · scripts/social_client.py (reported line 90)May include surrounding context.

python
for k, v in headers.items():
            req.add_header(k, v)
    try:
        with urllib.request.urlopen(req, timeout=timeout) as resp:
            return json.loads(resp.read().decode("utf-8"))
    except urllib.error.HTTPError as e:
        body_text = e.read().decode("utf-8", errors="replace")

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

Critical
Category
Data Flow
Confidence
93% confidence
Finding

GET requests are also built from the environment-controlled SOCIAL_PROXY_BASE, so usage and upgrade-info queries can be redirected to arbitrary infrastructure. While these calls may carry less sensitive payload than tool execution, they still leak identifiers and permit hostile response injection into client behavior.

Content

Scanner excerpt · scripts/social_client.py (reported line 112)May include surrounding context.

python
for k, v in headers.items():
            req.add_header(k, v)
    try:
        with urllib.request.urlopen(req, timeout=timeout) as resp:
            return json.loads(resp.read().decode("utf-8"))
    except urllib.error.HTTPError as e:
        body_text = e.read().decode("utf-8", errors="replace")

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

Critical
Category
Data Flow
Confidence
98% confidence
Finding

The main MCP tool-call path sends bearer user_id credentials, tool arguments, and skill metadata to a URL derived from SOCIAL_PROXY_BASE. If an attacker can influence that environment variable, they can capture authentication tokens and all submitted topic-analysis content, which is especially sensitive given this skill's social-media analysis and sampling use case.

Content

Scanner excerpt · scripts/social_client.py (reported line 187)May include surrounding context.

python
req.add_header("X-Skill-Id", SKILL_ID)

    try:
        with urllib.request.urlopen(req, timeout=timeout) as resp:
            raw = resp.read().decode("utf-8")
    except urllib.error.HTTPError as e:
        body_text = e.read().decode("utf-8", errors="replace")

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The script’s behavior is limited to fetching and formatting hot-search/ranking results for four sources. That partially matches the declared hot-search lookup function, but it does not perform the broader analysis promised in the description: no topic sentiment analysis, volume analysis, interaction analysis, platform distribution analysis, or original-post sampling. It also omits one declared platform, 小红书. There is no evidence of unrelated or dangerous extra capability; the mismatch is that the implementation is materially narrower than the declared purpose.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
86% confidence
Finding

The skill declares executable behavior that uses environment access, local file read/write, and network access, but it does not declare any tool scope or permissions boundary. That makes the actual privilege surface opaque to a caller or host system and can lead to overbroad execution in environments that rely on manifest-declared constraints for safe sandboxing.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The natural-language instructions, examples, and operational guidance are all presented only in Chinese, which effectively forces a specific language for users and agents consuming the skill. There is no opt-in, alternative language, or explanation that the skill is intentionally limited to a Chinese-language audience.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill enables implicit invocation for a tool-connected agent without any visible trigger constraints or narrowing conditions. Because this skill can reach an external MCP endpoint and perform social-media data retrieval/analysis, automatic invocation increases the chance that unrelated user prompts or ambient context will cause unintended tool use, data disclosure to the remote service, or silent external requests the user did not explicitly approve.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

This Python file contains user-facing natural-language strings entirely in Chinese for the command description and argument help text. Because the skill does not offer an explicit language option or justify a China-specific locale restriction, it appears to impose a language choice on users without opt-in.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The user-facing description and help strings are only in Chinese, and the examples/docs also assume Chinese-language usage. This imposes a specific language on users without an explicit opt-in or a documented justification that the skill is intended only for a Chinese-speaking or China-specific context.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
81% confidence
Finding

This code calls an external MCP tool to retrieve raw posts and then prints the full returned post data to stdout. While the module docstring says it samples posts, there is no explicit warning in code about privacy-sensitive or user-data implications of fetching and emitting raw social-media content.

Content

No source excerpt is available for this finding.

Tainted flow: 'USER_FILE' from os.environ.get (line 23, credential/environment) → pathlib.Path.write_text (file write)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · scripts/social_client.py (reported line 136)May include surrounding context.

python
def save_user(data: dict[str, Any]) -> None:
    USER_FILE.parent.mkdir(parents=True, exist_ok=True)
    USER_FILE.write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding="utf-8")


def ensure_user() -> dict[str, Any]:

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The client computes a stable machine fingerprint from username and hostname and transmits it during registration, but this file provides no user-facing notice or consent mechanism. That creates a privacy and tracking risk because users may be unaware that a persistent identifier tied to their machine context is being sent to a remote service.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

MCP proxy calls transmit user-supplied tool arguments together with a bearer user ID, yet this code gives no warning that prompts, topics, or sampled-post queries are sent to a remote service. In a social-analysis skill, those arguments may include sensitive brand-monitoring topics, PR plans, or internal research terms, so undisclosed transmission raises meaningful privacy and confidentiality concerns.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
87% confidence
Finding

The README states that the skill will automatically register an anonymous ID and persist user identity locally, while also describing collection of a machine-fingerprint hash for quota management. Even if the data collection is limited, doing this without a prominent upfront warning and explicit consent reduces transparency and can surprise users with local file creation and cross-session tracking behavior.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
78% confidence
Finding

The invocation examples and instructions only present Chinese-language prompts, which can amount to an implicit language constraint. Because the file does not say that other languages are supported or that Chinese is required for a justified region-specific reason, it risks violating a language-choice policy.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

The skill states later that first use automatically registers a user and writes a file under ~/.config/social-hotsearch/user.json, but this side effect is not clearly disclosed up front. Silent persistence in a user's home directory can violate user expectations, create privacy concerns, and be abused to normalize undeclared local state changes.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
89% confidence
Finding

User-facing CLI descriptions, option help text, and usage examples are written entirely in Chinese, which implies a fixed language/locale experience. The file does not offer an opt-in language choice or explain that the skill is intentionally limited to a Chinese-speaking or China-specific context.

Content

No source excerpt is available for this finding.