How pdf-inspector Handles Password-Protected Encrypted PDFs in Rust

pdf-inspector processes encrypted PDFs by detecting encryption at load time, accepting an optional password through its PdfOptions API, and attempting decryption with the provided password or falling back to an empty password for owner-only protection.

Encrypted PDF handling is a critical capability for any document processing library. The firecrawl/pdf-inspector repository implements a robust, multi-layered approach to password-protected PDFs that integrates seamlessly into both its Rust API and CLI interface. This article explains exactly how the library detects, decrypts, and processes encrypted documents based on the actual source code implementation.

PDF Options: Configuring Password Protection

The entry point for password handling begins with PdfOptions, the configuration builder exposed in src/lib.rs. This struct contains a password: Option<String> field that stores the optional decryption key (L254-L260).

use pdf_inspector::PdfOptions;

// Create options with a password
let opts = PdfOptions::new().password("secret123");

Security-conscious design is evident in the builder's implementation. The password() method deliberately redacts the password from Debug output to prevent accidental logging of sensitive credentials (L190-L199). This ensures that diagnostic logs never expose the actual password value.

Document Loading with Password Support

All PDF loading operations in pdf-inspector route through password-aware functions. The two primary entry points are:

  • load_document_from_path_with_password – for file-based loading
  • load_document_from_mem_with_password – for in-memory PDF data

Both functions accept Option<&str> for the password parameter (L3475-L3490). These functions delegate to load_document_bytes, which orchestrates the actual decryption logic.

Detecting Encryption at Runtime

The load_document_bytes function implements automatic encryption detection. It first attempts to load the PDF normally using lopdf::Document::load_mem. If either of these conditions occurs, it triggers the decryption fallback (L3528-L3532):

  • The loaded document returns true from is_encrypted()
  • The loader returns an encryption-related lopdf::Error

This approach avoids unnecessary decryption attempts on unencrypted documents while ensuring encrypted files are properly handled.

The Decryption Strategy

When encryption is detected, pdf-inspector invokes decrypt_document_bytes with a carefully designed retry strategy (L3538-L3542):

// Pseudocode representing the actual implementation
let password_to_try = provided_password.unwrap_or("");
let result = try_decrypt_with_password(password_to_try);

if result.is_err() && provided_password.is_some() {
    // Retry with empty password for owner-only encryption
    try_decrypt_with_password("")
}

The function uses lopdf::LoadOptions::with_password for the actual decryption. Key behaviors include:

  • User password provided – passed directly to lopdf
  • No password provided – defaults to empty string for owner-only encryption
  • Retry logic – if the provided password fails, attempts empty password as fallback (L3545-L3547)

Public API Integration

The high-level helper process_pdf_with_options bridges the configuration to execution. It forwards the password stored in PdfOptions directly to the internal loader (L292-L298):

use pdf_inspector::{process_pdf_with_options, PdfOptions};

// Process encrypted PDF with password
let opts = PdfOptions::new().password("secret123");
let result = process_pdf_with_options("encrypted.pdf", opts)?;

// Attempt without password — returns Err for encrypted files
let fail = process_pdf_with_options("encrypted.pdf", PdfOptions::new());

CLI Password Support

The pdf2md binary exposes password functionality through the --password flag. Implementation in src/bin/pdf2md.rs (L242-L287) parses this argument and forwards it through extract_text_with_positions_pages_with_password, ensuring parity between programmatic and command-line usage:


# Convert encrypted PDF to Markdown

pdf2md --password secret123 encrypted.pdf -o output.md

# Without password — clear error for encrypted files

pdf2md encrypted.pdf  # fails if PDF is encrypted

Testing Encrypted PDF Handling

The test suite in tests/integration_tests.rs validates three critical scenarios (L3899-L3918):

  1. No password supplied – operation fails with appropriate error
  2. Wrong password provided – decryption fails, error propagated
  3. Correct password provided – successful document processing

These integration tests ensure that pdf-inspector never silently processes encrypted content and provides clear feedback when authentication fails.

Summary

  • PdfOptions provides the configuration interface with automatic password redaction in debug output
  • Automatic detection identifies encrypted PDFs during initial load attempts
  • Smart decryption tries provided passwords first, then falls back to empty password for owner-only protection
  • Unified API exposes password support across library methods and CLI tools
  • Comprehensive testing verifies failure modes and success paths for encrypted documents

Frequently Asked Questions

What happens if I don't provide a password for an encrypted PDF?

pdf-inspector attempts decryption with an empty string, which succeeds only for owner-only encrypted PDFs. For user-password-protected documents, the operation returns an error that clearly indicates decryption failure. The library never processes encrypted content without authentication.

How does pdf-inspector protect passwords from appearing in logs?

The PdfOptions builder implements a custom Debug trait that redacts the password field, displaying "[REDACTED]" instead of the actual value (L190-L199). This prevents accidental credential exposure in stack traces and log files.

Can pdf-inspector crack or bypass PDF encryption?

No. The library relies entirely on lopdf for decryption and only attempts the specific password provided by the caller (plus an empty string fallback). There is no brute-force capability, password recovery, or encryption bypass implemented in the source code.

What encryption standards does pdf-inspector support?

Encryption support depends on the underlying lopdf crate. pdf-inspector passes passwords through to lopdf::LoadOptions::with_password, which handles standard PDF encryption including RC4 and AES-based methods defined in the PDF specification.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →