Back to skill

Security audit

Social Media Metrics

Security checks for vulnerabilities and agentic risk

Overview

The skill largely does what it advertises, but it needs Review because it persists an authenticated browser session, exposes a local browser control port, and can be tricked into opening URLs outside the intended social platforms.

Install only if you are comfortable with browser scraping and with Xiaohongshu login storing cookies in a persistent local Chrome profile. Use an isolated environment or throwaway account, clear ~/.playwright_cdp_profile after use, and avoid running this against untrusted URLs until hostname validation is fixed.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/utils/resolver.py:7
Finding
Unvalidated URL Classification Enables Blind SSRF and Local-Network Requests## Vulnerability Details **File Location**: `scripts/utils/resolver.py:7-22, 54-57` **Vulnerability Type**: Blind SSRF caused by unanchored platform URL matching **Risk Level**: Medium ### Vulnerable Code ```python PLATFORM_URL_PATTERNS: list[tuple[str, re.Pattern[str]]] = [ ("bilibili", re.compile(r"space\.bilibili\.com/(\d+)")), ("bilibili", re.compile(r"bilibili\.com/space/(\d+)")), ("youtube", re.compile(r"youtube\.com/(?:@|channel/|c/)([^/?&]+)")), ("douyin", re.compile(r"douyin\.com/user/([A-Za-z0-9_-]+)")), ("kuaishou", re.compile(r"kuaishou\.com/profile/([A-Za-z0-9_-]+)")), ("xiaohongshu", re.compile(r"xiaohongshu\.com/user/profile/([A-Za-z0-9]+)")), ("tiktok", re.compile(r"tiktok\.com/@([^/?&]+)")), ("instagram", re.compile(r"instagram\.com/([^/?&]+)")), ("toutiao", re.compile(r"toutiao\.com/c/user/token/([^/?&]+)")), ("baijiahao", re.compile(r"baijiahao\.baidu\.com/u\?app_id=(\d+)")), ("baijiahao", re.compile(r"author\.baidu\.com/home/(\d+)")), ("haokan", re.compile(r"haokan\.baidu\.com/author/(\d+)")), ("iqiyi", re.compile(r"iqiyi\.com/u/(\w+)")), ("iqiyi", re.compile(r"iqiyi\.com/creator/(\d+)")), ("wechat_video", re.compile(r"channels\.weixin\.qq\.com/([^/?&]+)")), ] def _resolve_url(url: str) -> ResolvedInput: for platform, pattern in PLATFORM_URL_PATTERNS: m = pattern.search(url) if m: return ResolvedInput(platform=platform, uid=m.group(1), url=url) parsed = urlparse(url) raise ValueError( f"Unsupported platform URL: {parsed.netloc}. " f"Supported platforms: bilibili, youtube, douyin, kuaishou, " f"xiaohongshu, tiktok, instagram, toutiao, baijiahao, haokan, iqiyi, wechat_video" ) ``` The resulting original URL is subsequently forwarded to a platform scraper. For example, YouTube navigation occurs at `scripts/platforms/youtube.py ...[truncated 3129 chars]
Remediation
## Remediation Suggestions 1. Parse the URL with `urllib.parse.urlsplit()` before performing any platform matching. 2. Normalize the hostname by lowercasing it, removing a trailing dot, and converting internationalized names to a canonical IDNA representation. 3. Match the parsed hostname against an explicit allowlist. Accept either the exact domain or a controlled subdomain using a boundary-safe comparison such as: ```python def host_matches(host: str, allowed: str) -> bool: return host == allowed or host.endswith("." + allowed) ``` 4. Require HTTPS for supported public platform URLs unless a documented platform strictly requires another scheme. 5. Reject URLs containing user-information, unexpected ports, malformed hostnames, or non-HTTP(S) schemes. 6. Resolve destination addresses and reject loopback, private, link-local, multicast, reserved, and unspecified IPv4 and IPv6 ranges. 7. Revalidate the destination after DNS resolution and on every redirect to mitigate open-redirect and DNS-rebinding scenarios. 8. Construct canonical platform URLs from validated identifiers instead of retaining and navigating to the original user-supplied URL. 9. Add regression tests covering deceptive URLs, including: - `http://127.0.0.1/youtube.com/@test` - `https://youtube.com.attacker.example/@test` - `https://attacker.example/?next=youtube.com/@test` - URLs using credentials, alternate ports, IPv6 loopback, and redirect chains. 10. Where deployment controls permit, enforce an outbound network allowlist so the Skill process can connect only to documented platform domains.

