Back to skill

Security audit

Travel Itinerary Builder

Security checks for vulnerabilities and agentic risk

Overview

The skill fits a travel-planning purpose, but it handles Gmail booking data and credentials with weak containment and can generate unsafe HTML from unescaped travel data.

Review before installing. Use the Gmail parser only when you intentionally want mailbox booking extraction, keep outputs in a private directory, and avoid opening generated HTML from untrusted email/API data unless it has been fixed to escape HTML. Treat the Homebrew dependencies as privileged local tools and verify them separately. Users outside Singapore should independently verify visa, driving, insurance, and payment guidance.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/generate_itinerary.py:312
Finding

Unescaped Data Injection in Generated HTML Itineraries

Content
View full analysis
') content_parts.append(f'
Day {day["day_number"]} - {day["date"]} ({day["weekday"]})
') content_parts.append(f'
') # Weather if day['weather']: w = day['weather'] content_parts.append(f'
🌤️ {w.get("condition", "N/A")} | {w.get("temperature", "N/A")}
') # Bookings if day['bookings']: for booking in day['bookings']: if booking['type'] == 'flight': f = booking['data'] content_parts.append(f'
✈️ Flight: {f.get("airline", "N/A")} {f.get("flight_number", "N/A")}
{f.get("departure_time", "N/A")} → {f.get("arrival_time", "N/A")}
') elif booking['type'] == 'hotel': h = booking['data'] content_parts.append(f'
🏨 Hotel: {h.get("name", "N/A")}
Check-in: {h.get("checkin_date", "N/A")}
') # Activities placeholder if day['activities']: content_parts.append('
    ') for activity in day['activities']: content_parts.append(f'
  • {activity}
  • ') content_parts.append('
