Back to skill

Security audit

TripIt

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly a TripIt email formatter, but it tells agents to retain a private TripIt calendar feed URL for reuse without adequate consent or secret-handling safeguards.

Install only if you are comfortable sending itinerary details to TripIt by email. Do not let the agent store your private TripIt iCal feed URL unless you explicitly choose that and have secure secret storage, redaction, and deletion controls; review generated email text before sending, especially when data was copied from untrusted booking messages.

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
SKILL.md:153
Finding
Insecure Persistent Storage of Private TripIt Calendar Feed URL<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:153-164` **Vulnerability Type**: Sensitive bearer URL stored without security controls **Risk Level**: Medium ### Vulnerable Documentation ```markdown 1. The user provides their TripIt iCal URL (found at **TripIt → Settings → Calendar Feed**), e.g.: `https://www.tripit.com/feed/ical/private/<hash>/tripit.ics` 2. Fetch the feed and look for the newly added item (match on confirmation number, dates, or summary text) 3. If the item doesn't appear after ~60 seconds, check: - Was the sender email linked to the TripIt account? - Was the email sent as plain text (not HTML)? - Were all required fields present? ```bash # Fetch and search the feed for a confirmation number curl -s "https://www.tripit.com/feed/ical/private/<hash>/tripit.ics" \ | grep -A5 "UA1234X" ``` **Tip:** Store the user's iCal feed URL so you can verify future sends without asking again. ``` ### Technical Analysis The private TripIt iCal URL contains a secret hash in its path and functions like a bearer credential: possession of the complete URL may be sufficient to retrieve the associated travel calendar without separate authentication. The Skill explicitly recommends storing this URL for future use but does not specify: - Explicit user consent for persistent retention - Use of an encrypted credential or secret store - Redaction from logs, transcripts, and diagnostic output - A retention period or deletion mechanism - Access controls limiting which sessions or tools can retrieve it - Rotation or revocation procedures after suspected disclosure Travel calendars can contain highly sensitive information, including travel dates, flight routes, accommodation details, and the periods during which a user may be away from home. Treating the feed URL as ordinary reusable state can therefore expose both personal data and physical-location information. ### Attack Path 1. The user supplies their private TripIt iCal feed UR ...[truncated 1230 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not store the private feed URL by default. Request it only when verification is required. 2. Obtain explicit informed consent before retaining the URL across sessions. 3. Store the URL only in an approved encrypted secret store, not in ordinary Agent memory, transcripts, configuration files, or logs. 4. Treat the entire URL as a credential and redact the private path and hash from all output and diagnostic messages. 5. Restrict access to the minimum Agent identity and tools that require calendar verification. 6. Define a limited retention period and provide the user with a way to inspect and delete the stored credential. 7. Never send the private feed URL to unrelated services, tools, or model contexts. 8. Advise users to regenerate the TripIt calendar feed URL after suspected exposure. 9. Replace the existing recommendation with guidance such as: ```markdown Do not persist the private iCal feed URL by default. If the user explicitly requests future automatic verification, store it only in an approved encrypted secret store, redact it from logs and responses, and provide a deletion option. Treat the URL as a bearer credential. ``` ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/tripit-email.py:27
Finding
TripIt Template-Structure Injection Through Unescaped Multiline Values<![CDATA[ ## Vulnerability Details **File Location**: `scripts/tripit-email.py:27-34` **Vulnerability Type**: Structured-text injection caused by insufficient output encoding **Risk Level**: Medium ### Vulnerable Code ```python def emit(label: str, value: str | None) -> str: """Emit a single 'Label : Value' line, or empty string if no value.""" if value is None or value == "": return "" str_value = str(value) if "\n" in str_value: return f"{label} : {str_value}\n***" return f"{label} : {str_value}" ``` ### Technical Analysis The `emit()` function inserts field values into a structured TripIt email without escaping or rejecting syntax that has control significance to the TripIt parser. When a value contains a newline, the function appends `***` after the entire value. This does not prevent the value itself from containing an earlier `***` terminator, a field label, or section markers such as: - `End of Flight Information` - `Hotel Information` - `End of Hotel Information` - `Confirmation # : ...` - `TripIt Approved` An attacker-controlled value can therefore terminate its intended multiline field and inject additional fields or object sections. For example, a malicious `notes` value could conceptually contain: ```text Legitimate note *** End of Activity Information Hotel Information Hotel name : Injected Reservation Check-in date : 2026-10-01 Check-out date : 2026-10-02 End of Hotel Information ``` The function would preserve these lines verbatim and append another `***` afterward. Because the generated output is intended to be sent to a parser that interprets these markers structurally, the injected content may be treated as fields or itinerary sections rather than as literal text. The issue affects any field passed through `emit()`, not only fields documented as multiline. There are no field-specific schemas, newline restrictions for single-line fields, reserved-marker checks, or output-encoding rules. ### Attac ...[truncated 1603 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Implement strict, field-aware validation before constructing the email: 1. Reject carriage returns and line feeds in every field that is defined as single-line. 2. Permit multiline content only for an explicit allowlist, such as `notes`, `restrictions`, and cancellation remarks. 3. Normalize `\r\n` and standalone `\r` to `\n` before validation. 4. Reject reserved syntax on any line of a multiline value, including: - `***` - `TripIt Approved` - Section start and end markers - Nested block markers such as `Traveler #N` and `Flight segment #N` 5. Reject lines matching TripIt field-label syntax where they could be interpreted as separate fields. 6. Enforce expected primitive types and reasonable maximum lengths for every field. 7. Apply the same validation to every item and nested segment in multi-item input. 8. Add tests demonstrating that injected terminators, field labels, and section markers cannot alter the generated structure. 9. Where supported by TripIt, use an official escaping mechanism rather than inventing an incompatible encoding. A hardened implementation should separate single-line and multiline emitters, for example: ```python RESERVED_LINES = { "***", "TripIt Approved", "Flight Information", "End of Flight Information", "Hotel Information", "End of Hotel Information", "Car Information", "End of Car Information", "Rail Information", "End of Rail Information", "Activity Information", "End of Activity Information", } def emit_single_line(label: str, value: object | None) -> str: if value is None or value == "": return "" text = str(value) if "\r" in text or "\n" in text: raise ValueError(f"{label} must be a single-line value") return f"{label} : {text}" def emit_multiline(label: str, value: object | None) -> str: if value is None or value == "": return "" text = str(value).replace("\r\n", "\n").replace("\r", ...[truncated 309 chars]
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 Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (17)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The script is a formatter/generator, not a TripIt management or email-sending tool. Its own docstring says it generates TripIt-formatted confirmation emails, and the implementation is limited to parsing JSON input, validating fields, building text sections, and printing output. There is no integration with email services, no network access, and no logic to send to plans@tripit.com. Additionally, supported object types are flight, hotel, activity, car, rail, and multi-item bundles; cruises are mentioned in the declared description but absent from the builders registry and CLI commands. The description therefore overstates the implemented capabilities in material ways.