T08 · Insecure Dependencies

Note
Location
requirements.txt:1
Finding
Mutable and Unhashed Dependencies Weaken Supply-Chain Integrity## Vulnerability Details **File Location**: `requirements.txt:1-3` **Vulnerability Type**: Unpinned and unhashed executable dependencies **Risk Level**: Low ### Vulnerable Code ```text requests>=2.31.0 playwright>=1.40.0 beautifulsoup4>=4.12.0 ``` The documented installation instructions in `SKILL.md:43-44` and `README.md:35-36` install these mutable dependencies and a remotely obtained browser: ```bash pip install -r requirements.txt playwright install chromium ``` ### Technical Analysis The dependency declarations specify only minimum versions. As a result, installations performed at different times may resolve to different package versions, including versions released after this audit. No lock file or package hashes are supplied to verify the exact artifacts being installed. `playwright install chromium` also downloads a browser executable associated with the resolved Playwright version. Since the Playwright package itself is not fixed, the browser revision is indirectly mutable as well. This is not evidence that the current dependencies are malicious. The risk is that the installed code is not reproducibly constrained to the reviewed dependency set. A compromised upstream release, transitive dependency, package index, or unexpected future version could therefore introduce code that was not part of the audited project. ### Attack Path 1. A user follows the documented setup procedure. 2. `pip` resolves the newest available versions satisfying each `>=` constraint, along with their transitive dependencies. 3. The installation accepts packages without checking project-supplied cryptographic hashes. 4. Playwright downloads a browser binary corresponding to the dynamically resolved Playwright release. 5. If an upstream artifact or dependency source has been compromised, attacker-controlled package code may execute during installation, import, or normal Skill operation. 6. Such code runs with t ...[truncated 623 chars]
Remediation
## Remediation Suggestions 1. Pin every direct dependency to an exact reviewed version rather than using minimum-version ranges. 2. Generate a complete lock file containing exact versions for direct and transitive dependencies. 3. Record and enforce cryptographic hashes, for example by using a hash-locked requirements file with: ```bash pip install --require-hashes -r requirements.lock ``` 4. Regenerate the lock file only through a controlled dependency-update process that includes review, vulnerability scanning, and automated tests. 5. Configure the expected Python package index explicitly and avoid untrusted supplemental indexes. 6. Pin and document the Playwright package and corresponding browser revision so the downloaded executable is reproducible. 7. Where feasible, distribute a verified container or artifact containing the reviewed dependencies and browser binary. 8. Run installation and the Skill itself as a non-privileged user in an isolated environment with restricted filesystem and network access. 9. Add automated dependency scanning and update tooling so exact pins can be maintained without leaving known vulnerabilities unresolved.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • YARA SignaturesMalware Match, Webshell Match, Cryptominer Match
Findings (33)

YARA rule 'info_stealer': Information stealer patterns (credential harvesting, browser data theft) [malware]

High
Category
YARA Match
Content
persistent profile at `~/.playwright_cdp_profile`.

**First-time setup:**
1. Run any Xiaohongshu query (e.g., `python scripts/main.py --nickname "test" --platform xiaohongshu`)
2. A Chrome window will open showing a QR code login page
3. Scan the QR code with the Xiaohongshu app on your phone
4. The script will detect the login and proceed automatically (120-second timeout)

**Subsequent runs:** Cookies are persisted in the Chrome profile — no login needed until the session expires.

## Error Handling

- **Missing platform for nickname**: Ask the user which platform they want to query
- **Unsupported URL**: Tell the user which platforms are supported
- **Scraping failure**: Some platforms may block headless browsers or require login. Inform the user and suggest trying a direct URL
- **Xiaohongshu login required**: The script will prompt the user to scan a QR code in the Chrome window. If the session has expired, re-run the script and scan again
- **YouTube API key missing**: The scr
Confidence
75% confidence
Finding
YARA rule matched a known malware signature (reverse shell, backdoor, ransomware, C2 framework, or info stealer).

