Back to skill

Security audit

Travel Itinerary Planner

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent travel itinerary generator, but it needs Review because its helper script can silently overwrite existing Markdown files and can embed insufficiently validated Markdown inputs.

Review this skill before installing if it will run in a project directory with important Markdown files. Use a dedicated output folder, avoid user- or third-party-controlled image URLs/currency values, and do not allow it to write over existing Markdown unless that is explicitly intended.

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)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/build_trip_plan.py:77
Finding

Markdown Content Injection Through Insufficiently Validated Image URLs and Currency Values

Content
View full analysis
str: value = (raw or "").strip() parsed = urlparse(value) if parsed.scheme != "https" or not parsed.netloc: raise ValueError(f"--{field_name} only accepts valid HTTPS URLs.") if parsed.username or parsed.password: raise ValueError(f"--{field_name} cannot include URL credentials.") if "\n" in value or "\r" in value: raise ValueError(f"--{field_name} contains invalid newline characters.") return value ``` ```python def format_currency(amount: int, currency: str) -> str: return f"{currency} {amount:,}" ``` ```python def build_gallery(destination: str, image_urls: list[str]) -> str: if not image_urls: return "\n".join( [ "- Add at least 3 trusted HTTPS image URLs for this destination.", "- Prefer official tourism boards, museums, or your own photos.", ] ) lines = [] for idx, url in enumerate(image_urls, start=1): lines.append(f"![{destination} photo {idx}]({url})") return "\n".join(lines) ``` ```python cover = ( f"![{destination} cover]({args.cover_image})" if args.cover_image else "Add one trusted HTTPS cover image URL." ) ``` ```python parser.add_argument( "--currency", default="CNY", help="Currency code shown in budget table (default: CNY).", ) ``` ```python if args.cover_image: args.cover_image = validate_https_url(args.cover_image, "cover-image") if args.image_url: args.image_url = [validate_https_url(url, "image-url") for url in args.image_url] ``` ### Technical Analysis The URL validator checks only that a value has an HTTPS ...[truncated 2895 chars]
Remediation
View remediation
str: value = (raw or "").strip().upper() if not re.fullmatch(r"[A-Z]{3}", value): raise ValueError("--currency must be a three-letter ISO-style currency code.") return value ``` 2. Validate image URLs for their specific Markdown context. Reject characters that can terminate or restructure a Markdown destination, including unencoded parentheses, whitespace, backslashes, and control characters. 3. Reconstruct accepted URLs from parsed components instead of returning the original untrusted string. 4. Percent-encode path, query, and fragment components where appropriate. Do not encode the URL as one opaque string because doing so can damage the scheme and host. 5. Consider using angle-bracket Markdown destinations if supported by the target renderer, while still rejecting angle brackets and control characters: ```markdown ![Caption]() ``` 6. If generated Markdown will be rendered as HTML, configure the renderer to disable raw HTML and restrict remote resource loading. 7. Add regression tests covering closing parentheses, spaces, backslashes, pipes, newlines, embedded HTML, and attempts to append secondary Markdown links or images. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/build_trip_plan.py:326
Finding

Arbitrary Overwrite of Existing Markdown Files Within the Working Directory

Content
View full analysis
Path: if output: resolved = Path(output).expanduser().resolve() cwd = Path.cwd().resolve() if not _is_relative_to(resolved, cwd): raise ValueError("--output must stay inside the current working directory.") if resolved.suffix.lower() != ".md": raise ValueError("--output must be a .md file.") return resolved filename = ( f"trip-plan-{slugify(destination)}-{start_date.isoformat()}-{end_date.isoformat()}.md" ) return Path.cwd() / filename ``` ```python def main() -> int: try: args = parse_args() output_path = build_output_path( output=args.output or None, destination=args.destination, start_date=args.start_date, end_date=args.end_date, ) output_path.parent.mkdir(parents=True, exist_ok=True) output_path.write_text(render_markdown(args), encoding="utf-8") print(f"Wrote trip plan: {output_path}") return 0 except ValueError as exc: print(f"Error: {exc}") return 2 ``` ### Technical Analysis The output-path validation correctly confines the resolved path to the current working directory and requires a `.md` extension. However, it does not require the destination to be a new file. `Path.write_text()` opens the destination for writing and truncates an existing file. As a result, any writable Markdown file under the current working directory can be silently replaced, including project documentation or `SKILL.md`. The documented safety guardrail states that output should remain under the current directory and use a Markdown extens ...[truncated 1645 chars]
Remediation
View remediation
Vulnerability Patterns
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (3)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill invokes a local script that writes Markdown output and instructs verification of live travel facts from external sources, which implies file-write and network-capable behavior. Because the manifest declares no explicit tool scope or allowed-tools boundary, an agent may grant or infer broader capabilities than intended, weakening least-privilege controls and making misuse or prompt-injection-assisted tool abuse more likely.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The description uses very broad activation cues such as general trip planning, route design, and 'input time and location,' which can match many ordinary conversations. Over-broad triggers increase the chance of unintended auto-invocation, causing the agent to collect data, perform network lookups, or write files when the user did not clearly request this specific skill.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The description includes the trigger phrase "图文并茂 travel itinerary," which signals a Chinese-language invocation pattern, but the file does not state that language choice is optional or user-selected. This can be interpreted as a locale-specific behavior without explicit opt-in or documented justification.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.