PDF Redaction Failures: Por Que Seus Documentos “Sanitizados” Ainda Vazam Dados
Em fevereiro de 2024, a Adobe divulgou o CVE-2024-20767: uma vulnerabilidade no Acrobat DC que permitia leitura de conteúdo redacted através de manipulação de layers. Não foi um bug obscuro de parsing ou exploit de buffer overflow. Foi algo mais fundamental: o PDF estava tecnicamente correto segundo a especificação, mas a redação era cosmética. Um retângulo preto sobre texto ainda legível nas camadas inferiores do documento.
O problema não é novo. CVE-2023-26085, divulgado em abril de 2023, expunha informações sensíveis através de metadados em PDFs redacted. O UK Information Commissioner’s Office publicou guidance em 2020 após incidentes repetidos de vazamento em documentos públicos. A recomendação foi direta: validação automatizada obrigatória.
Pesquisas demonstram que 15-20% dos PDFs redacted publicamente disponíveis contêm texto oculto recuperável através de análise de streams. Isso não é teoria acadêmica. É documentação legal exposta, números de CPF vazados, informações médicas recuperáveis com strings e um editor de texto. Cada vazamento é potencialmente um breach reportável sob GDPR Article 32 e LGPD.
Anatomia de Uma Redação Quebrada
A Adobe documenta oficialmente 11 categorias de dados que podem vazar em PDFs aparentemente sanitizados: metadata, comments, file attachments, hidden layers, overlapping objects, previous versions, deleted content, form data, JavaScript, embedded search indices e bookmarks.
Essa lista não é exaustiva. É o mínimo documentado.
PDF é um formato de apresentação, não de armazenamento. Um documento pode ter múltiplas representações do mesmo conteúdo em diferentes estruturas internas. A especificação permite layers, objetos sobrepostos, texto em coordenadas negativas (fora da área visível), e objetos órfãos que não são renderizados mas permanecem no arquivo.
Redação visual - colocar um retângulo preto sobre texto - é trivialmente contornável. O texto continua na árvore de objetos do PDF. Metadados XMP (Extensible Metadata Platform) frequentemente preservam informações originais mesmo após redação aparente. Se o documento foi convertido de Word ou Google Docs, tracking metadata pode sobreviver ao processo.
A diferença entre “Apply Redactions” no Adobe Acrobat Pro DC e simplesmente cobrir texto visualmente? O primeiro remove permanentemente os objetos de texto da estrutura interna. O segundo só afeta a camada de renderização. A distinção é crítica e não óbvia para usuários não técnicos.
Detecção Multi-Camada: Quando Bibliotecas Discordam
A complexidade da especificação PDF cria uma oportunidade de validação: diferentes bibliotecas interpretam a estrutura de formas ligeiramente distintas. Quando PyMuPDF extrai mais texto que pdfplumber no mesmo documento, você provavelmente tem hidden content.
Um benchmark informal de 2023 mostrou PyMuPDF extraindo 8% mais texto que pdfplumber em um corpus de 1000 PDFs governamentais. Essa diferença não é bug - é interpretação de edge cases da especificação. E é exatamente o que queremos para validação.
import fitz # PyMuPDF
import pdfplumber
def detect_hidden_content(pdf_path):
"""
Compara extração de texto entre bibliotecas para detectar discrepâncias.
Diferenças significativas indicam potencial hidden content.
"""
# PyMuPDF com modo rawdict revela todos text layers
doc = fitz.open(pdf_path)
pymupdf_text = []
for page in doc:
blocks = page.get_text("rawdict")["blocks"]
for block in blocks:
if "lines" in block:
for line in block["lines"]:
for span in line["spans"]:
pymupdf_text.append(span["text"])
pymupdf_content = " ".join(pymupdf_text)
# pdfplumber com extração de coordenadas
with pdfplumber.open(pdf_path) as pdf:
plumber_text = []
for page in pdf.pages:
plumber_text.append(page.extract_text() or "")
plumber_content = " ".join(plumber_text)
# Análise de discrepância
pymupdf_len = len(pymupdf_content.strip())
plumber_len = len(plumber_content.strip())
discrepancy_ratio = abs(pymupdf_len - plumber_len) / max(pymupdf_len, 1)
return {
"pymupdf_chars": pymupdf_len,
"pdfplumber_chars": plumber_len,
"discrepancy": discrepancy_ratio,
"suspicious": discrepancy_ratio > 0.05 # 5% diferença é flag
}
Esse código identifica documentos onde a extração diverge significativamente. PyMuPDF processa mais agressivamente objetos de texto em posições incomuns. pdfplumber é mais conservador com objetos fora da geometria esperada. Quando há 5%+ de divergência, você tem um documento que precisa investigação manual.
O gotcha: nenhuma biblioteca Python tem 100% coverage da especificação PDF. Edge cases com encoding customizado escapam detecção. A solução não é escolher a “melhor” biblioteca - é usar múltiplas e identificar inconsistências.
Metadados: O Vazamento Silencioso
Texto redacted é óbvio. Metadados são insidiosos porque não aparecem na renderização normal do documento. XMP metadata pode conter autor original, histórico de edições, caminhos de arquivos internos, e até fragmentos de texto de versões anteriores.
pikepdf, baseado em QPDF, oferece .remove_unreferenced_resources() para eliminar objetos órfãos. PyPDF2 v3.0+ inclui .remove_text() mas não toca metadados XMP automaticamente. Você precisa processar ambos.
import pikepdf
from pikepdf import Pdf
def sanitize_metadata(input_path, output_path):
"""
Remove metadados XMP e objetos órfãos que podem conter dados residuais.
"""
pdf = Pdf.open(input_path)
# Remove XMP metadata
with pdf.open_metadata() as meta:
meta.clear()
# Remove objetos não referenciados (órfãos)
pdf.remove_unreferenced_resources()
# Linearize para eliminar estruturas de versões anteriores
pdf.save(output_path, linearize=True)
Linearização força reconstrução completa do PDF, eliminando fragmentos de edições anteriores que podem conter texto não redacted. O trade-off: documentos linearizados são otimizados para streaming web mas perdem algumas otimizações de tamanho de arquivo.
O Problema do OCR em Documentos Scanned
PDFs gerados por scanners são imagens com opcional OCR layer sobreposto. Redação em documentos scanned tem complexidade adicional: você precisa sanitizar tanto a imagem quanto o texto OCR.
OCR tem accuracy entre 85-98% dependendo da qualidade da imagem. Isso cria risco: se você redacta baseado no output do OCR e ele miss 2-15% do texto, o vazamento vai para produção. A imagem ainda contém o dado original.
A abordagem do Freedom of the Press Foundation no projeto ‘dangerzone’ é radical mas efetiva: converte PDF para pixels e depois reconstrói como PDF limpo. Garante sanitização completa, mas elimina searchability e acessibilidade do documento original. Para documentos públicos que precisam ser acessíveis (WCAG compliance), essa abordagem não é viável.
Não existe solução que preserve 100% funcionalidade E garanta 100% sanitização em PDFs scanned. Você escolhe entre segurança máxima (conversão para imagem) ou usabilidade (redação tradicional com risco residual).
Validação em Pipeline: Implementação Prática
Soluções enterprise como Relativity e Nuix reportam 99.9% accuracy com validação automática. Esse número vem dos vendors e deve ser tratado com ceticismo saudável, mas a arquitetura de validação multi-estágio é sólida.
Pipeline de três estágios funciona:
- Redação estrutural: Remove objetos de texto permanentemente usando pikepdf ou Adobe SDK
- Sanitização de metadados: XMP cleanup + removal de unreferenced resources
- Validação cruzada: Extração com múltiplas bibliotecas + comparação de outputs
O processamento leva ~3-5 segundos para PDFs de 50 páginas segundo documentação do pdfplumber. PyMuPDF é 2-3x mais rápido para documentos grandes. Para pipelines de alto volume (milhares de documentos/dia), paralelização é mandatória.
A validação deve falhar hard: se detecta discrepância entre bibliotecas, o documento não passa. Falsos positivos são aceitáveis. Falsos negativos em produção são breach reportável sob LGPD (equivalente ao Article 32 do GDPR) e podem custar multas de até 2% do faturamento.
Para empresas brasileiras processando documentos sensíveis (fintechs com comprovantes de renda, healthtechs com laudos médicos), a latência adicional de validação é trivial comparada ao risco regulatório. Um vazamento documentado pode significar R$500k-5M em multas dependendo do porte da empresa e gravidade do incidente.
Quando Não Confiar em Redação Automatizada
Modelos de ML para detecção de PII reportam F1-scores entre 0.85-0.95 para entidades comuns (CPF, datas de nascimento, números de registro médico). Isso significa 5-15% de erro. Em um lote de 10.000 documentos, você potencialmente vaza dados em 500-1500 PDFs.
NIST SP 800-88 Rev. 1 estabelece guidelines para sanitização que incluem validação humana após automação para documentos de alta sensibilidade. Isso não é recomendação teórica - é requirement para contratos governamentais e ambientes regulated.
Redação automatizada sozinha não é suficiente quando:
- Documentos têm tabelas complexas onde PII aparece em células sem padrão consistente
- PDFs contêm formulários interativos e JavaScript embedded
- Documentos multi-idioma onde detecção de entidades tem accuracy reduzida
- Scans de baixa qualidade onde OCR accuracy cai para 85%
Nesses cenários, o pipeline deve rotear para revisão manual. O custo operacional é alto, mas menor que o custo de um breach.
O Que Implementar Amanhã
Validação multi-biblioteca é implementável em um sprint. Integre PyMuPDF e pdfplumber no seu pipeline de documentos, compare outputs, flague discrepâncias maiores que 5%. Isso pega a maioria dos casos de hidden content.
Sanitização de metadados com pikepdf leva 30 minutos para adicionar ao código existente. Remove XMP, unreferenced resources, linearize o output. Essas três operações eliminam as categorias mais comuns de vazamento.
Para documentos scanned, aceite o trade-off: ou preserva searchability e aceita risco residual de 2-5%, ou converte para imagem e perde funcionalidade. Não existe terceira opção com tecnologia atual. A escolha depende do seu perfil de risco regulatório.
E o mais importante: assuma que sua solução não é perfeita. Nenhuma biblioteca Python cobre 100% da especificação PDF. Edge cases existem. Monitore, revise amostras, e esteja preparado para descobrir que algo vazou mesmo com validação. Ter runbook de resposta a incidente é mais realista que acreditar em sanitização perfeita.