Aug 22, 2026·7 min read·3 visits
Unsanitized input interpolation in site extractors allows remote attackers to execute arbitrary client-side JavaScript via crafted page metadata.
CVE-2026-61824 is a high-severity Cross-Site Scripting (XSS) vulnerability in kepano/defuddle before version 0.19.1. Custom site extractors for platforms such as X/Twitter, Substack, and YouTube constructed HTML representations via template string interpolation without output escaping. This allowed malicious pages to bypass standard parser sanitization routines and execute arbitrary JavaScript.
The defuddle library is an open-source tool designed to parse and clean up raw HTML documents. It extracts core article content and metadata from various web domains. To streamline parsing for complex platforms, the library implements specialized site extractors for platforms such as X/Twitter, Substack, and YouTube. These extractors run on matched domains to isolate specific structured content like headings, descriptions, and media before downstream consumption.
A high-severity Cross-Site Scripting (XSS) vulnerability, tracked as CVE-2026-61824 and GHSA-jg4p-g6xj-4qmf, exists in defuddle versions prior to 0.19.1. The flaw resides within the custom extractor modules, specifically in how they construct HTML strings from parsed DOM attributes. In affected versions, the library interpolates page-derived values directly into template literals without context-aware HTML entity encoding.
The impact is compounded by an architectural bypass. While the main pipeline executes standard DOM-based sanitization routines, output produced by site extractors bypassed this phase. Consequently, a malicious page or an attacker who can inject attributes into a target platform's DOM can cause downstream applications to render unescaped, executable HTML. This leads to arbitrary script execution in the context of the user viewing the processed content.
The root cause of CVE-2026-61824 lies in the combination of missing output encoding and a sanitization architectural bypass within the site extractor implementations. The affected extractor files include src/extractors/x-article.ts, src/extractors/substack.ts, and src/extractors/youtube.ts. These modules target specific DOM components on their respective platforms to scrape rich metadata, such as header image alternate descriptions (alt), media sources (src), Open Graph tags (og:image), and video descriptions.
During this extraction phase, raw DOM attribute values are extracted via methods like getAttribute() or querySelector(). The extractors then compile these strings into HTML representations using JavaScript template literals. Because these values are derived from arbitrary third-party pages, they must be treated as untrusted input. However, the library directly interpolated these values without sanitizing quote characters (" or '), allowing an attacker to escape the attribute boundaries.
A secondary and critical structural failure occurred within the buildExtractorResponse() function. Unlike the primary document parsing pipeline, which feeds raw elements through an internal _stripUnsafeElements() sanitizer, the extractor response was returned with minimal sanitization. The pipeline only resolved relative URLs in buildExtractorResponse() before emitting the final string. This lack of centralized sanitization meant that any malformed HTML constructed during the extraction stage passed directly to downstream applications.
To understand the mechanics of the vulnerability, we analyze the vulnerable code path in src/extractors/x-article.ts. In this file, the header image's alt description was retrieved and prepared for template string interpolation as shown below:
// Vulnerable pattern in src/extractors/x-article.ts
const alt = headerPhoto.getAttribute('alt')?.replace(/\s+/g, ' ').trim() || 'Image';
return `<img src="${this.upgradeImageSrc(src)}" alt="${alt}">`;If the alt attribute of the target image contains a double quote character followed by an event handler, the resulting string breaks out of the HTML attribute block. For example, an alt value of x" onerror="alert(document.cookie) renders as <img src="url" alt="x" onerror="alert(document.cookie)">.
The patch merged in commit baf2eaef61d334ef595b28c89e5c5e89e52daf7f introduces a dual-layer mitigation. First, it implements context-aware escaping on individual template interpolations using escapeHtml(). Second, it implements a central choke-point sanitizer _sanitizeExtractorHtml in src/defuddle.ts to process all extractor-generated HTML blocks.
// Patched centralized sanitizer in src/defuddle.ts
private _sanitizeExtractorHtml(html: string): string {
if (!html) return html;
const container = this.doc.createElement('div');
container.appendChild(parseHTML(this.doc, html));
this._stripUnsafeElements(container);
this.resolveRelativeUrls(container);
return serializeHTML(container);
}By converting the generated string back into a temporary DOM tree and executing _stripUnsafeElements() on it, the library ensures that even if an individual extractor fails to sanitize its template literals, the centralized pipeline strips any inline event handlers or malicious protocols (such as javascript: links) before serialization.
Exploitation of CVE-2026-61824 requires an attacker to place a crafted payload within an element processed by one of the supported site extractors. On X (formerly Twitter), Substack, or YouTube, the attacker modifies metadata properties that the extractors parse. For example, configuring an article on X with a header image having a malicious alt attribute acts as the delivery vector.
<!-- Attacker-controlled source DOM on x.com -->
<div data-testid="tweetPhoto">
<img src="https://example.com/legit.jpg" alt='x" onerror="alert(1)'>
</div>When the victim's application scrapes this target page using an unpatched version of defuddle, the XArticleExtractor matches the domain pattern. The scraper extracts the alt string verbatim, producing the unescaped payload shown in the Mermaid diagram below.
If the host application takes the output from the content property of the DefuddleResponse and inserts it directly into its DOM (e.g., via innerHTML in a browser or inside an Electron application), the injected onerror handler triggers immediately. This execution occurs under the origin of the hosting application, bypassing the sandbox boundary of the original scraped domain.
The vulnerability carries a CVSS base score of 8.2 (High). Since the attack vector is Network (AV:N), exploitation can occur remotely without local access. No privileges (PR:N) are required to conduct the attack, as any public-facing or accessible content on the scraped platform can contain the payload. However, exploitation requires User Interaction (UI:R) because a downstream application must ingest and display the scraped page content to a user.
The security scope of this vulnerability is considered Changed (S:C). The script executes not within the original origin (e.g., x.com or substack.com), but within the domain context of the host application rendering the parsed HTML. This shift allows an attacker to exploit the trust relationship of the rendering application, exposing all session data, authentication tokens, and private client-side databases stored under that application's origin.
If the rendering application runs in a privileged context, such as a desktop application built on Electron, a Cross-Site Scripting vulnerability can escalate to Remote Code Execution (RCE). An attacker who can execute arbitrary JavaScript in an Electron renderer node can often access Node.js APIs if context isolation is disabled or bypassed. Consequently, this vulnerability must be treated with high priority in applications that automate web scraping and parsing.
The primary remediation path is upgrading the defuddle library to version 0.19.1 or higher. This update introduces the centralized sanitization choke-point and context-aware escaping on individual extractors. The update can be performed using standard package management tools:
# Upgrade defuddle via npm
npm install defuddle@0.19.1In environments where immediate upgrading is not feasible, downstream sanitization must be enforced. Host applications must treat the output from DefuddleResponse.content as untrusted and process it using a dedicated, resilient HTML sanitization library. Libraries such as DOMPurify (for browser-based environments) or sanitize-html (for Node.js runtimes) should be configured to strip event handlers and unsafe URL schemes.
import DOMPurify from 'dompurify';
const response = await Defuddle(doc, url);
// Implement mandatory downstream sanitization
const cleanHtml = DOMPurify.sanitize(response.content, {
ALLOWED_TAGS: ['img', 'p', 'br', 'h1', 'div'],
ALLOWED_ATTR: ['src', 'alt', 'class']
});Developers should adopt a defensive development posture. Even when using parsing libraries that claim to sanitize output, the rendering application should maintain a strict Content Security Policy (CSP). Implementing a robust CSP that restricts script execution sources and blocks inline scripts ('unsafe-inline') provides a critical layer of defense, neutralizing XSS payloads even if a bypass occurs in the parser pipeline.
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:L/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
defuddle kepano | < 0.19.1 | 0.19.1 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-79 |
| Attack Vector | Network |
| CVSS Score | 8.2 (High) |
| Exploit Status | Proof-of-Concept in tests |
| KEV Status | Not Listed |
| Ransomware Use | No |
The software does not neutralize or incorrectly neutralizes user-controlled input before it is placed in output that is used as a web page that is served to other users.
A critical SQL injection vulnerability exists in the GeoTools open-source Java library. This vulnerability is situated within the post-processing phase of OGC Filter conversion inside the PostGIS DataStore module. Specifically, the `jsonArrayContains` function does not validate or sanitize its arguments before constructing PostgreSQL SQL/JSON path evaluation queries. An unauthenticated remote attacker can exploit this weakness by submitting crafted filters via standard OGC services like WFS or WMS to execute arbitrary SQL commands on the underlying database system.
A high-severity vulnerability exists in KeystoneJS, a popular Node.js CMS and GraphQL framework, where the query resolution engine fails to validate signed negative integers within the pagination subsystem. Unauthenticated remote attackers can leverage this flaw to bypass the 'graphql.maxTake' safety boundary. By sending large negative values in the 'take' query parameter, the underlying Prisma ORM interprets the value as an instruction to fetch rows from the end of the collection, allowing malicious actors to bypass pagination limits, trigger database resource exhaustion, and execute application-level Denial of Service (DoS) attacks.
A critical path traversal vulnerability in Atlantis allows authenticated users or repository contributors to execute directory operations outside of the repository directory boundary via crafted workspace parameters in configuration files or API requests.
CVE-2026-76905 is a high-severity Denial of Service (DoS) vulnerability in the getkin/kin-openapi library, specifically inside the openapi3filter sub-package. When processing multipart/form-data request validation errors, a missing nil-pointer guard causes a Go runtime panic during error formatting. This panic terminates the active server process if no recovery handler is present, resulting in a total denial of service. The vulnerability affects versions from v0.10.0 to v0.140.0, and is resolved in v0.141.0.
A critical server-side template injection (SSTI) vulnerability exists in the Volt template engine of the Phalcon PHP framework. In versions 5.15.0 and earlier, raw AST token values for filter arguments in the 'join' filter are directly spliced into the generated PHP template code. This allows an attacker who can influence Volt templates to execute arbitrary PHP code during template rendering.
CVE-2026-61539 is a critical remote code execution vulnerability in Xinference, an inference API framework for open-source LLMs. In version 2.5.0 and earlier, model-generated outputs representing Llama3 tool calls are passed directly to Python's built-in eval() function inside the parser components. By manipulating conversational input or injecting instructions, an attacker can influence the LLM to output a Python expression containing malicious system commands, resulting in unauthenticated remote code execution on the host. This vulnerability has been resolved in Xinference version 2.7.0.