Back to skill

Security audit

TikTok Hotspot Monitor

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches TikTok trend monitoring, but it handles login sessions and paid crawling too broadly and includes an undeclared video downloader.

Review this skill before installing. Use a dedicated low-privilege TikTok account and Apify token, protect or delete data/tiktok_session.json, avoid shared machines, inspect any alternate config before using MCP mode, avoid --schedule unless you have external billing limits, and do not run the downloader unless you have validated the input URLs and want local media downloads.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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
Findings (6)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/tiktok_login_save_session.py:47
Finding

TikTok Authentication Session Stored Without Restrictive File Permissions

Content
View full analysis
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/crawl_tiktok_hotspots.py:291
Finding

Configuration-Controlled MCP Process Inherits the Entire Parent Environment

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/crawl_tiktok_hotspots.py:547
Finding

Documented Apify Cost and Crawl Limits Are Not Enforced

Content
View full analysis
list[CrawlRequest]: enabled_sources = [source for source in config.sources if source.enabled] if max_sources is not None: enabled_sources = enabled_sources[:max_sources] requests: list[CrawlRequest] = [] for source in enabled_sources: windows = crawl_windows_for(config, source) if not windows or config.provider_type != "apify": requests.append(CrawlRequest(source=source, window=None, limit=source.limit)) continue for window, limit in split_limit_by_weight(source.limit, windows): requests.append(CrawlRequest(source=source, window=window, limit=limit)) return requests ``` Every generated request starts a paid Actor run: ```python client = ApifyClient(token) actor_run = client.actor(config.apify_actor_id).call(run_input=run_input) dataset_id = actor_run.get("defaultDatasetId") if actor_run else None ``` Scheduling repeats indefinitely: ```python def run_schedule(config: CrawlerConfig) -> None: while True: snapshot_path, log_path, summary = run_once(config) print( f"crawl complete: records={summary['raw_record_count']} failed_runs={summary['failed_run_count']}/{summary['planned_run_count']} " f"snapshot={snapshot_path} log={log_path}", flush=True, ) time.sleep(config.interval_minutes * 60) ``` ### Technical Analysis `skill.md` claims these enforced guardrails: - Maximum 50 sources - Maximum 500 records per source - Maximum requested total of 5,000 - Maximum 250 planned runs The ...[truncated 1743 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
`. 4. The script passes the URL to `yt-dlp`. 5. `yt-dlp` attempts to resolve and request the destination from the victim host’s network context. 6. Depending on content type and extractor behavior, the response may be downloaded, its availability may be inferred from errors or timing, or redirects may reach another destination. ### Impact Assessment The process can reach destinations available to the host, potentially including intranet services or other non-public endpoints. It can also consume bandwidth ...[truncated 419 chars]:132
Finding

Untrusted Analysis URLs Can Drive Arbitrary Outbound Requests Through yt-dlp

