Skip to content

Security Overview

TCPDF-Next is built on a security-first design philosophy. Every component, from cryptographic primitives to HTML parsing, is engineered to eliminate entire categories of vulnerabilities rather than patch them after discovery.

Security-First Design Philosophy

Security in TCPDF-Next is not a feature bolted on top of a legacy codebase. It is an architectural constraint that influenced every design decision from day one:

  • Deny by default — External resource loading, network requests, and file access are blocked unless explicitly allowed.
  • Fail closed — When a security check cannot be performed (e.g., OCSP responder unreachable), the operation fails rather than proceeding insecurely.
  • Defense in depth — Multiple independent layers of protection ensure that a single bypass does not compromise the system.
  • Minimal attack surface — Zero runtime Composer dependencies. All cryptographic operations use PHP's built-in OpenSSL and Sodium extensions.

AES-256 Encryption (No Legacy Algorithms)

TCPDF-Next exclusively implements AES-256 encryption as defined in PDF 2.0 (ISO 32000-2, Revision 6). All legacy and insecure algorithms are permanently rejected:

AlgorithmStatusReason
AES-256-CBCSupportedPDF 2.0 standard, no known practical attacks
RC4 (40-bit / 128-bit)ProhibitedStream cipher with known biases and practical attacks
AES-128ProhibitedInsufficient margin for long-term confidentiality
DES / 3DESNot implementedBlock size and key length vulnerabilities
MD5 (for key derivation)ProhibitedCollision attacks since 2004
php
use YeeeFang\TcpdfNext\Encryption\EncryptionAlgorithm;
use YeeeFang\TcpdfNext\Encryption\Permissions;

$pdf->setEncryption()
    ->setAlgorithm(EncryptionAlgorithm::AES256)
    ->setUserPassword('reader-password')
    ->setOwnerPassword('admin-password')
    ->setPermissions(
        Permissions::PRINT_HIGH_QUALITY
        | Permissions::COPY
        | Permissions::ACCESSIBILITY
    )
    ->apply();

PAdES Digital Signatures (B-B through B-LTA)

TCPDF-Next implements the full PAdES Baseline Profile (ETSI EN 319 142-1) for digital signatures with increasing levels of long-term validity:

LevelDescriptionValidation Period
PAdES B-BBasic CMS signature with signing certificateCertificate validity (~1-3 years)
PAdES B-T+ RFC 3161 timestamp from a trusted TSATSA certificate validity (~10-15 years)
PAdES B-LT+ Document Security Store with OCSP/CRL dataAlgorithm security lifetime (~15-30 years)
PAdES B-LTA+ Archive timestamp for indefinite re-validationIndefinite (with periodic re-timestamping)

For implementation details, see PAdES B-LTA Signatures.

SSRF Protection with DNS Pinning

All external network requests (image fetching, TSA communication, OCSP lookups) pass through a hardened HTTP client with built-in SSRF protection:

  • DNS pinning — Resolved IP addresses are validated before connection. Private network ranges (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16), loopback (127.0.0.0/8), and link-local (169.254.0.0/16) addresses are blocked.
  • Protocol restriction — Only https:// is permitted by default. Plain http:// is rejected unless explicitly allowed.
  • Domain allowlisting — Configurable allowlist for permitted external domains.
  • Redirect following — Limited to a configurable maximum (default: 3) with re-validation at each hop.

Path Traversal Prevention

All file path operations are sanitized to prevent directory traversal attacks:

  • Embedded file names are stripped of path separators and .. sequences.
  • Font file paths are resolved to absolute canonical paths and validated against allowed directories.
  • Image paths referenced in HTML are restricted to explicitly configured directories via ResourcePolicy.

#[\SensitiveParameter] on Passwords and Keys

All method parameters that accept passwords, passphrases, private keys, or PINs are annotated with PHP 8.2's #[\SensitiveParameter] attribute. This ensures that sensitive values are automatically redacted from stack traces, error logs, and exception messages:

php
public function setUserPassword(
    #[\SensitiveParameter] string $password
): self { /* ... */ }

public function setCertificate(
    string $certificate,
    #[\SensitiveParameter] string $privateKey,
    #[\SensitiveParameter] string $passphrase = ''
): self { /* ... */ }

#[\NoDiscard] on Critical Return Values

Methods that return security-critical results (validation outcomes, signature verification) are annotated with #[\NoDiscard] to prevent callers from ignoring return values:

php
#[\NoDiscard]
public function validate(string $pdfPath): ValidationResult { /* ... */ }

#[\NoDiscard]
public function verify(): SignatureVerificationResult { /* ... */ }

Ignoring these return values produces a compiler warning, catching a common class of security bugs at development time.

PHPStan Level 8 (Zero Errors, No Baseline)

The entire codebase passes PHPStan static analysis at the strictest level (level 8) with zero errors and no baseline file. This means:

  • No @phpstan-ignore annotations anywhere in the codebase.
  • No suppressed error categories.
  • All types are fully specified, including generics and template types.
  • All dead code paths are eliminated.

100% declare(strict_types=1)

Every PHP file in TCPDF-Next begins with declare(strict_types=1). There are no exceptions. This eliminates an entire class of type coercion bugs that have historically led to security vulnerabilities in PHP applications.

OWASP Compliance Considerations

TCPDF-Next addresses the following OWASP categories relevant to PDF generation libraries:

OWASP CategoryMitigation
A01 — Broken Access ControlGranular PDF permissions, certificate-based encryption
A02 — Cryptographic FailuresAES-256 only, no weak algorithms, constant-time comparisons
A03 — InjectionHTML sanitization, path traversal prevention, no eval()
A05 — Security MisconfigurationSecure defaults, deny-by-default resource policies
A06 — Vulnerable ComponentsZero runtime dependencies, built-in crypto via OpenSSL/Sodium
A07 — Authentication Failures#[\SensitiveParameter], secure memory wiping via sodium_memzero()
A10 — SSRFDNS pinning, private network blocking, domain allowlisting

Security Documentation

Explore the full security documentation:

Released under the LGPL-3.0-or-later License.