') content_html = '\n'.join(content_parts) # Replace template placeholders html = template.replace('{{title}}', itinerary['title']) html = html.replace('{{language}}', itinerary['language']) html = html.replace('{{subtitle}}', ', '.join(itinerary['destinations'])) html = html.replace('{{content}}', content_html) ``` ### Technical Analysis The HTML generator directly interpolates dynamic values into HTML without context-appropriate escaping. Sources include command-lin ...[truncated 2192 chars]
Remediation
View remediation
``` 7. Add tests containing HTML metacharacters, event handlers, SVG payloads, and malformed values to verify that they are rendered as text. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/gmail_parser.py:303
Finding

Sensitive Gmail Booking Data Stored Without Restrictive File Permissions

Content
View full analysis
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
SKILL.md:17
Finding

Unpinned Executable Dependencies Installed from External Homebrew Sources

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (22)

Tp4

High
Category
MCP Tool Poisoning
Confidence
89% confidence
Finding

This mismatch includes undeclared network access to wttr.in, which is a real security and privacy concern even if the destination data seems low sensitivity. Any undisclosed outbound network behavior can leak user travel plans, dates, and locations, and it should be treated as a true permission and transparency issue.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

This mismatch includes undeclared network access to wttr.in, which is a real security and privacy concern even if the destination data seems low sensitivity. Any undisclosed outbound network behavior can leak user travel plans, dates, and locations, and it should be treated as a true permission and transparency issue.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

This mismatch includes undeclared network access to wttr.in, which is a real security and privacy concern even if the destination data seems low sensitivity. Any undisclosed outbound network behavior can leak user travel plans, dates, and locations, and it should be treated as a true permission and transparency issue.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

This mismatch includes undeclared network access to wttr.in, which is a real security and privacy concern even if the destination data seems low sensitivity. Any undisclosed outbound network behavior can leak user travel plans, dates, and locations, and it should be treated as a true permission and transparency issue.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
84% confidence
Finding

The script accesses and propagates a keyring password to enable Gmail search, which constitutes handling credential material inside the skill. In this skill's context, that is particularly dangerous because an itinerary builder does not inherently require direct credential brokering, and compromise or misuse of this path could enable mailbox access well beyond the immediate travel-planning task.

Content

Scanner excerpt · scripts/gmail_parser.py (reported line 51)May include surrounding context.

python
"--json"
        ]
        result = subprocess.run(cmd, capture_output=True, text=True, check=True,
                               env={**subprocess.os.environ, "GOG_KEYRING_PASSWORD": subprocess.os.environ.get("GOG_KEYRING_PASSWORD", "")})
        messages = json.loads(result.stdout)
        print(f"✅ Found {len(messages)} messages")
        return messages

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding

The skill declares broad operational capabilities involving shell execution, local file I/O, environment-variable use, and optional access to Gmail and external APIs, but it does not define an explicit permission or allowed-tools scope. In this context, the undocumented capability set is dangerous because the skill handles sensitive email content and credentials, increasing the chance of overbroad agent execution or unintended access beyond user expectations.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
85% confidence
Finding

The top-level manifest emphasizes HTML itinerary generation, while the body of the skill documentation broadens behavior to multiple other output and export targets. Markdown/JSON may be implementation-adjacent, but PDF export and Notion sync materially expand the described behavior beyond the manifest's stated output scope.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The manifest describes itinerary generation, weather, places, Gmail booking extraction, multilingual support, printable documents, and budget estimation, but does not mention third-party workspace synchronization. Adding a Notion sync capability expands the skill from itinerary creation into external data publishing, which is a distinct capability not clearly justified by the stated purpose.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The document gives country-specific legal, visa, licensing, insurance, and payment guidance as if it broadly applies, but it is tailored to Singapore citizens and Singapore-issued documents/cards. In a travel-planning skill, users may rely on this information for real-world compliance decisions; users from other nationalities could be misled about entry requirements, driving legality, or financial preparation, causing denied boarding, border issues, or uninsured travel.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The manifest describes a comprehensive generator that appears to obtain and organize forecasts, places, restaurant recommendations, transportation, and Gmail-derived bookings. In this file, the code merely accepts file paths for bookings, weather, and places and loads those JSON files locally; it does not fetch weather, query POIs/restaurants, or organize Gmail data itself.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The itinerary-building logic suggests generic activities from a places list and surfaces existing bookings for flights, hotels, and car rentals. It does not generate restaurant recommendations, nor does it compute transportation logistics such as routing, transfers, schedules, or movement plans between destinations.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

This skill reaches beyond itinerary generation and directly searches a user's Gmail through an external CLI, which expands its privilege boundary into mailbox access. In the context of a travel tool, this is sensitive because email contents can reveal full travel history, booking identifiers, and personal data, and the access occurs via a subprocess rather than a tightly scoped in-process API with visible consent handling.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/gmail_parser.py (reported line 50)May include surrounding context.

python
"--query", query,
            "--json"
        ]
        result = subprocess.run(cmd, capture_output=True, text=True, check=True,
                               env={**subprocess.os.environ, "GOG_KEYRING_PASSWORD": subprocess.os.environ.get("GOG_KEYRING_PASSWORD", "")})
        messages = json.loads(result.stdout)
        print(f"✅ Found {len(messages)} messages")

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The code reads a credential-related environment variable and forwards it to a subprocess without user-facing disclosure or any safeguards around exposure. Even though it does not print the password, passing credential material through process environments increases the sensitivity of the operation and can broaden exposure through debugging, process inspection on misconfigured systems, or accidental reuse by child processes.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The script writes extracted booking data to a local JSON file without any warning, consent prompt, retention policy, or protection of the output file. Because the data includes travel dates, hotel names, booking numbers, and other itinerary details, local storage can create a privacy and safety risk if the file is left on shared systems, synced storage, or insecure directories.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/places_fetcher.py (reported line 40)May include surrounding context.

python
try:
        # Use wttr.in format: city?format=j1
        cmd = ["curl", "-s", f"https://wttr.in/{city}?format=j1"]
        result = subprocess.run(cmd, capture_output=True, text=True, timeout=10)
        
        if result.returncode != 0:
            return None

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/weather_fetcher.py (reported line 29)May include surrounding context.

python
try:
        # Use wttr.in format: city?format=j1
        cmd = ["curl", "-s", f"https://wttr.in/{city}?format=j1"]
        result = subprocess.run(cmd, capture_output=True, text=True, timeout=10)
        
        if result.returncode != 0:
            return None

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The template adds OpenClaw branding and watermark content that is not part of the stated core function of generating a neutral travel itinerary. This is a supply-chain integrity and output-manipulation issue: generated documents are silently altered to include third-party branding, which can mislead users about authorship, violate white-label expectations, or create unauthorized endorsement/disclosure risks.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
78% confidence
Finding

The file includes attraction and food names in multiple East Asian scripts and transliterations, but it does not explain the language presentation choice or offer any user opt-in or alternative locale format. This can be a natural-language locale policy issue because the formatting implicitly forces a specific multilingual presentation style.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
83% confidence
Finding

The Seoul section presents names in Korean alongside Chinese-character renderings, but the file does not justify or document why that locale convention is being imposed. Absent an explicit rationale or user choice, this may violate language/locale policy expectations.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
90% confidence
Finding

The CLI forces the output language to one of four predefined options and defaults to "en". Under the policy, locale or language constraints should be user-selectable with opt-in or clearly justified; this file does not document such a justification.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
86% confidence
Finding

The HTML generator reads a template if present, but the code itself does not enforce print-ready formatting or dark-theme styling. Its built-in fallback is a very basic HTML page without styling, which does not match the stronger presentation guarantees in the manifest.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.