{"id":"CVE-2026-57232","aliases":["EUVD-2026-51596","GHSA-87mg-5grr-rhwh"],"status":"published","title":"Contao: Server-Side Request Forgery (SSRF) via Unvalidated RSS Feed URL in Feed Reader Module","description":"Contao is an Open Source CMS. From 5.3.35 through 5.3.47 and from 5.7.0-RC1 through 5.7.8, the Feed Reader front-end module passes configured RSS feed URLs from FeedReaderController::getResponse() to feedIo-\u003eread() without scheme or private-address validation, allowing a backend user with module-edit permissions to make the server request internal network services, loopback addresses, or cloud metadata endpoints. In core-bundle/src/Controller/FrontendModule/FeedReaderController.php, the getResponse() function iterates over the configured feed URLs and passes each one directly to the HTTP client (via $this-\u003efeedIo-\u003eread($url, new Feed())) with no validation, while the DCA field definition for rss_feed in tl_module.php carries no URL scheme or host validation and the HTTP client is wired as @psr18.http_client (Symfony HttpClient) with no SSRF protection configured, since NoPrivateNetworkHttpClient is not used. This issue is fixed in versions 5.3.48.","severity":{"version":"3.1","score":3.1,"vector":"CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:L/I:N/A:N","level":"low","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-09","score":0.0029,"percentile":0.21664,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":true},"cwes":["CWE-918"],"published":"2026-07-31T18:29:53Z","modified":"2026-10-28T02:30:49Z","fixes":[{"ecosystem":"Packagist","package":"contao/contao","fixed_in":["5.3.48","5.7.9"],"sources":["ghsa","osv"]},{"ecosystem":"Packagist","package":"contao/core-bundle","fixed_in":["5.3.48","5.7.9"],"sources":["ghsa","osv"]}],"affected":[{"source":"ghsa","ecosystem":"Packagist","package":"contao/contao","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"5.3.35"},{"fixed":"5.3.48"}]}]},{"source":"ghsa","ecosystem":"Packagist","package":"contao/contao","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"5.4.0"},{"fixed":"5.7.9"}]}]},{"source":"ghsa","ecosystem":"Packagist","package":"contao/core-bundle","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"5.3.35"},{"fixed":"5.3.48"}]}]},{"source":"ghsa","ecosystem":"Packagist","package":"contao/core-bundle","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"5.4.0"},{"fixed":"5.7.9"}]}]},{"source":"osv","ecosystem":"Packagist","package":"contao/contao","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"5.3.35"},{"fixed":"5.3.48"}]}],"versions":["5.3.35","5.3.36","5.3.37","5.3.38","5.3.39","5.3.40","5.3.41","5.3.42","5.3.43","5.3.44","5.3.45","5.3.46","5.3.47"]},{"source":"osv","ecosystem":"Packagist","package":"contao/contao","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"5.4.0"},{"fixed":"5.7.9"}]}],"versions":["5.4.0","5.4.1","5.4.10","5.4.11","5.4.12","5.4.13","5.4.14","5.4.2","5.4.3","5.4.4","5.4.5","5.4.6","5.4.7","5.4.8","5.4.9","5.5.0","5.5.0-RC1","5.5.0-RC2","5.5.0-RC3","5.5.0-RC4","5.5.1","5.5.10","5.5.11","5.5.12","5.5.13","5.5.14","5.5.15","5.5.16","5.5.2","5.5.3","5.5.4","5.5.5","5.5.6","5.5.7","5.5.8","5.5.9","5.6.0","5.6.0-RC1","5.6.0-RC2","5.6.0-RC3","5.6.1","5.6.10","5.6.11","5.6.2","5.6.3","5.6.4","5.6.5","5.6.6","5.6.7","5.6.8","5.6.9","5.7.0","5.7.0-RC1","5.7.0-RC2","5.7.0-RC3","5.7.0-RC4","5.7.1","5.7.2","5.7.3","5.7.4","5.7.5","5.7.6","5.7.7","5.7.8"]},{"source":"osv","ecosystem":"Packagist","package":"contao/core-bundle","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"5.3.35"},{"fixed":"5.3.48"}]}],"versions":["5.3.35","5.3.36","5.3.37","5.3.38","5.3.39","5.3.40","5.3.41","5.3.42","5.3.43","5.3.44","5.3.45","5.3.46","5.3.47"]},{"source":"osv","ecosystem":"Packagist","package":"contao/core-bundle","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"5.4.0"},{"fixed":"5.7.9"}]}],"versions":["5.4.0","5.4.1","5.4.10","5.4.11","5.4.12","5.4.13","5.4.14","5.4.2","5.4.3","5.4.4","5.4.5","5.4.6","5.4.7","5.4.8","5.4.9","5.5.0","5.5.0-RC1","5.5.0-RC2","5.5.0-RC3","5.5.0-RC4","5.5.1","5.5.10","5.5.11","5.5.12","5.5.13","5.5.14","5.5.15","5.5.16","5.5.2","5.5.3","5.5.4","5.5.5","5.5.6","5.5.7","5.5.8","5.5.9","5.6.0","5.6.0-RC1","5.6.0-RC2","5.6.0-RC3","5.6.1","5.6.10","5.6.11","5.6.2","5.6.3","5.6.4","5.6.5","5.6.6","5.6.7","5.6.8","5.6.9","5.7.0","5.7.0-RC1","5.7.0-RC2","5.7.0-RC3","5.7.0-RC4","5.7.1","5.7.2","5.7.3","5.7.4","5.7.5","5.7.6","5.7.7","5.7.8"]}],"products":[{"vendor":"contao","product":"contao"}],"references":[{"url":"https://github.com/contao/contao/security/advisories/GHSA-87mg-5grr-rhwh","tags":["x_refsource_CONFIRM","advisory","web"]},{"url":"https://github.com/contao/contao/commit/27f6201809553bee767dcef15535bb8f0f4eac5f","tags":["x_refsource_MISC","fix","web"]},{"url":"https://github.com/contao/contao/commit/53b939ff2c4718e3a1d7c54ddd8886e9370618e4","tags":["x_refsource_MISC","fix","web"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-57232","tags":["advisory"]},{"url":"https://contao.org/en/security-advisories/server-side-request-forgery-via-unvalidated-rss-feed-urls","tags":["web"]},{"url":"https://github.com/FriendsOfPHP/security-advisories/blob/master/contao/contao/CVE-2026-57232.yaml","tags":["web"]},{"url":"https://github.com/FriendsOfPHP/security-advisories/blob/master/contao/core-bundle/CVE-2026-57232.yaml","tags":["web"]},{"url":"https://github.com/contao/contao/releases/tag/5.3.48","tags":["web"]},{"url":"https://github.com/contao/contao/releases/tag/5.7.9","tags":["web"]},{"url":"https://github.com/advisories/GHSA-87mg-5grr-rhwh"},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/57xxx/CVE-2026-57232.json","tags":["advisory"]},{"url":"https://github.com/contao/contao","tags":["package"]}],"sources":{"cve":[{"id":"CVE-2026-57232","title":"Contao: Server-Side Request Forgery (SSRF) via Unvalidated RSS Feed URL in Feed Reader Module","description":"Contao is an Open Source CMS. From 5.3.35 through 5.3.47 and from 5.7.0-RC1 through 5.7.8, the Feed Reader front-end module passes configured RSS feed URLs from FeedReaderController::getResponse() to feedIo-\u003eread() without scheme or private-address validation, allowing a backend user with module-edit permissions to make the server request internal network services, loopback addresses, or cloud metadata endpoints. In core-bundle/src/Controller/FrontendModule/FeedReaderController.php, the getResponse() function iterates over the configured feed URLs and passes each one directly to the HTTP client (via $this-\u003efeedIo-\u003eread($url, new Feed())) with no validation, while the DCA field definition for rss_feed in tl_module.php carries no URL scheme or host validation and the HTTP client is wired as @psr18.http_client (Symfony HttpClient) with no SSRF protection configured, since NoPrivateNetworkHttpClient is not used. This issue is fixed in versions 5.3.48.","status":"published","published":"2026-07-31T18:29:53.924Z","modified":"2026-08-03T17:24:45.798Z","cvss":[{"version":"3.1","score":3.1,"vector":"CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:L/I:N/A:N","level":"low","assessor":"cna"}],"cwes":["CWE-918"],"updated_at":"2026-11-02T13:43:44.898272Z"}],"euvd":[{"id":"EUVD-2026-51596","description":"Contao is an Open Source CMS. From 5.3.35 through 5.3.47 and from 5.7.0-RC1 through 5.7.8, the Feed Reader front-end module passes configured RSS feed URLs from FeedReaderController::getResponse() to feedIo-\u003eread() without scheme or private-address validation, allowing a backend user with module-edit permissions to make the server request internal network services, loopback addresses, or cloud metadata endpoints. In core-bundle/src/Controller/FrontendModule/FeedReaderController.php, the getResponse() function iterates over the configured feed URLs and passes each one directly to the HTTP client (via $this-\u003efeedIo-\u003eread($url, new Feed())) with no validation, while the DCA field definition for rss_feed in tl_module.php carries no URL scheme or host validation and the HTTP client is wired as @psr18.http_client (Symfony HttpClient) with no SSRF protection configured, since NoPrivateNetworkHttpClient is not used. This issue is fixed in versions 5.3.48.","status":"published","published":"2026-07-31T18:29:53Z","modified":"2026-08-03T17:24:45Z","cvss":[{"version":"3.1","score":3.1,"vector":"CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:L/I:N/A:N","level":"low"}],"updated_at":"2026-11-02T18:02:24.01774Z"}],"ghsa":[{"id":"GHSA-87mg-5grr-rhwh","title":"Contao: Server-Side Request Forgery (SSRF) via Unvalidated RSS Feed URL in Feed Reader Module","description":"### Summary\n\nThe Feed Reader front-end module passes RSS feed URLs from its configuration directly to `$this-\u003efeedIo-\u003eread($url)` without any scheme validation or private-IP blocklist. A backend user with module-edit permissions can configure an arbitrary URL pointing to internal network services, cloud-provider metadata endpoints, or loopback addresses, causing the server to fetch those resources unconditionally. Confirmed live: the server successfully reaches the internal MySQL database container and its own loopback Apache instance.\n\n---\n\n### Details\n\nIn `core-bundle/src/Controller/FrontendModule/FeedReaderController.php`, the `getResponse()` function iterates over the configured feed URLs and passes each one directly to the HTTP client with no validation:\n\n```php\n// Line 50-55\nforeach (StringUtil::trimsplit('[\\n\\t ]', trim($model-\u003erss_feed)) as $url) {\n    try {\n        $feed = $this-\u003ecache-\u003eget(\n            'feed_reader_'.$model-\u003eid.'_'.md5($url),\n            function (ItemInterface $item) use ($url, $model) {\n                $readerResult = $this-\u003efeedIo-\u003eread($url, new Feed()); // \u003c-- no validation\n```\n\nThe DCA field definition for `rss_feed` in `tl_module.php` carries no URL scheme or host validation:\n```php\n'eval' =\u003e array('mandatory'=\u003etrue, 'decodeEntities'=\u003etrue, 'style'=\u003e'height:60px')\n```\n\nThe HTTP client is wired as `@psr18.http_client` (Symfony HttpClient) with no SSRF protection configured (`NoPrivateNetworkHttpClient` is not used).\n\n---\n\n### Impact\n\nThis is a CWE-918 (SSRF) vulnerability. A backend user with module-edit access can:\n\n1. **Enumerate internal network services** -- probe any IP/port on the internal network by observing response times and error messages\n2. **Reach internal APIs** -- access unauthenticated services inside the Docker/Kubernetes network (databases, caches, admin panels)\n3. **Steal cloud metadata credentials** -- on AWS, fetch `http://169.254.169.254/latest/meta-data/iam/security-credentials/` to obtain IAM role credentials (IMDSv1 has no authentication)\n4. **Pivot to internal infrastructure** -- use the server as a proxy to interact with services not exposed to the public internet\n\nConfirmed in live testing: the server successfully connected to the internal MySQL container (`172.19.0.3:3306`) and retrieved a full HTTP response from its own loopback interface (`127.0.0.1:80`).\n\n---\n\n### Remediation\n\n1. **Use `NoPrivateNetworkHttpClient`** -- wrap the injected HTTP client with Symfony's built-in SSRF protection before passing it to feedIo:\n   ```php\n   use Symfony\\Component\\HttpClient\\NoPrivateNetworkHttpClient;\n\n   $safeClient = new NoPrivateNetworkHttpClient($this-\u003ehttpClient);\n   ```\n   This blocks all RFC-1918, loopback, and link-local addresses at the HTTP client level.\n\n2. **Validate URL scheme and host** -- before calling `feedIo-\u003eread()`, parse the URL and reject anything that is not `http://` or `https://` with a public routable IP or hostname.\n\n3. **Configure the DCA field** -- add `'rgxp' =\u003e 'url'` and a custom validation callback to `tl_module.rss_feed` to reject non-public URLs at save time.","status":"published","published":"2026-09-24T19:59:16Z","modified":"2026-09-24T20:00:10Z","cvss":[{"version":"3.1","score":3.1,"vector":"CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:L/I:N/A:N","level":"low"}],"cwes":["CWE-918"],"updated_at":"2026-11-02T14:41:21.616682Z"}],"nvd":[{"id":"CVE-2026-57232","description":"Contao is an Open Source CMS. From 5.3.35 through 5.3.47 and from 5.7.0-RC1 through 5.7.8, the Feed Reader front-end module passes configured RSS feed URLs from FeedReaderController::getResponse() to feedIo-\u003eread() without scheme or private-address validation, allowing a backend user with module-edit permissions to make the server request internal network services, loopback addresses, or cloud metadata endpoints. In core-bundle/src/Controller/FrontendModule/FeedReaderController.php, the getResponse() function iterates over the configured feed URLs and passes each one directly to the HTTP client (via $this-\u003efeedIo-\u003eread($url, new Feed())) with no validation, while the DCA field definition for rss_feed in tl_module.php carries no URL scheme or host validation and the HTTP client is wired as @psr18.http_client (Symfony HttpClient) with no SSRF protection configured, since NoPrivateNetworkHttpClient is not used. This issue is fixed in versions 5.3.48.","status":"published","published":"2026-07-31T19:17:11.423Z","modified":"2026-09-08T20:51:43.49Z","cvss":[{"version":"3.1","score":3.1,"vector":"CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:L/I:N/A:N","level":"low","assessor":"secondary"}],"cwes":["CWE-918"],"updated_at":"2026-11-02T14:12:34.290716Z"}],"osv":[{"id":"CVE-2026-57232","title":"Contao: Server-Side Request Forgery (SSRF) via Unvalidated RSS Feed URL in Feed Reader Module","description":"Contao is an Open Source CMS. From 5.3.35 through 5.3.47 and from 5.7.0-RC1 through 5.7.8, the Feed Reader front-end module passes configured RSS feed URLs from FeedReaderController::getResponse() to feedIo-\u003eread() without scheme or private-address validation, allowing a backend user with module-edit permissions to make the server request internal network services, loopback addresses, or cloud metadata endpoints. In core-bundle/src/Controller/FrontendModule/FeedReaderController.php, the getResponse() function iterates over the configured feed URLs and passes each one directly to the HTTP client (via $this-\u003efeedIo-\u003eread($url, new Feed())) with no validation, while the DCA field definition for rss_feed in tl_module.php carries no URL scheme or host validation and the HTTP client is wired as @psr18.http_client (Symfony HttpClient) with no SSRF protection configured, since NoPrivateNetworkHttpClient is not used. This issue is fixed in versions 5.3.48.","status":"published","published":"2026-07-31T18:29:53.924Z","modified":"2026-10-28T02:30:49.061968898Z","cvss":[{"version":"3.1","score":3.1,"vector":"CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:L/I:N/A:N","level":"low"}],"cwes":["CWE-918"],"updated_at":"2026-11-02T15:45:12.016252Z"},{"id":"GHSA-87mg-5grr-rhwh","title":"Contao: Server-Side Request Forgery (SSRF) via Unvalidated RSS Feed URL in Feed Reader Module","description":"### Summary\n\nThe Feed Reader front-end module passes RSS feed URLs from its configuration directly to `$this-\u003efeedIo-\u003eread($url)` without any scheme validation or private-IP blocklist. A backend user with module-edit permissions can configure an arbitrary URL pointing to internal network services, cloud-provider metadata endpoints, or loopback addresses, causing the server to fetch those resources unconditionally. Confirmed live: the server successfully reaches the internal MySQL database container and its own loopback Apache instance.\n\n---\n\n### Details\n\nIn `core-bundle/src/Controller/FrontendModule/FeedReaderController.php`, the `getResponse()` function iterates over the configured feed URLs and passes each one directly to the HTTP client with no validation:\n\n```php\n// Line 50-55\nforeach (StringUtil::trimsplit('[\\n\\t ]', trim($model-\u003erss_feed)) as $url) {\n    try {\n        $feed = $this-\u003ecache-\u003eget(\n            'feed_reader_'.$model-\u003eid.'_'.md5($url),\n            function (ItemInterface $item) use ($url, $model) {\n                $readerResult = $this-\u003efeedIo-\u003eread($url, new Feed()); // \u003c-- no validation\n```\n\nThe DCA field definition for `rss_feed` in `tl_module.php` carries no URL scheme or host validation:\n```php\n'eval' =\u003e array('mandatory'=\u003etrue, 'decodeEntities'=\u003etrue, 'style'=\u003e'height:60px')\n```\n\nThe HTTP client is wired as `@psr18.http_client` (Symfony HttpClient) with no SSRF protection configured (`NoPrivateNetworkHttpClient` is not used).\n\n---\n\n### Impact\n\nThis is a CWE-918 (SSRF) vulnerability. A backend user with module-edit access can:\n\n1. **Enumerate internal network services** -- probe any IP/port on the internal network by observing response times and error messages\n2. **Reach internal APIs** -- access unauthenticated services inside the Docker/Kubernetes network (databases, caches, admin panels)\n3. **Steal cloud metadata credentials** -- on AWS, fetch `http://169.254.169.254/latest/meta-data/iam/security-credentials/` to obtain IAM role credentials (IMDSv1 has no authentication)\n4. **Pivot to internal infrastructure** -- use the server as a proxy to interact with services not exposed to the public internet\n\nConfirmed in live testing: the server successfully connected to the internal MySQL container (`172.19.0.3:3306`) and retrieved a full HTTP response from its own loopback interface (`127.0.0.1:80`).\n\n---\n\n### Remediation\n\n1. **Use `NoPrivateNetworkHttpClient`** -- wrap the injected HTTP client with Symfony's built-in SSRF protection before passing it to feedIo:\n   ```php\n   use Symfony\\Component\\HttpClient\\NoPrivateNetworkHttpClient;\n\n   $safeClient = new NoPrivateNetworkHttpClient($this-\u003ehttpClient);\n   ```\n   This blocks all RFC-1918, loopback, and link-local addresses at the HTTP client level.\n\n2. **Validate URL scheme and host** -- before calling `feedIo-\u003eread()`, parse the URL and reject anything that is not `http://` or `https://` with a public routable IP or hostname.\n\n3. **Configure the DCA field** -- add `'rgxp' =\u003e 'url'` and a custom validation callback to `tl_module.rss_feed` to reject non-public URLs at save time.","status":"published","published":"2026-09-24T19:59:16Z","modified":"2026-09-24T20:15:04.877718431Z","cvss":[{"version":"3.1","score":3.1,"vector":"CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:L/I:N/A:N","level":"low"}],"cwes":["CWE-918"],"updated_at":"2026-11-02T15:46:42.077781Z"}]}}