YARA rule 'info_stealer': Information stealer patterns (credential harvesting, browser data theft) [malware]

High
Category
YARA Match
Content
persistent profile at `~/.playwright_cdp_profile`.

**First-time setup:**
1. Run any Xiaohongshu query (e.g., `python scripts/main.py --nickname "test" --platform xiaohongshu`)
2. A Chrome window will open showing a QR code login page
3. Scan the QR code with the Xiaohongshu app on your phone
4. The script will detect the login and proceed automatically (120-second timeout)

**Subsequent runs:** Cookies are persisted in the Chrome profile — no login needed until the session expires.

## Error Handling

- **Missing platform for nickname**: Ask the user which platform they want to query
- **Unsupported URL**: Tell the user which platforms are supported
- **Scraping failure**: Some platforms may block headless browsers or require login. Inform the user and suggest trying a direct URL
- **Xiaohongshu login required**: The script will prompt the user to scan a QR code in the Chrome window. If the session has expired, re-run the script and scan again
- **YouTube API key missing**: The scr
Confidence
75% confidence
Finding
YARA rule matched a known malware signature (reverse shell, backdoor, ransomware, C2 framework, or info stealer).

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The README instructs users to authenticate a real browser session and persist cookies in a local Chrome profile, but it does not clearly warn that this creates long-lived session data on disk. In an agent skill context, that can expose private authenticated state to other local processes, future runs, or unintended reuse, especially if users do not realize a personal account session is being retained.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The skill instructs users to authenticate a real Chrome profile and persist session cookies in a fixed local profile directory, but it does not clearly warn about the privacy and security implications of storing an authenticated session on disk. If that profile is reused, exposed, or accessible to other local processes or users, the stored session could be abused to access the user's Xiaohongshu account without re-authentication.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The requirement explicitly says to use browser automation to scrape follower-count data when no API is available, but it provides no warning or controls around platform terms, account exposure, rate limits, or privacy implications. In a skill intended for broad publication, this increases the chance of misuse, account bans, or collection activity that violates site policies and affects third parties.

Missing User Warnings

Medium
Confidence
82% confidence
Finding
The skill navigates to a user-supplied URL with a browser, which causes outbound network access to a third-party site. There is no confirmation prompt, user-facing log/print, or explanatory comment/docstring in this file disclosing that the skill will contact external websites using the provided input.

Missing User Warnings

Medium
Confidence
87% confidence
Finding
The code constructs a Baidu search URL using the provided nickname and immediately loads it, transmitting user-provided data to an external search engine. This file contains no user-facing warning, confirmation, or explanatory comment indicating that the nickname will be sent off-system.

External Transmission

Medium
Category
Data Exfiltration
Content
from .base import BasePlatform, MetricsResult

API_STAT_URL = "https://api.bilibili.com/x/relation/stat"
API_USER_URL = "https://api.bilibili.com/x/space/acc/info"
SEARCH_URL = "https://api.bilibili.com/x/web-interface/search/type"
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
from .base import BasePlatform, MetricsResult

API_STAT_URL = "https://api.bilibili.com/x/relation/stat"
API_USER_URL = "https://api.bilibili.com/x/space/acc/info"
SEARCH_URL = "https://api.bilibili.com/x/web-interface/search/type"
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
from .base import BasePlatform, MetricsResult

API_STAT_URL = "https://api.bilibili.com/x/relation/stat"
API_USER_URL = "https://api.bilibili.com/x/space/acc/info"
SEARCH_URL = "https://api.bilibili.com/x/web-interface/search/type"
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Missing User Warnings

Medium
Confidence
85% confidence
Finding
The skill navigates a browser to a caller-supplied URL, which triggers network requests to a third-party site and may transmit system metadata such as IP address and browser fingerprinting data. The file contains no confirmation prompt, logging, or explanatory comment/docstring warning the user about this external network access, and the same pattern is repeated for nickname-based search navigation.

Natural-Language Policy Violations

Medium
Confidence
90% confidence
Finding
The code explicitly depends on the Chinese label '用户' to operate, which creates a language-specific behavior that is not optional or documented in this file. Under the policy, forcing a specific language without user opt-in or documented justification is a natural-language locale violation.

Context-Inappropriate Capability