Ae1

High
Category
analysis-evasion
Content
3. `tripit-email.py` generates the formatted email body
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
3. `tripit-email.py` generates the formatted email body
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
3. `tripit-email.py` generates the formatted email body
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
3. `tripit-email.py` generates the formatted email body
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
3. `tripit-email.py` generates the formatted email body
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
3. `tripit-email.py` generates the formatted email body
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
3. `tripit-email.py` generates the formatted email body
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
3. `tripit-email.py` generates the formatted email body
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
3. `tripit-email.py` generates the formatted email body
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
See [references/template-format.md](references/template-format.md) for the complete field list for each object type, including required vs optional fields and f
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Missing User Warnings

High
Confidence
97% confidence
Finding
This guidance encourages storing a private TripIt iCal URL without warning that it is a sensitive access token to the user's travel feed. Because the URL can expose ongoing and future itinerary data, retaining it without clear safeguards materially raises the risk of privacy compromise if the agent, logs, or storage are accessed by unauthorized parties.

Vague Triggers

Medium
Confidence
90% confidence
Finding
The manifest says to use the skill when the user asks to "add something to TripIt, sync a trip to TripIt, update their itinerary, or manage travel plans." The final phrase is broad and lacks constraints or negative examples, which could cause the skill to be invoked for general travel-planning requests not specifically intended for TripIt.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill encourages sending detailed travel information to a third-party email address without a clear privacy warning or explicit confirmation step. Travel itineraries contain sensitive personal data such as names, locations, dates, and confirmation numbers, so silent or insufficiently disclosed transfer can expose users to privacy and safety risks.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
| grep -A5 "UA1234X"
```

**Tip:** Store the user's iCal feed URL so you can verify future sends without asking again. The URL is stable — it doesn't change unless the user regenerates it.

## Gotchas
Confidence
84% confidence
Finding
The phrase 'without asking again' promotes ongoing reuse of sensitive access data and verification actions without renewed user awareness or consent. In the context of a private travel feed, this can normalize silent access to personal itinerary information and reduce opportunities for the user to limit or revoke access.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
The private TripIt iCal feed URL functions like a bearer secret: anyone with the URL can often read the user's travel itinerary without additional authentication. Instructing storage of that URL for future reuse increases the chance of unnecessary retention, leakage through logs or memory, and unauthorized access to sensitive travel data.

Ssd 3

Medium
Confidence
96% confidence
Finding
Persistent storage of a private calendar-feed URL exceeds what is necessary for one-time email generation and verification, violating data minimization principles. Retained travel-feed access increases the blast radius of compromise because an attacker or unintended process can repeatedly retrieve itinerary details over time.

Static analysis

No suspicious patterns detected.