T01 · Skill Instruction Hijacking
- Location
scripts/extract_rides_gateway.py:98- Finding
Untrusted Receipt Content Can Influence Model Instructions and Persisted Ride Records
- Content
View full analysis
Vulnerability Details
File Location:
scripts/extract_rides_gateway.py, lines 98-103
Vulnerability Type: Indirect prompt injection
Risk Level: MediumVulnerable Code:
python def call_gateway(email_obj: dict, timeout: int = 180): base_url, token, model = load_gateway_settings() prompt = SYSTEM_PROMPT + "\n\nEmail JSON:\n" + json.dumps(email_obj, ensure_ascii=False) payload = { 'model': model, 'input': prompt, }Related output handling in
scripts/extract_rides_gateway.py, lines 124-143:python def normalize(result: dict, email_obj: dict): result = result or {} source = result.get('source') or {} ride = result.get('ride') or {} return { 'provider': result.get('provider') or email_obj.get('provider') or 'Other', 'source': { 'gmail_message_id': source.get('gmail_message_id') or email_obj.get('gmail_message_id'), 'email_date': source.get('email_date') or email_obj.get('email_date'), 'subject': source.get('subject') or email_obj.get('subject'), }, 'ride': {k: ride.get(k) for k in [ 'start_time_text','end_time_text','total_text','currency','amount','pickup','dropoff', 'pickup_city','pickup_country','dropoff_city','dropoff_country','payment_method','driver', 'distance_text','duration_text','notes' ]}, } def write_results(out_path: Path, results: list[dict]): out_path.parent.mkdir(parents=True, exist_ok=True) out_path.write_text(json.dumps(results, ensure_ascii=False, indent=2) + '\n', encoding='utf-8')Technical Analysis
Receipt subjects, snippets, senders, and full HTML are attacker-influenced data. The extractor serializes the entire email object directly after the system instructions in a single model input. It does not explicitly tell the model that email content is untrusted ...[truncated 2227 chars]
- Remediation
View remediation
Remediation Suggestions
- Clearly delimit receipt content as untrusted data and add an explicit instruction that text inside the receipt must never be interpreted as commands.
- Use separate system and user message roles, or structured input fields, if the Gateway API supports them.
- Validate responses against a strict JSON Schema before persistence.
- Enforce expected types, maximum lengths, and a fixed provider allowlist.
- Reject unexpected nested objects, unknown fields, control characters, and excessively long textual values.
- Preserve authoritative metadata such as Gmail message ID and provider exclusively from the fetched email object rather than accepting model-provided replacements.
- When generating insights, serialize stored fields as quoted untrusted data and repeat that no embedded instructions may be followed.
- Record validation failures and require review rather than silently persisting suspicious model output.
