Skip to content

Commit 672ea8e

Browse files
1 parent 2105dd1 commit 672ea8e

2 files changed

Lines changed: 121 additions & 0 deletions

File tree

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
{
2+
"schema_version": "1.4.0",
3+
"id": "GHSA-5mq8-78gm-pjmq",
4+
"modified": "2026-03-06T18:39:35Z",
5+
"published": "2026-03-06T18:39:35Z",
6+
"aliases": [
7+
"CVE-2026-30830"
8+
],
9+
"summary": "defuddle vulnerable to XSS via unescaped string interpolation in _findContentBySchemaText image tag",
10+
"details": "### Summary\n\nThe `_findContentBySchemaText` method in `src/defuddle.ts` interpolates image `src` and `alt` attributes directly into an HTML string without escaping:\n\n```typescript\nhtml += `<img src=\"${imageSrc}\" alt=\"${imageAlt}\">`;\n```\n\nAn attacker can use a `\"` in the `alt` attribute to break out of the attribute context and inject event handlers. This is a separate vulnerability from the sanitization bypass fixed in f154cb7 — the injection happens during string construction, not in the DOM, so `_stripUnsafeElements` cannot catch it.\n\n### Details\n\nWhen `_findContentBySchemaText` finds a sibling image outside the matched content element, it reads the image's `src` and `alt` attributes via `getAttribute()` and interpolates them into a template literal. `getAttribute('alt')` returns the raw attribute value. If the alt contains `\"`, it terminates the `alt` attribute in the interpolated HTML string, and subsequent content becomes new attributes (including event handlers).\n\nThe recently added `_stripUnsafeElements()` (commit f154cb7) strips `on*` attributes from DOM elements, but the `alt` attribute's name is `alt` (not `on*`), so it is preserved with its full value. The `onload` handler is created by the string interpolation, not present in the original DOM.\n\n### PoC\n\nInput HTML:\n\n```html\n<!DOCTYPE html>\n<html>\n<head>\n<title>PoC</title>\n<script type=\"application/ld+json\">\n{\"@type\": \"Article\", \"text\": \"Long article text repeated many times to exceed the extracted content word count. Long article text repeated many times to exceed the extracted content word count. Long article text repeated many times to exceed the extracted content word count.\"}\n</script>\n</head>\n<body>\n<article><p>Short.</p></article>\n<div class=\"post-container\">\n <p>Extra text to inflate parent word count padding padding padding.</p>\n <div class=\"post-body\">\n Long article text repeated many times to exceed the extracted content word count. Long article text repeated many times to exceed the extracted content word count. Long article text repeated many times to exceed the extracted content word count.\n </div>\n <img width=\"800\" height=\"600\" src=\"https://example.com/photo.jpg\" alt='pwned\" onload=\"alert(document.cookie)'>\n</div>\n</body>\n</html>\n```\n\nOutput:\n\n```html\n<img src=\"https://example.com/photo.jpg\" alt=\"pwned\" onload=\"alert(document.cookie)\">\n```\n\nThe `onload` event handler is injected as a separate HTML attribute.\n\n### Impact\n\nXSS in any application that renders defuddle's HTML output (browser extensions, web clippers, reader modes). The attack requires crafted HTML with schema.org structured data that triggers the `_findContentBySchemaText` fallback, combined with a sibling image whose `alt` attribute contains a quote character followed by an event handler.\n\n### Suggested Fix\n\nUse DOM API instead of string interpolation:\n\n```typescript\nif (imageSrc) {\n const img = this.doc.createElement('img');\n img.setAttribute('src', imageSrc);\n img.setAttribute('alt', imageAlt);\n html += img.outerHTML;\n}\n```\n\nThis ensures attribute values are properly escaped by the DOM serializer.",
11+
"severity": [
12+
{
13+
"type": "CVSS_V4",
14+
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:N/VI:N/VA:N/SC:L/SI:L/SA:N/E:P"
15+
}
16+
],
17+
"affected": [
18+
{
19+
"package": {
20+
"ecosystem": "npm",
21+
"name": "defuddle"
22+
},
23+
"ranges": [
24+
{
25+
"type": "ECOSYSTEM",
26+
"events": [
27+
{
28+
"introduced": "0"
29+
},
30+
{
31+
"fixed": "0.9.0"
32+
}
33+
]
34+
}
35+
]
36+
}
37+
],
38+
"references": [
39+
{
40+
"type": "WEB",
41+
"url": "https://github.com/kepano/defuddle/security/advisories/GHSA-5mq8-78gm-pjmq"
42+
},
43+
{
44+
"type": "WEB",
45+
"url": "https://github.com/kepano/defuddle/commit/f154cb740ee603431b69638273af737a27156df9"
46+
},
47+
{
48+
"type": "PACKAGE",
49+
"url": "https://github.com/kepano/defuddle"
50+
}
51+
],
52+
"database_specific": {
53+
"cwe_ids": [
54+
"CWE-79"
55+
],
56+
"severity": "LOW",
57+
"github_reviewed": true,
58+
"github_reviewed_at": "2026-03-06T18:39:35Z",
59+
"nvd_published_at": null
60+
}
61+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
{
2+
"schema_version": "1.4.0",
3+
"id": "GHSA-rw8p-c6hf-q3pg",
4+
"modified": "2026-03-06T18:40:58Z",
5+
"published": "2026-03-06T18:40:58Z",
6+
"aliases": [
7+
"CVE-2026-30834"
8+
],
9+
"summary": "PinchTab has SSRF with Full Response Exfiltration via Download Handler",
10+
"details": "# SSRF with Full Response Exfiltration via Download Handler\n\n### Summary\nA Server-Side Request Forgery (SSRF) vulnerability in the `/download` endpoint allows any user with API access to induce the PinchTab server to make requests to arbitrary URLs, including internal network services and local system files, and exfiltrate the full response content.\n\n### Details\nThe `GET /download?url=<url>` handler in [download.go](file:///Users/quan.m.le/Workspaces/pinchtab/internal/handlers/download.go#L78) accepts a user-controlled `url` parameter and passes it directly to `chromedp.Navigate(dlURL)` without any validation or sanitization.\n\n```go\n// internal/handlers/download.go:78\nif err := chromedp.Run(ctx, chromedp.Navigate(dlURL)); err != nil {\n return fmt.Errorf(\"navigate to %s: %w\", dlURL, err)\n}\n```\n\nSince the request is performed by the headless Chrome browser instance managed by PinchTab, it can access:\n1. **Local Files**: Using the `file://` scheme (e.g., `file:///etc/passwd`).\n2. **Internal Services**: Accessing services bound to `localhost` or internal network IPs that are not reachable from the outside.\n3. **Cloud Metadata**: Accessing cloud provider metadata endpoints (e.g., `169.254.169.254`).\n\nThe server then returns the captured response body directly to the attacker, enabling full exfiltration of sensitive data.\n\n### PoC\nTo reproduce the vulnerability, ensure the PinchTab server is running and accessible.\n\n1. **Local File Read**:\n Execute the following curl command to read `/etc/passwd`:\n ```bash\n curl -X GET \"http://localhost:9867/download?url=file:///etc/passwd\"\n ```\n\n2. **Internal Service Access**:\n If a service is running on `localhost:8080`, access it via:\n ```bash\n curl -X GET \"http://localhost:9867/download?url=http://localhost:8080/internal-admin\"\n ```\n\nThe response will contain the content of the targeted file or service.\n\n\nPoC video:\n\nhttps://github.com/user-attachments/assets/b15776ea-13cc-4534-ba7b-6d5c4e0ee74f\n\n### Impact\nThis is a high-severity SSRF vulnerability. It impacts the confidentiality and security of the host system and the internal network where PinchTab is deployed. Attackers can exfiltrate sensitive system files, probe internal network infrastructure, and potentially gain access to internal management interfaces or cloud credentials. While PinchTab is often used in local environments, any deployment where the API is exposed (even with authentication) allows a compromised or malicious client to pivot into the internal network.",
11+
"severity": [
12+
{
13+
"type": "CVSS_V3",
14+
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N"
15+
}
16+
],
17+
"affected": [
18+
{
19+
"package": {
20+
"ecosystem": "Go",
21+
"name": "github.com/pinchtab/pinchtab/cmd/pinchtab"
22+
},
23+
"ranges": [
24+
{
25+
"type": "ECOSYSTEM",
26+
"events": [
27+
{
28+
"introduced": "0"
29+
},
30+
{
31+
"fixed": "0.7.7"
32+
}
33+
]
34+
}
35+
],
36+
"database_specific": {
37+
"last_known_affected_version_range": "<= 0.7.6"
38+
}
39+
}
40+
],
41+
"references": [
42+
{
43+
"type": "WEB",
44+
"url": "https://github.com/pinchtab/pinchtab/security/advisories/GHSA-rw8p-c6hf-q3pg"
45+
},
46+
{
47+
"type": "PACKAGE",
48+
"url": "https://github.com/pinchtab/pinchtab"
49+
}
50+
],
51+
"database_specific": {
52+
"cwe_ids": [
53+
"CWE-918"
54+
],
55+
"severity": "HIGH",
56+
"github_reviewed": true,
57+
"github_reviewed_at": "2026-03-06T18:40:58Z",
58+
"nvd_published_at": null
59+
}
60+
}

0 commit comments

Comments
 (0)