
Generate 67 malicious PDF test files for testing phone-home callbacks, SSRF, XSS, XXE, NTLM credential theft, and data exfiltration in PDF viewers, converters, and web applications. Can be used with Burp Collaborator or Interact.sh
Used for penetration testing, bug bounty hunting, and/or red-teaming etc. I created this tool because I needed a tool to generate a bunch of PDF files with various links. Educational and professional purposes only.
pip install -r requirements.txt
python3 malicious-pdf.py burp-collaborator-url
Output will be written to the output/ directory as: test1.pdf, test2.pdf, test3.pdf etc.
--output-dir DIR Directory to save generated PDF files (default: output/)
--no-credit Do not embed credit/attribution metadata in generated PDFs
--obfuscate LEVEL Obfuscation level (0-3):
0 = None (default)
1 = PDF name hex encoding + string octal/hex encoding
2 = Level 1 + JS bracket notation + javascript: URI case/whitespace obfuscation
3 = Level 2 + FlateDecode stream compression
Example with obfuscation:
python3 malicious-pdf.py https://your-interact-sh-url --obfuscate 2
Maximum obfuscation (Level 4 wraps JS payloads in a base64 decoder stub so the original API calls never appear as literal substrings):
python3 malicious-pdf.py https://your-interact-sh-url --obfuscate 4
/V, base64 decoder) defeat naïve /JS regex scannersClick to expand all 70 test cases
| Test File | Function | CVE/Reference | Attack Vector | Method | Impact |
|---|---|---|---|---|---|
| test1.pdf | create_malpdf() |
CVE-2018-4993 | External file access | /GoToE action with UNC path |
Network callback via file system |
| test1_1.pdf | create_malpdf() |
CVE-2018-4993 | External file access | /GoToE action with HTTPS URL |
Network callback via HTTPS |
| test2.pdf | create_malpdf2() |
XFA form submission | Form data exfiltration | XDP form with submit event | Automatic form submission |
| test3.pdf | create_malpdf3() |
JavaScript injection | Code execution | /OpenAction with app.openDoc() |
External document loading |
| test4.pdf | create_malpdf4() |
CVE-2019-7089 | XSLT injection | XFA with external XSLT stylesheet | UNC path callback |
| test5.pdf | create_malpdf5() |
PDF101 research | URI action | /URI action type |
DNS prefetching/HTTP request |
| test6.pdf | create_malpdf6() |
PDF101 research | Launch action | /Launch with external URL |
External resource execution |
| test7.pdf | create_malpdf7() |
PDF101 research | Remote PDF | /GoToR action |
Remote PDF loading |
| test8.pdf | create_malpdf8() |
PDF101 research | Form submission | /SubmitForm with HTML flags |
Form data submission |
| test9.pdf | create_malpdf9() |
PDF101 research | Data import | /ImportData action |
External data import |
| test10.pdf | create_malpdf10() |
CVE-2017-10951 | JavaScript execution | Foxit this.getURL() callback |
Network callback via Foxit Reader |
| test11.pdf | create_malpdf11() |
EICAR test | AV detection | Embedded EICAR string | Anti-virus testing |
| test12.pdf | create_malpdf12() |
CVE-2014-8453 | FormCalc data exfiltration | XFA FormCalc Post() function |
Same-origin data exfiltration with cookies |
| test13.pdf | create_malpdf13() |
Request injection | CRLF header injection | XFA submit textEncoding CRLF |
HTTP header manipulation |
| test14.svg | create_malpdf14() |
ImageMagick shell injection | Shell injection via SVG/MSL | SVG-MSL polyglot authenticate attribute |
Remote code execution via ImageMagick |
| test15.pdf | create_malpdf15() |
PDF specification | FormCalc header injection | XFA FormCalc Post() with custom headers |
Arbitrary HTTP header injection |
| test16.pdf | create_malpdf16() |
PDF specification | JavaScript via GotoE | /GoToE with javascript: URI |
Browser XSS when PDF embedded via <embed>/<object> |
| test17.pdf | create_malpdf17() |
CVE-2014-8452 | XXE injection | XMLData.parse() external entity |
XML external entity resolution |
| test18.pdf | create_malpdf18() |
PortSwigger research | Annotation URI injection | Unescaped parens inject JS action via duplicate /A key |
XSS via PDF-Lib/jsPDF output |
| test19.pdf | create_malpdf19() |
PortSwigger research | PV auto-execution | /AA /PV Screen annotation fires JS on page visible |
Automatic code execution (Acrobat) |
| test20.pdf | create_malpdf20() |
PortSwigger research | PC close trigger | /AA /PC annotation fires JS on page close |
Code execution on close (Acrobat) |
| test21.pdf | create_malpdf21() |
PortSwigger research | SubmitForm SubmitPDF | /SubmitForm with Flags 256 sends entire PDF |
Full PDF content exfiltration |
| test22.pdf | create_malpdf22() |
PortSwigger research | JS submitForm() | this.submitForm() with cSubmitAs: "PDF" |
PDF content submission (Acrobat) |
| test23.pdf | create_malpdf23() |
PortSwigger research | Widget button injection | Invisible /Btn widget covering page, JS on click |
Code execution (Chrome/PDFium) |
| test24.pdf | create_malpdf24() |
PortSwigger research | Text field SSRF | Widget /Tx field with submitForm() POST |
Blind SSRF via form data |
| test25.pdf | create_malpdf25() |
PortSwigger research | Content extraction | getPageNthWord() reads all text and exfiltrates |
Rendered text exfiltration |
| test26.pdf | create_malpdf26() |
PortSwigger research | Mouseover trigger | /AA /E annotation fires JS on mouse enter |
Code execution on hover (PDFium) |
| ~~test27~~ | — | — | Removed | Duplicate of test3 (Acrobat OpenAction JS) + test23 (Chrome Widget Btn) | — |
| test28.pdf | create_malpdf28() |
PortSwigger research | URL hijacking | Unescaped parens inject new /URI action |
Click redirection via PDF-Lib/jsPDF |
| test29.pdf | create_malpdf29() |
CVE-2024-4367 | FontMatrix injection | Type1 font FontMatrix string breaks out of c.transform() |
Arbitrary JS execution in PDF.js (Firefox < 126) |
| test30.pdf | create_malpdf30() |
PDF101 research | External XObject stream | Image XObject fetches data from remote URL via /FS /URL |
Silent callback via page rendering (no actions/JS) |
| test31.pdf | create_malpdf31() |
PDF101 research | Thread action | /S /Thread with remote FileSpec |
Network callback via thread reference |
| test32.pdf | create_malpdf32() |
PDF101 research | Launch with print | /Launch with /Win << /O /print >> forces remote fetch |
Network callback via print operation |
| test33_1.pdf | create_malpdf33_1() |
PDF101 research | JS: this.submitForm() |
Acrobat JS form submission callback | Acrobat Reader |
| test33_2.pdf | create_malpdf33_2() |
PDF101 research | JS: this.getURL() |
Acrobat JS URL fetch | Acrobat Reader |
| test33_3.pdf | create_malpdf33_3() |
PDF101 research | JS: app.launchURL() |
Acrobat JS launch URL | Acrobat Reader |
| test33_4.pdf | create_malpdf33_4() |
PDF101 research | JS: app.media.getURLData() |
Acrobat JS media fetch | Acrobat Reader |
| test33_5.pdf | create_malpdf33_5() |
PDF101 research | JS: SOAP.connect() |
Acrobat JS SOAP connection | Acrobat Reader |
| test33_6.pdf | create_malpdf33_6() |
PDF101 research | JS: SOAP.request() |
Acrobat JS SOAP request | Acrobat Reader |
| test33_7.pdf | create_malpdf33_7() |
PDF101 research | JS: this.importDataObject() |
Acrobat JS data import | Acrobat Reader |
| test33_8.pdf | create_malpdf33_8() |
PDF101 research | JS: app.openDoc() |
Acrobat JS open document | Acrobat Reader |
| test33_9.pdf | create_malpdf33_9() |
PDF101 research | JS: fetch() |
Web API callback (PDF.js/browser) | Firefox/PDF.js |
| test33_10.pdf | create_malpdf33_10() |
PDF101 research | JS: XMLHttpRequest |
Web API callback (PDF.js/browser) | Firefox/PDF.js |
| test33_11.pdf | create_malpdf33_11() |
PDF101 research | JS: new Image() |
Web API image callback (PDF.js/browser) | Firefox/PDF.js |
| test33_12.pdf | create_malpdf33_12() |
PDF101 research | JS: WebSocket |
Web API WebSocket callback (PDF.js/browser) | Firefox/PDF.js |
| test33_13.pdf | create_malpdf33_13() |
Adobe 0-day blog (Apr 2026) | JS: RSS.addFeed() |
Acrobat JS RSS feed callback | Acrobat Reader |
| test33_14.pdf | create_malpdf33_14() |
Adobe 0-day blog (Apr 2026) | JS: util.readFileIntoStream() + SOAP.request() |
Local file read + exfil chain (try/catch error path also callbacks) | Acrobat Reader |
| test33_15.pdf | create_malpdf33_15() |
Adobe 0-day blog (Apr 2026) | Form-field-staged JS loader | Base64 payload in /Tx widget /V, decoded via getField() + util.stringFromStream |
Acrobat Reader |
| test34_1.pdf | create_malpdf34_1() |
PDF101 research | UNC: XObject stream | Image XObject with UNC path | NTLM theft via page rendering |
| test34_2.pdf | create_malpdf34_2() |
PDF101 research | UNC: GoToR | /GoToR action with UNC FileSpec |
NTLM theft via remote PDF |
| test34_3.pdf | create_malpdf34_3() |
PDF101 research | UNC: Thread | /Thread action with UNC FileSpec |
NTLM theft via thread reference |
| test34_4.pdf | create_malpdf34_4() |
PDF101 research | UNC: URI | /URI action with UNC path |
NTLM theft via URI action |
| test34_5.pdf | create_malpdf34_5() |
PDF101 research | UNC: JS submitForm | this.submitForm() with UNC path |
NTLM theft via JS form submission |
$ claude mcp add malicious-pdf \
-- python -m otcore.mcp_server <graph>