Medium
Confidence
94% confidence
Finding
The CDP browser path is explicitly designed to bypass automation detection and reuse a persistent profile so cookies survive across runs. That combination enables stealthy authenticated browsing and reduces user visibility into session reuse, which is dangerous in an agent skill because it can facilitate scraping, account misuse, or actions performed under stored credentials.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The code stores browser state in a fixed persistent profile directory without any nearby disclosure, consent, or isolation controls. In a skill context, that can silently retain cookies and authenticated state across executions, increasing the chance of unintended account access, cross-task data leakage, or actions performed with stale privileged sessions.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
user_data = os.path.expanduser("~/.playwright_cdp_profile")

        chrome_bin = _find_chrome()
        self._chrome_proc = subprocess.Popen(
            [
                chrome_bin,
                f"--remote-debugging-port={port}",
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
Launching a real Chrome instance with remote debugging enabled exposes a powerful control interface over the browser session. Even though it binds to 127.0.0.1, local processes on the host could connect to that port and inspect pages, cookies, or drive authenticated actions, which is especially risky when combined with a persistent user-data directory.

Natural-Language Policy Violations

Low
Confidence
77% confidence
Finding
The natural-language instructions are entirely in Chinese and do not indicate that users may choose another language or locale. Under SQP-3, forcing a specific language without user opt-in can be a policy violation unless the locale constraint is clearly documented and justified, which is not present here.

Unpinned Dependencies

Low
Category
Supply Chain
Content
requests>=2.31.0
playwright>=1.40.0
beautifulsoup4>=4.12.0
Confidence
93% confidence
Finding
The dependency is specified with a lower bound only, which allows installation of different future versions and makes builds non-reproducible. This increases supply-chain risk because a newly released vulnerable or malicious version could be pulled in without review.

Unverifiable Dependency: requests has 16 known advisory(ies) (CVE-2014-1830 (Exposure of Sensitive Information to an Unauthorized Actor in Requests); CVE-2024-47081 (Requests vulnerable to .netrc credentials leak via malicious URLs); CVE-2024-35195 (Requests `Session` object does not verify requests after making first request wi) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
88% confidence
Finding
Requests has multiple known advisories across versions, and because the manifest does not pin an exact release, it is impossible to verify whether the installed version is affected. In this context, the issue is not proof of a specific exploitable CVE, but a real supply-chain risk due to version ambiguity.

Unpinned Dependencies

Low
Category
Supply Chain
Content
requests>=2.31.0
playwright>=1.40.0
beautifulsoup4>=4.12.0
Confidence
93% confidence
Finding
The dependency is not strictly pinned, so environments may resolve to different versions over time. That weakens reproducibility and can expose consumers to unintended vulnerable or compromised upstream releases.

Unpinned Dependencies

Low
Category
Supply Chain
Content
requests>=2.31.0
playwright>=1.40.0
beautifulsoup4>=4.12.0
Confidence
93% confidence
Finding
Using only a minimum version for beautifulsoup4 permits unreviewed newer releases to be installed automatically. This is a supply-chain hygiene weakness because security posture depends on whichever version is resolved at install time.

Missing User Warnings

Low
Confidence
83% confidence
Finding
This code sends the extracted Bilibili UID to a remote API via HTTP requests, and similar requests recur later for user info and search. There is no confirmation prompt, print/log message, or comment/docstring in this file disclosing that user-provided profile URLs or nicknames will be sent to Bilibili services.

Missing User Warnings

Low
Confidence
86% confidence
Finding
The nickname search function transmits the user's provided nickname to Bilibili's search endpoint. The file contains no user-facing warning, log message, or explanatory comment indicating that entered nicknames will be sent to an external service.

Missing User Warnings

Low
Confidence
87% confidence
Finding
The skill navigates a browser page to a user-supplied Douyin URL, which initiates network requests to an external service, and later performs a search request as well. In this file, there is no confirmation prompt or user-facing notice around that external access; only internal docstrings are present, which do not disclose the behavior to the user.

Missing User Warnings

Low
Confidence
90% confidence
Finding
The code interpolates the provided nickname into a Douyin search URL and loads it in the browser, transmitting user input to a third-party service. This file does not include a user-facing prompt, warning, or log indicating that the nickname will be sent externally.

Static analysis

No suspicious patterns detected.