Revision: 8 Timestamp: 2026-02-15 01:13:05 UTC
This document reviews the current security state of the CFF and CFF2 implementation in the PascalType2 library. The audit covers vulnerabilities identified in the Project Zero research "One font vulnerability to rule them all" and more recent industry findings.
The PascalType2 CFF/CFF2 implementation is designed with security-first principles, utilizing managed types and explicit logical boundaries to prevent the memory corruption and stack exhaustion issues prevalent in legacy font engines. The implementation is verified to be resilient against all identified CharString and DICT parsing exploit vectors.
| Bulletin / CVE | Status | Protection Mechanism |
|---|---|---|
| MS15-021 | PASS | Enforced recursion and stack limits; validated instruction stream bounds. |
| MS15-044 | PASS | Automated zero-initialization of transient memory. |
| APSB15-10 | PASS | Robust opcode validation and bounds-checked operands. |
| CVE-2020-0938 | PASS | Non-implementation of legacy Master design operators (BLEND). |
| CVE-2020-1020 | PASS | Isolated interpreter state prevents out-of-bounds stack manipulation. |
| CVE-2023-25193 | PASS | Variable font variation limits are inherently safe due to non-implementation of CFF2 variations. |
- CVEs: CVE-2015-0074
- Status: PASS
- Mechanism: The
Interpretmethod inPascalType.Tables.OpenType.PostScript.CharStrings.pasenforces a strict recursion depth limit of 32 (CMaxRecursionDepth). This proactively prevents system stack exhaustion from recursive subroutine calls.
- CVEs: CVE-2015-0087, CVE-2015-3095
- Status: PASS
- Mechanism: The
hintmaskandcntrmaskoperators perform explicit bounds checks against the CharString byte array before advancing the instruction pointer, raisingECffHintMaskOverflowon violation. Furthermore, the BCD parser in DICT table loading validates stream positions to prevent infinite loops on malformed or unterminated data.
- CVEs: CVE-2015-0088
- Status: PASS
- Mechanism: The interpreter utilizes a dynamic
TList<Single>with a hard capacity limit of 192 elements (CMaxStackDepth), raisingECffStackOverflowif exceeded. All operations includingPop,index, androllare guarded by bounds checks.
- CVEs: CVE-2015-0089, CVE-2015-3049, CVE-2015-1670
- Status: PASS
- Mechanism: The
FTransientArrayis zero-initialized during interpreter setup. Thegetandputoperators are strictly limited to the defined array bounds, preventing arbitrary memory access or disclosure.
- CVEs: CVE-2015-0090, CVE-2015-0092, CVE-2015-0093, CVE-2020-0938, CVE-2020-1020
- Status: PASS (Protected by non-implementation)
- Mechanism: Legacy and deprecated operators (
LOAD,STORE,BLEND,STOREWV) are deliberately excluded from the implementation. Executing these opcodes in the PascalType2 interpreter result in a no-op (stack clear), eliminating the primary attack surface used for complex ROP-based exploits in historical vulnerabilities. Regression tests inTest/TestCFFSecurity.pasguard against accidental implementation of these vulnerable paths.
- Status: PASS
- Mechanism: The interpreter distinguishes between fatal logical errors and non-fatal warnings. Only exceptions of type
EPascalTypeWarningare swallowed by theExecutemethod to allow for graceful degradation. FatalEPascalTypeErrorexceptions bubble up, ensuring that security violations or severe corruption are explicitly handled.
The following sequences are verified in Test/TestCFFSecurity.pas to ensure ongoing compliance with security boundaries.
- Recursion:
20 0a 0ecalls Subr 0 containing20 0a 0b(Infinite recursion test). Verified to raiseECffMaxRecursion. - Stack Overflow:
8b ... 8b(Push > 192 elements test). Verified to raiseECffStackOverflow. - OOB Mask:
8b 8b 8b 8b 01 13(Mask skip beyond EOB test). Verified to raiseECffHintMaskOverflow. - Unterminated DICT:
1e 12 34(BCD parsing beyond DICT size test). Verified to raiseEPascalTypeError. - Unimplemented Operators: Opcode
16(BLEND), Escape13(LOAD), Escape16(callothersubr), etc. Verified to be safe (no-op/stack clear).