Content
View full analysis
bool: if dry_run: return True output_path.parent.mkdir(parents=True, exist_ok=True) tmp_tmpl = output_path.with_suffix(".%(ext)s") cmd = [ sys.executable, "-m", "yt_dlp", "-f", "bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best", "--no-playlist", "--no-warnings", "--no-part", # avoid .part files "-o", str(tmp_tmpl), url, ] try: result = subprocess.run(cmd, capture_output=True, text=True, timeout=300) ``` The URL originates from analysis JSON without domain validation: ```python url = str(video.get("url", "") or video.get("webpage_url", "")) if not url or not video_id: continue ... ok = download_video(url, mp4_path) ``` ### Technical Analysis The downloader trusts URLs from an analysis JSON file and gives them to `yt-dlp`. There is no scheme allowlist, TikTok hostname validation, DNS/IP filtering, redirect validation, or block on loopback, private, link-local, and cloud metadata addresses. Using a subprocess argument list prevents shell metacharacter injection, so this is not a shell command-injection vulnerability. The risk instead comes from `yt-dlp` performing network requests through its generic and site-specific extractors. The downloader is also inconsistent with the declared Skill boundary in `skill.md`, which states that downloading video or audio files is not a responsibility of the Skill. Its presence expands network, storage, copyright, and data-handling privileges beyond metadata analysis. ### Attack Path 1. An attacker provides or modifies an analysis JSON file. 2. A video entry contains a syntactically valid `video_id` and an a ...[truncated 917 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
requirements.txt:1
Finding

Security-Critical Dependencies Use Open-Ended Lower-Bound Version Constraints

Content
View full analysis
=1.0.0 playwright>=1.40.0 ``` ### Technical Analysis Both dependencies use open-ended `>=` constraints with no upper bound, lock file, hashes, or reproducible artifact references. A future installation may therefore select a substantially different package version from the one reviewed. These packages operate in sensitive contexts: - `apify-client` receives the Apify API token and performs paid cloud operations. - `playwright` controls an authenticated browser and loads the plaintext TikTok session. - Playwright installation also downloads a browser runtime. The source provides no hashes or locked transitive dependency graph. In addition, code imports `mcp` and invokes `yt_dlp`, but neither package is declared in `requirements.txt`, encouraging ad hoc installation outside a reviewed dependency set. No evidence in the reviewed files establishes that the current named packages are malicious. The confirmed issue is insufficient dependency integrity and reproducibility, not a demonstrated package compromise. ### Attack Path 1. A user installs dependencies at a later date using `pip install -r requirements.txt`. 2. Package resolution selects the latest compatible releases and their current transitive dependencies. 3. If a selected release is compromised, malicious, or unexpectedly incompatible, installation or import-time code runs under the user account. 4. Runtime package code may access the Apify token, TikTok session, filesystem, and network because the scripts do not sandbox dependencies. ### Impact Assessment A compromised dependency can execute with the same privileges as the Skill, read credentials and local files, alter reports, initiate network traffic, or misuse the Apify account. This is a supply-chain exposure rather ...[truncated 42 chars]
Remediation
View remediation

other

Note
Location
scripts/render_tiktok_hotspot_report.py:407
Finding

Generated Reports Contact Google Fonts Despite Being Declared Self-Contained

Content
View full analysis
``` The same external references appear in `examples/report.html:7-9`. ### Technical Analysis `skill.md` declares the HTML report to be self-contained with no external dependencies. However, opening a generated report causes the browser to connect to Google Fonts and Google’s font asset domain. These requests disclose at least the viewer’s IP address, user-agent characteristics, request timing, and potentially additional browser metadata to a third party. They also make report rendering dependent on an external service. No API token or TikTok session is directly included in these font requests. The issue is an unnecessary network side effect and privacy mismatch, not credential exfiltration. ### Attack Path 1. The user renders an HTML hotspot report. 2. The user opens the report in a browser with network access. 3. The browser follows the preconnect and stylesheet tags. 4. Google receives network requests associated with viewing the local report. ### Impact Assessment The report viewer’s network metadata is disclosed to Google, and offline/self-contained operation is not achieved. This network access is unnecessary for static trend reporting and exceeds the minimum network privileges needed after analysis is complete. ]]>
Remediation
View remediation
``` 5. Update the example report and documentation so generated and example outputs follow the same offline policy. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (43)

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding

The code is clearly related to TikTok hotspot analysis and does implement trend scoring, coverage-like scoring, recent-window bucketing, and crawl log metric summarization, so it partially aligns with the declared domain. However, the declared description presents a broader monitoring skill that crawls metadata via Apify/Playwright and generates static HTML reports. This code chunk does neither: it loads preexisting snapshot files from disk, analyzes them, and writes a JSON report. The cost-aware crawl strategy is only indirectly reflected by parsing crawl logs and window summaries, not by executing any crawl scheduling logic. Additionally, the presence of a --download flag without implementation indicates a description/behavior gap rather than added capability. Therefore this chunk materially underdelivers on key declared capabilities, making the description inaccurate for the supplied code chunk.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

The code is clearly focused on crawling and normalizing TikTok video metadata, saving snapshots/logs, and supporting weighted crawl windows with a cost note. That partially matches the declared crawling/monitoring aspect and the cost-aware multi-window strategy. However, several material parts of the declared purpose are not represented in this code: there is no women's-fashion-specific analysis logic, no trend analysis or heat/coverage scoring, and no static HTML report generation. The fallback/alternate crawler is also not Playwright; it is an MCP-based TikTok search client invoked over stdio. Because core declared capabilities are absent and one provider mechanism is materially different, the description does not accurately represent what this code chunk actually does.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The declared description is for a monitoring/analysis/report-generation skill: crawling TikTok metadata, scoring trends, and producing static HTML reports. This code chunk does not perform crawling via Apify or Playwright, does not analyze trends, and does not generate HTML reports. Instead, its primary function is to download TikTok videos referenced in an existing analysis JSON and save them as local .mp4 files alongside markdown metadata. Downloading media is a materially different and undeclared capability, so this is a description-behavior mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The declared description is about automated TikTok trend monitoring, metadata crawling, scoring, and HTML report generation. This code chunk does none of that. Its sole purpose is to create and save an authenticated TikTok session using Playwright. While a saved login session could be a supporting prerequisite for later crawling, this specific code introduces a significant undeclared capability: collecting and persisting authentication state/cookies. That is materially different from the declared primary purpose and is not represented in the description or permissions.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The code only provides a thin MCP-compatible search service for TikTok video search using Playwright. It reads a saved session file, opens TikTok search pages, intercepts search API responses, extracts metadata, and returns results over stdio. This is only a subset of the declared functionality and omits several central described behaviors: there is no Apify-based primary crawler, no backup selection logic between Apify and Playwright, no trend-analysis or scoring logic, no hotspot detection specific to US women's fashion, no report generation, and no cost-aware multi-window crawling strategy. The implemented behavior is materially narrower and differently scoped than the declared end-to-end monitor.

Content

No source excerpt is available for this finding.

Hidden Instructions

High
Category
Prompt Injection
Confidence
60% confidence
Finding

Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Content

Scanner excerpt · examples/report.html (reported line 512)May include surrounding context.

html
<span class="source">关键词 / vacation outfits</span>
          <span class="status status-warm">近七天</span>
        </div>
        <h3>SHEIN is getting to good.\ud83c\udf68\ud83e\udee7\ud83e\uddd8\ud83c\udffd‍♀️Download the SHEIN App to check out the amazing store Avantive and unlock the latest fashion trends anytime, anywhere! Search \u0026 follow Avantive on SHEIN and use; 4SPUSsophienelsonnnnn034 to enjoy exclusive discounts! ✨
@sheinofficial @shein_us @SHEIN US 
#SHEINtrends #ad
#sheinhaul #summersheinhaul #vacationoutfits </h3>

Hidden Instructions

High
Category
Prompt Injection
Confidence
60% confidence
Finding

Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Content

Scanner excerpt · examples/report.html (reported line 620)May include surrounding context.

html
<span class="source">关键词 / vacation outfits</span>
          <span class="status status-warm">近七天</span>
        </div>
        <h3>SHEIN is getting to good.\ud83c\udf68\ud83e\udee7\ud83e\uddd8\ud83c\udffd‍♀️Download the SHEIN App to check out the amazing store Avantive and unlock the latest fashion trends anytime, anywhere! Search \u0026 follow Avantive on SHEIN and use; 4SPUSsophienelsonnnnn034 to enjoy exclusive discounts! ✨
@sheinofficial @shein_us @SHEIN US 
#SHEINtrends #ad
#sheinhaul #summersheinhaul #vacationoutfits </h3>

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · README.md (reported line 55)May include surrounding context.

md
pip install apify-client

# 2. Set Apify API Token
echo "APIFY_TOKEN=your_token_here" > .env

# 3. Crawl (10 sources × window weights)
python scripts/crawl_tiktok_hotspots.py --once

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · readme-en.md (reported line 55)May include surrounding context.

md
pip install apify-client

# 2. Set Apify API Token
echo "APIFY_TOKEN=your_token_here" > .env

# 3. Crawl (10 sources × window weights)
python scripts/crawl_tiktok_hotspots.py --once

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/crawl_tiktok_hotspots.py (reported line 70)May include surrounding context.

python
return datetime.now(timezone.utc).strftime("%Y%m%dT%H%M%SZ")


def load_dotenv(path: Path = PROJECT_ROOT / ".env") -> None:
    if not path.exists():
        return

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · skill.md (reported line 381)May include surrounding context.

md
return datetime.now(timezone.utc).strftime("%Y%m%dT%H%M%SZ")


def load_dotenv(path: Path = PROJECT_ROOT / ".env") -> None:
    if not path.exists():
        return

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
93% confidence
Finding

The code launches an external MCP subprocess and passes the entire parent process environment with env={**os.environ, **config.tiktok_mcp_env}. If the configured MCP command/args point to an untrusted or compromised program, it receives all loaded secrets from the shell and .env file, enabling credential exfiltration far beyond the minimum needed for TikTok crawling.

Content

Scanner excerpt · scripts/crawl_tiktok_hotspots.py (reported line 298)May include surrounding context.

python
server_params = StdioServerParameters(
        command=config.tiktok_mcp_command,
        args=config.tiktok_mcp_args,
        env={**os.environ, **config.tiktok_mcp_env},
        cwd=config.tiktok_mcp_cwd,
        encoding_error_handler="replace",
    )

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · skill.md (reported line 286)May include surrounding context.

md
### 4.2 `analyze_tiktok_hotspots.py` — Offline Analyzer

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · skill.md (reported line 602)May include surrounding context.

md
### 4.2 `analyze_tiktok_hotspots.py` — Offline Analyzer

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The README instructs users to save a TikTok authenticated session for local Playwright scraping but does not warn that the resulting browser/session state is sensitive credential material. If that state file is stored insecurely, committed to source control, or reused by other processes, an attacker could hijack the TikTok account session and access or act as the user.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding

Without declared permissions the skill's intent is opaque and cannot be validated.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This manifest/config file includes multiple natural-language labels in Chinese such as "近24小时高赞" while the config market is explicitly "US". The file provides no opt-in, fallback, or documented justification for forcing a non-user-selected language, which conflicts with the language/locale policy criterion.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The label field here is natural-language user-facing text in Chinese, continuing a pattern of fixed locale content in the configuration. Because the file does not offer a language choice or explain a region-specific requirement, this is a policy-relevant locale constraint.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This line contains another Chinese label in a configuration otherwise scoped to the US market. The mismatch suggests the skill may force a specific language without user choice or clear justification.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The configuration continues to define user-facing labels only in Chinese. Without any documented opt-in or regional constraint, this appears to impose a fixed language/locale contrary to the stated policy.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This label is another instance of fixed Chinese-language text in the config. The absence of locale selection or justification makes it a natural-language policy concern.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This user-facing label is hard-coded in Chinese and appears in a US-market configuration. No language selection or explicit region-specific rationale is present.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The label field here enforces Chinese-language output without any visible opt-in mechanism. That makes the locale behavior fixed rather than user-selected.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This is another hard-coded Chinese label in the same config, reinforcing a forced locale pattern. The file does not expose a language option or note a justified regional restriction.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This label continues the use of a fixed Chinese locale for user-facing text. Because the config offers no opt-in or rationale, it fits the policy-violation category.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.