Skip to content

Latest commit

 

History

4 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

pdf-redact

Two scripts for redacting sensitive information from PDFs:

  • generate_wordlist.py — generates a text file of all variants of personal info (names, SSNs, phone numbers, etc.)
  • redact_pdf.py — redacts terms from a PDF or a folder of PDFs using that wordlist

Setup

uv venv
uv pip install -e .

Requires Python 3.9+. Runtime dependency: pymupdf.


Typical workflow

# 1. Generate a wordlist from personal info
python3 generate_wordlist.py \
  --name "John Michael Doe" \
  --ssn "345-34-2345" \
  --dob "01-01-1990" \
  --phone "555-555-0000" \
  --email "john@example.com" \
  --address "123 Main St, Springfield, IL 62701" \
  -o wordlist.txt

# 2. Redact a folder of PDFs using the wordlist
python3 redact_pdf.py -i ./docs/ -w wordlist.txt

Output PDFs are saved alongside the originals as <name>_redacted.pdf.


generate_wordlist.py

Generates a plain-text wordlist (one term per line) covering all common variants of each input field. All matching in redact_pdf.py is case-insensitive, so case variants are not generated.

Options

Flag Description
--name "Full Name" Full name — repeatable or comma-separated
--ssn "SSN" Social Security Number — repeatable or comma-separated
--dob "DOB" Date of birth (MM-DD-YYYY or YYYY-MM-DD) — repeatable or comma-separated
--phone "Phone" Phone number — repeatable or comma-separated
--email "Email" Email address — repeatable or comma-separated
--address "Address" Mailing address (Street, City, ST ZIP)
-o FILE Output file (default: stdout)
-a, --append Append to existing file, deduplicating against current contents; creates file if missing

All fields except --address accept multiple values either by repeating the flag or using comma separation:

--name "John Doe" --name "Jane Smith"
# or
--name "John Doe, Jane Smith"

Variants generated per field

Name — full name, reversed (Doe, John), first+last, first+middle, each token, initial combos (J. Doe, J.M. Doe, John M. Doe), hyphen variants

SSN — dashes (345-34-2345), spaces (345 34 2345), dots (345.34.2345), no separator (345342345), masked last-4 variants (XXX-XX-2345, ***-**-2345, xxx-xx-2345, XXXXX2345, *****2345)

DOB — US numeric formats, ISO, European (when unambiguous), 2-digit year, no-separator compact (01011990, 19900101), named month, abbreviated month, ordinal day (January 1st, 1990)

Phone(555) 555-0000, (555)555-0000, 555-555-0000, 555.555.0000, 5555550000, 555 555 0000, and all of those with +1 and 1 country code prefixes

Email — as-is, local part as standalone (if not generic like info or admin), subaddress tag stripped (john+work@john@)

Address — full address, street only (with abbreviation expansion, e.g. StStreet), city+state (abbreviated and full, e.g. Springfield, IL and Springfield, Illinois), city, ZIP, no-comma variant

Examples

# Multiple people, append to existing file
python3 generate_wordlist.py --name "John Doe" --ssn "345-34-2345" -o wordlist.txt
python3 generate_wordlist.py --name "Jane Smith" --phone "555-999-1234" -a -o wordlist.txt

# Pipe to redact in one step
python3 generate_wordlist.py --name "John Doe" --ssn "345-34-2345" | \
  python3 redact_pdf.py -i input.pdf -w /dev/stdin -o output.pdf

redact_pdf.py

Performs true redaction — removes text from the PDF content stream, not just a visual overlay. Images and vector graphics are left untouched.

Matching is case-insensitive by default.

Note: Scanned or image-only PDFs will yield zero matches. OCR must be run first.

Options

Flag Description
-i FILE|DIR Input PDF or folder (required)
-o FILE Output PDF — required for single file, ignored in folder mode
-w TERM [TERM...] Terms to redact, or a path to a .txt wordlist file
--log FILE Write detailed per-file output to a log file (folder mode)
--color R,G,B Redaction fill color as floats 0.0–1.0 (default: 0,0,0 black)
--case-sensitive Enable case-sensitive matching
--dry-run Count matches without writing output
--verbose Print per-page match details (written to log in folder mode)
--workers N Parallel workers for folder mode (default: CPU count; 1 = sequential)

Single file

python3 redact_pdf.py -i input.pdf -w wordlist.txt -o output.pdf
python3 redact_pdf.py -i input.pdf -w "John Doe" "confidential" -o output.pdf

Folder mode

Processes all *.pdf files in the folder in parallel. Already-redacted *_redacted.pdf files are skipped. Outputs <name>_redacted.pdf alongside each original.

python3 redact_pdf.py -i ./docs/ -w wordlist.txt
python3 redact_pdf.py -i ./docs/ -w wordlist.txt --log redact.log --verbose
python3 redact_pdf.py -i ./docs/ -w wordlist.txt --workers 4

The console shows a progress line per file as it completes. All detail (per-page hits, per-term counts, warnings) is written to --log if provided:

[info] Found 8 PDF file(s) — using 4 worker(s)
[info] Detailed log : redact.log

  [1/8]  12%  contract.pdf (14 matches)
  [2/8]  25%  invoice.pdf (0 matches)  ⚠ no matches
  ...

Folder summary:
  File              Matches  Pages affected
  ----------------  -------  --------------
  contract.pdf      14       3/10
  invoice.pdf       0        0/2

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages