Back to skill

Security audit

FlyClaw (Flight N-in-1 Search Zero Login)

Security checks for vulnerabilities and agentic risk

Overview

This is a real flight-search skill, but it needs review because a default provider silently stores a device ID and sends host details externally despite stronger privacy claims.

Review this skill before installing if you are sensitive to travel-query privacy. Expect flight searches to contact third-party services, and note that the default Fliggy source can persist a device ID and send host metadata. Consider disabling fliggy_mcp or using the skill only after the publisher documents and minimizes that data flow; avoid running update-airports with URLs you do not fully trust.

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

Warning
Location
sources/fliggy_mcp.py:101
Finding

Automatic Transmission of a Persistent Device Identifier and Host Fingerprint

Content
View full analysis
str: """Return a stable device ID (SHA-256 hex of a UUID4), cached in cache/.device_id.""" global _device_id_cache if _device_id_cache is not None: return _device_id_cache id_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), "cache", ".device_id") try: with open(id_path, "r") as f: did = f.read().strip() if len(did) == 64: _device_id_cache = did return did except FileNotFoundError: pass did = hashlib.sha256(uuid.uuid4().bytes).hexdigest() os.makedirs(os.path.dirname(id_path), exist_ok=True) with open(id_path, "w") as f: f.write(did) _device_id_cache = did return did ``` ```python def _build_context() -> dict: """Build the full context dict for x-ff-ctx header.""" mem_tier = _memory_tier_gb() cpus = os.cpu_count() or 1 os_type = platform.system().lower() arch = platform.machine() os_release_major = platform.release().split(".")[0] node_version = "v22.22.0" lang = _parse_language() return { "machine": { "platform": os_type, "arch": arch, "cpus": cpus, "memoryTierGB": mem_tier, "osType": os_type, "nodeVersion": node_version, "osReleaseMajor": os_release_major, }, "fingerprint": { "language": lang, "platform": os_type, "userAgent": f"flyai-cli/1.0.6 (Node.js {node_version}; {os_type} {arch})", "hardwa ...[truncated 3638 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
sources/fliggy_mcp.py:43
Finding

Reusable API Credential and HMAC Signing Secret Embedded in Source Code

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
airport_manager.py:228
Finding

Arbitrary URL Fetch in Airport Updater Enables Internal-Network Requests

Content
View full analysis
config.yaml > AIRPORT_UPDATE_URL constant url = getattr(args, "url", None) or cache_cfg.get("airport_update_url", "") or cfg.AIRPORT_UPDATE_URL if not url: print("Error: no update URL provided. Use --url or set airport_update_url in config.yaml", file=sys.stderr) sys.exit(1) print(f"Updating airport data from: {url}") ok = airport_manager.update_from_url(url) ``` ```python def update_from_url(self, url: str) -> bool: """Download airport data from *url* and merge into existing data.""" if not url: return False try: resp = requests.get(url, timeout=30) resp.raise_for_status() new_data = resp.json() except Exception as e: logger.warning("Failed to download airport data from %s: %s", url, e) return False ``` ```python update_parser = subparsers.add_parser( "update-airports", help="Update airport data from remote URL", ) update_parser.add_argument( "--url", required=False, default=None, help="URL to download airport data from (overrides config)", ) ``` ### Technical Analysis The updater accepts a caller-controlled URL and passes it directly to `requests.get()`. It does not enforce HTTPS, restrict destination hosts, validate the resolved IP address, reject loopback/private/link-local networks, constrain redirects, verify content type, or impose a response-size limit before parsing JSON. The subsequent structural validation protects the airport cache from many ...[truncated 1987 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
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (49)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

Using SerpAPI or similar keyed external services while marketing the skill as zero-API-key is a concrete documentation-to-behavior mismatch with security implications. Users may unknowingly depend on third-party services, disclose queries externally, or be prompted for credentials despite assurances to the contrary.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

Using SerpAPI or similar keyed external services while marketing the skill as zero-API-key is a concrete documentation-to-behavior mismatch with security implications. Users may unknowingly depend on third-party services, disclose queries externally, or be prompted for credentials despite assurances to the contrary.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

Using SerpAPI or similar keyed external services while marketing the skill as zero-API-key is a concrete documentation-to-behavior mismatch with security implications. Users may unknowingly depend on third-party services, disclose queries externally, or be prompted for credentials despite assurances to the contrary.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

Using SerpAPI or similar keyed external services while marketing the skill as zero-API-key is a concrete documentation-to-behavior mismatch with security implications. Users may unknowingly depend on third-party services, disclose queries externally, or be prompted for credentials despite assurances to the contrary.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

Using SerpAPI or similar keyed external services while marketing the skill as zero-API-key is a concrete documentation-to-behavior mismatch with security implications. Users may unknowingly depend on third-party services, disclose queries externally, or be prompted for credentials despite assurances to the contrary.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 167)May include surrounding context.

md
**文件位置**:主程序 `flyclaw.py`,配置 `config.yaml`,机场缓存 `cache/airports.json`。

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The manifest strongly claims 'Pure Python, no browser', yet the search flow can invoke a Playwright-powered browser baseline when --compare --browser is used. This is a direct mismatch because the code explicitly supports browser automation as part of the skill's functionality.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
85% confidence
Finding

The skill manifest does not declare tool scope or allowed capabilities, yet the analyzed implementation reportedly uses sensitive capabilities including environment access, file read/write, MCP, and network. This creates an authorization and transparency gap: consumers may invoke a skill whose real privileges exceed what is documented, increasing the chance of unintended data access or network activity.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The trigger section contains broad natural-language phrases that could cause the skill to activate on ambiguous travel-related requests. Overbroad activation is dangerous because it can initiate unintended network requests, data processing, or tool use when the user did not clearly ask to invoke this specific skill.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The trigger section uses broad natural-language activation phrases such as generic flight-search requests and catch-all modifiers like 'all flights' or 'including connecting' without clear guardrails on when the skill should or should not auto-activate. In an agent environment, this can cause unintended invocation, parameter inference, or over-collection of user travel intent from ambiguous messages, increasing the chance of incorrect actions or privacy leakage.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The module includes a network-enabled self-update path that downloads JSON from an arbitrary URL and atomically rewrites a local cache file. Even though the downloaded content is schema-validated, there is no allowlist, signature check, size limit, or provenance control, so any caller that can influence the URL can cause persistent untrusted data to be written locally and used by future resolutions.

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 · config.py (reported line 28)May include surrounding context.

python
"AppleWebKit/537.36 (KHTML, like Gecko) "
    "Chrome/131.0.0.0 Safari/537.36"
)
FR24_API_BASE = "https://api.flightradar24.com/common/v1"
AIRPLANESLIVE_API_BASE = "https://api.airplanes.live/v2"
ADSB_LOL_API_BASE = "https://api.adsb.lol/v2"

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 · config.py (reported line 29)May include surrounding context.

python
"Chrome/131.0.0.0 Safari/537.36"
)
FR24_API_BASE = "https://api.flightradar24.com/common/v1"
AIRPLANESLIVE_API_BASE = "https://api.airplanes.live/v2"
ADSB_LOL_API_BASE = "https://api.adsb.lol/v2"

# Default airport data update URL (set to GitHub raw URL after project is published)

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 · config.py (reported line 30)May include surrounding context.

python
)
FR24_API_BASE = "https://api.flightradar24.com/common/v1"
AIRPLANESLIVE_API_BASE = "https://api.airplanes.live/v2"
ADSB_LOL_API_BASE = "https://api.adsb.lol/v2"

# Default airport data update URL (set to GitHub raw URL after project is published)
AIRPORT_UPDATE_URL = ""

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The skill performs remote airport-database update operations, including an automatic startup update path, which extends beyond simple local flight aggregation. Fetching and applying remote data introduces a supply-chain and trust-boundary risk, especially if the update URL is configurable and the content is not strongly authenticated before use.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The manifest explicitly markets the skill as requiring no login/account/API key, but the implementation passes a serpapi_key into Google Flights queries and accepts api_key and sign_secret for the Fliggy MCP source. That is a semantic mismatch between the stated no-credential experience and the actual supported behavior of the tool.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

Using Playwright/browser automation is not an obvious requirement for a skill described as zero-login, zero-API, pure-Python flight aggregation. The browser baseline is a separate verification capability that expands the operational surface beyond normal aggregation/search needs.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The tool silently auto-updates airport data at startup without user-facing notice or confirmation. In a zero-login CLI context, undeclared background network access and remote data ingestion are dangerous because they expand the skill's behavior, create privacy surprises, and expose users to unreviewed remote content every time the tool runs.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The module docstring explicitly says it provides real-time aircraft position data and does not provide schedules or prices. The manifest, however, describes the skill primarily as multi-source flight aggregation for ticket search and pricing, so this file adds a materially different live-tracking capability not reflected in that description.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The code generates a stable device identifier, stores it on disk in cache/.device_id, and reuses it across runs. This enables long-term correlation of a user's activity and host across searches, which is not justified by the stated zero-login flight aggregation purpose.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The skill writes a persistent identifier to disk without visible disclosure, creating hidden state and long-term trackability. In the context of a flight-search utility marketed around zero-login convenience, undisclosed persistent tracking artifacts are especially problematic because users may reasonably expect stateless behavior.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The code builds and transmits a detailed host fingerprint in the x-ff-ctx header, including CPU count, memory tier, OS type, architecture, language, timezone, user-agent, and a stable device ID. For a flight-search skill, this exceeds what is functionally necessary and creates unnecessary privacy and tracking risk, especially because it is sent to a third-party service on every request.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill transmits host fingerprinting data to an external endpoint without any visible disclosure in the code path or user-facing warning. Even if intended to match an upstream protocol, sending this telemetry silently undermines user privacy and makes the behavior more dangerous in a tool advertised as zero-login and pure Python.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The request parameters hard-code hl to en, which enforces an English-language locale for results. This is a natural-language locale policy issue because the file does not offer opt-in, configurability, or a documented reason for restricting the locale.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
96% confidence
Finding

The top-level documentation describes FlyClaw as a lightweight Python implementation with 'no browser automation' / '非浏览器模拟'. Later, the same README documents a --browser mode that launches Playwright for browser-based validation, which directly contradicts that claim even if presented as an optional debug feature.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.