/// SECURITY

Native PDF redaction — remove PII, not just cover it

Overlaid black boxes still leak. Real redaction removes the text from the PDF. Here is how the ASHDOCS redact-pdf endpoint works.

Document automation engineers, ASHDOCS
Published:
Last updated:

Native PDF redaction removes text from the PDF's content stream rather than drawing a black box on top of it. The distinction matters: overlaid redactions leak the underlying text to any tool that reads the raw PDF — copy-paste, pdftotext, and every search-engine crawler. ASHDOCS's POST /api/tools/redact-pdf/run uses PyMuPDF's add_redact_annot + apply_redactions to delete the glyphs, then re-serialises the document so nothing recoverable remains.

Why do overlaid redactions leak?

A black box drawn over text only hides it on screen. The words are still in the PDF’s content stream, so anyone can select and copy them, search the file, run a text extractor, or delete the box in a PDF editor. Highlights set to black, and white text on a black background, fail the same way.

Native redaction removes the matched characters from the content stream and then rewrites the file, so nothing is left under the box to recover. That’s what redact-pdf does: it marks each match with a redaction annotation and applies it with PyMuPDF, which deletes the underlying text before the document is saved.

What data types does redact-pdf detect out of the box?

The endpoint accepts a types array in options. Each type maps to a regex + validator. Credit-card matches are Luhn-validated so non-checksummed 16-digit strings (order numbers, tracking IDs) don't get erased.

TypePatternValidated?
email RFC 5322 subset Yes — TLD check
ssn US SSN (9 digits, formatted) Yes — no invalid area codes
credit_card 13–19 digits Yes — Luhn
phone E.164 + common US formats No
iban ISO 13616 Yes — checksum

What does a redaction request look like?

curl -X POST https://www.ashdocs.com/api/tools/redact-pdf/run \
  -H "X-API-Key: ash_live_xxxxxxxx" \
  -F "file=@contract.pdf" \
  -F 'options={
    "types": ["email", "ssn", "credit_card", "phone"]
  }'

What does the response include?

{
  "job_id": "job_01H...",
  "status": "completed",
  "output_files": [{ "url": "https://...redacted.pdf", "size_bytes": 84213 }],
  "redaction_summary": {
    "counts": { "email": 3, "ssn": 1, "credit_card": 0, "phone": 2 },
    "pages_affected": [1, 2, 5]
  }
}

The counts array tells you what was removed. The actual matched values are never returned — that would defeat the point.

Frequently asked questions

Does redact-pdf work on scanned PDFs?

Scanned PDFs run through OCR first to obtain a text layer, then the redaction pass removes matched glyphs. Confidence is lower on handwritten or heavily compressed scans — inspect the returned redaction_summary.confidence_floor before shipping to production.

Can I supply my own regex patterns?

Not yet. The types array is currently limited to the built-in detectors listed above. Custom pattern support is on the roadmap; subscribe to release notes on our blog to hear when it lands.

Is redaction reversible?

No. Once apply_redactions runs, the glyphs are gone from the content stream. That is the whole point — reversible redactions are the overlaid-black-box failure mode we exist to avoid.

Does redact-pdf work inside a pipeline?

Yes. The visual pipeline builder in the dashboard offers a redact-pdf step. Chain it after any extraction or conversion tool to produce a redacted output alongside the structured JSON, then deliver both to your webhook or destination in one atomic pipeline run.