{
  "schemaVersion": "1.0",
  "canonicalPage": "https://fileformat.co/ext/pdf",
  "inspectorUrl": "https://fileformat.co/inspect",
  "spec": {
    "slug": "pdf",
    "extension": ".pdf",
    "aliases": [],
    "name": "Portable Document Format (ISO 32000)",
    "shortName": "PDF",
    "category": "devtools-security",
    "tier": 1,
    "summary": "Object-graph document format parsed bottom-up from its trailing `startxref` and `%%EOF` markers—primary battleground for AI RAG table extraction and active `/JavaScript` upload sanitization.",
    "technicalNotes": "Many PDF readers scan for `%PDF-` anywhere within the first 1024 bytes! Combined with bottom-up `xref` parsing, PDF is a frequent polyglot target unless offset `0x00` is strictly enforced.",
    "mimeTypes": [
      "application/pdf"
    ],
    "identifiers": {
      "pronomPuid": "fmt/276",
      "specUrl": "https://opensource.adobe.com/dc-acrobat-sdk-docs/pdfstandards/PDF32000_2008.pdf"
    },
    "binarySignature": {
      "endianness": "text",
      "magicBytes": [
        {
          "offset": 0,
          "hex": "25 50 44 46 2D",
          "ascii": "%PDF-",
          "description": "5-byte '%PDF-' header followed by version (e.g. 1.7 or 2.0)"
        }
      ],
      "containerFamily": null,
      "headerLayout": [
        {
          "offset": "0x00 - 0x07",
          "byteOffset": 0,
          "byteLength": 8,
          "lengthLabel": "8 B",
          "dataType": "ascii",
          "fieldName": "pdf_version",
          "description": "'%PDF-1.7' version header"
        },
        {
          "offset": "0x09 - 0x0E",
          "byteOffset": 9,
          "byteLength": 6,
          "lengthLabel": "6 B",
          "dataType": "uint8[6]",
          "fieldName": "binary_comment",
          "description": "High-bit comment (%\\xE2\\xE3\\xCF\\xD3) signaling binary content"
        },
        {
          "offset": "EOF-64..",
          "byteOffset": 16,
          "byteLength": 16,
          "lengthLabel": "var",
          "dataType": "ascii",
          "fieldName": "xref_trailer",
          "description": "Cross-reference table, startxref byte offset & %%EOF"
        }
      ]
    },
    "securityProfile": {
      "riskLevel": "high",
      "allowsArbitraryCodeOrMacros": true,
      "xxeRisk": false,
      "polyglotPrependRisk": true,
      "pickleDeserializationRisk": false,
      "uploadValidationNotes": "Require '%PDF-' strictly at offset 0x00 (blocking polyglots), verify trailing '%%EOF', and reject or flatten `/JavaScript`, `/JS`, `/Launch`, and `/EmbeddedFiles` actions."
    },
    "codeSnippets": {
      "python": "import os, sys\nwith open(sys.argv[1], \"rb\") as f:\n    head = f.read(8)\n    f.seek(-64, os.SEEK_END)\n    tail = f.read(64)\n    assert head.startswith(b\"%PDF-\") and b\"%%EOF\" in tail\n    print(f\"Valid {head.decode('ascii', 'ignore').strip()}\")",
      "typescript": "export async function checkPdf(file: File) {\n  const head = new TextDecoder().decode(await file.slice(0, 8).arrayBuffer());\n  const tail = new TextDecoder().decode(await file.slice(Math.max(0, file.size - 64)).arrayBuffer());\n  return { version: head.trim(), hasEof: tail.includes('%%EOF') };\n}",
      "rust": "use std::{fs::File, io::Read};\nfn main() -> std::io::Result<()> {\n    let mut h = [0u8; 8];\n    File::open(std::env::args().nth(1).expect(\"usage: <prog> <file>\"))?.read_exact(&mut h)?;\n    println!(\"PDF header: {}\", String::from_utf8_lossy(&h).trim());\n    Ok(())\n}",
      "go": "package main\nimport (\"fmt\"; \"io\"; \"os\")\nfunc main() {\n    f, err := os.Open(os.Args[1])\n    if err != nil {\n        fmt.Fprintln(os.Stderr, \"open:\", err)\n        os.Exit(1)\n    }\n    defer f.Close()\n    h := make([]byte, 8)\n    if _, err := io.ReadFull(f, h); err != nil {\n        fmt.Fprintln(os.Stderr, \"read:\", err)\n        os.Exit(1)\n    }\n    fmt.Println(string(h))\n}"
    },
    "relatedFormats": [
      "xlsx",
      "csv",
      "png"
    ],
    "verifiedAt": "2026-11-14T16:31:19Z"
  },
  "samples": [
    {
      "id": "pdf-minimal",
      "filename": "minimal-1page.pdf",
      "variant": "minimal",
      "title": "Minimal Valid 1-Page PDF",
      "description": "Real single-page PDF generated by reportlab and parseable by pypdf.",
      "localPath": "/fixtures/v1/pdf/minimal-1page.pdf",
      "cdnUrl": "https://fileformat.co/fixtures/v1/pdf/minimal-1page.pdf",
      "sizeBytes": 1376,
      "sha256": "3d510c3e24ce7b489b9861769c0643c75e13c5364754a752186baaf68546a0d7",
      "expectValid": true
    },
    {
      "id": "pdf-realistic",
      "filename": "rag-two-column-financial-table.pdf",
      "variant": "realistic",
      "title": "Two-Column Financial Table PDF (AI RAG Parser Fixture)",
      "description": "Real 2-page reportlab PDF with financial Table cells, heading hierarchy and rule lines for RAG extractor benchmarking.",
      "localPath": "/fixtures/v1/pdf/rag-two-column-financial-table.pdf",
      "cdnUrl": "https://fileformat.co/fixtures/v1/pdf/rag-two-column-financial-table.pdf",
      "sizeBytes": 2945,
      "sha256": "d547e41d47d805961980567b9776216f65f3744ea2906789dfa6bb629c40569a",
      "expectValid": true
    },
    {
      "id": "pdf-edge-case",
      "filename": "benign-js-dictionary-canary.pdf",
      "variant": "edge-case",
      "title": "PDF Containing Benign `/JavaScript` Dictionary Marker",
      "description": "Real reportlab PDF with an inert /JavaScript name tree added via pypdf (FILEFORMAT_CO_BENIGN_TEST_MARKER) for security scanner verification.",
      "localPath": "/fixtures/v1/pdf/benign-js-dictionary-canary.pdf",
      "cdnUrl": "https://fileformat.co/fixtures/v1/pdf/benign-js-dictionary-canary.pdf",
      "sizeBytes": 1091,
      "sha256": "dc38f4be9c4ba992b60254dab44878c1c111e7d7bd06169e6a3836a48850cfc3",
      "expectValid": true,
      "edgeCaseTag": "Benign /JavaScript Canary"
    }
  ]
}