{"id":"CVE-2026-48013","aliases":["EUVD-2026-48378","GHSA-gq96-5pfx-f4vc"],"status":"published","title":"Shopware: SSRF in Media External-Link Endpoint Bypasses IP Validation","description":"Shopware is an open commerce platform. Prior to 6.6.10.18 and 6.7.10.1, the `/api/_action/media/external-link` endpoint allows authenticated admin users to make server-side HTTP HEAD requests to arbitrary internal IP addresses. While the parallel `uploadFromURL` flow validates target IPs against private/reserved ranges via `FileUrlValidator`, the `linkURL` flow only performs a URL format check (regex for `http://` or `https://` prefix), allowing SSRF to internal network services and cloud metadata endpoints. This issue is fixed in versions 6.6.10.18 and 6.7.10.1.","severity":{"version":"3.1","score":4.1,"vector":"CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:L/I:N/A:N","level":"medium","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-11","score":0.00366,"percentile":0.30873,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":true},"cwes":["CWE-918"],"published":"2026-06-04T19:36:07Z","modified":"2026-11-04T02:48:05Z","fixes":[{"ecosystem":"Packagist","package":"shopware/core","fixed_in":["6.7.10.1"],"sources":["ghsa","osv"]},{"ecosystem":"Packagist","package":"shopware/platform","fixed_in":["6.7.10.1"],"sources":["ghsa","osv"]}],"affected":[{"source":"ghsa","ecosystem":"Packagist","package":"shopware/core","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"6.7.0.0"},{"fixed":"6.7.10.1"}]}]},{"source":"ghsa","ecosystem":"Packagist","package":"shopware/platform","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"6.7.0.0"},{"fixed":"6.7.10.1"}]}]},{"source":"osv","ecosystem":"Packagist","package":"shopware/core","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"6.7.0.0"},{"fixed":"6.7.10.1"}]}],"versions":["v6.7.0.0","v6.7.0.1","v6.7.1.0","v6.7.1.1","v6.7.1.2","v6.7.10.0","v6.7.2.0","v6.7.2.1","v6.7.2.2","v6.7.3.0","v6.7.3.1","v6.7.4.0","v6.7.4.1","v6.7.4.2","v6.7.5.0","v6.7.5.1","v6.7.6.0","v6.7.6.1","v6.7.6.2","v6.7.7.0","v6.7.7.1","v6.7.8.0","v6.7.8.1","v6.7.8.2","v6.7.9.0","v6.7.9.1"]},{"source":"osv","ecosystem":"Packagist","package":"shopware/platform","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"6.7.0.0"},{"fixed":"6.7.10.1"}]}],"versions":["v6.7.0.0","v6.7.0.1","v6.7.1.0","v6.7.1.1","v6.7.1.2","v6.7.10.0","v6.7.2.0","v6.7.2.1","v6.7.2.2","v6.7.3.0","v6.7.3.1","v6.7.4.0","v6.7.4.1","v6.7.4.2","v6.7.5.0","v6.7.5.1","v6.7.6.0","v6.7.6.1","v6.7.6.2","v6.7.7.0","v6.7.7.1","v6.7.8.0","v6.7.8.1","v6.7.8.2","v6.7.9.0","v6.7.9.1"]}],"products":[{"vendor":"runzero","product":"platform"},{"vendor":"shopware","product":"platform"},{"vendor":"shopware","product":"shopware"}],"references":[{"url":"https://github.com/shopware/shopware/security/advisories/GHSA-gq96-5pfx-f4vc","tags":["x_refsource_CONFIRM","advisory","web"]},{"url":"https://github.com/shopware/shopware/releases/tag/v6.6.10.18","tags":["x_refsource_MISC","web"]},{"url":"https://github.com/shopware/shopware/releases/tag/v6.7.10.1","tags":["x_refsource_MISC","web"]},{"url":"https://github.com/advisories/GHSA-gq96-5pfx-f4vc"},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/48xxx/CVE-2026-48013.json","tags":["advisory"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-48013","tags":["advisory"]},{"url":"https://github.com/shopware/shopware","tags":["package"]}],"sources":{"cve":[{"id":"CVE-2026-48013","title":"Shopware: SSRF in Media External-Link Endpoint Bypasses IP Validation","description":"Shopware is an open commerce platform. Prior to 6.6.10.18 and 6.7.10.1, the `/api/_action/media/external-link` endpoint allows authenticated admin users to make server-side HTTP HEAD requests to arbitrary internal IP addresses. While the parallel `uploadFromURL` flow validates target IPs against private/reserved ranges via `FileUrlValidator`, the `linkURL` flow only performs a URL format check (regex for `http://` or `https://` prefix), allowing SSRF to internal network services and cloud metadata endpoints. This issue is fixed in versions 6.6.10.18 and 6.7.10.1.","status":"published","published":"2026-07-23T19:14:32.579Z","modified":"2026-07-23T19:27:54.53Z","cvss":[{"version":"3.1","score":4.1,"vector":"CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:L/I:N/A:N","level":"medium","assessor":"cna"}],"cwes":["CWE-918","CWE-918"],"updated_at":"2026-11-02T13:50:49.872037Z"}],"euvd":[{"id":"EUVD-2026-48378","description":"Shopware is an open commerce platform. Prior to 6.6.10.18 and 6.7.10.1, the `/api/_action/media/external-link` endpoint allows authenticated admin users to make server-side HTTP HEAD requests to arbitrary internal IP addresses. While the parallel `uploadFromURL` flow validates target IPs against private/reserved ranges via `FileUrlValidator`, the `linkURL` flow only performs a URL format check (regex for `http://` or `https://` prefix), allowing SSRF to internal network services and cloud metadata endpoints. This issue is fixed in versions 6.6.10.18 and 6.7.10.1.","status":"published","published":"2026-07-23T19:14:32Z","modified":"2026-07-23T19:27:54Z","cvss":[{"version":"3.1","score":4.1,"vector":"CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:L/I:N/A:N","level":"medium"}],"updated_at":"2026-11-02T18:19:41.632414Z"}],"ghsa":[{"id":"GHSA-gq96-5pfx-f4vc","title":"Shopware: SSRF in Media External-Link Endpoint Bypasses IP Validation","description":"## Summary\n\nThe `/api/_action/media/external-link` endpoint allows authenticated admin users to make server-side HTTP HEAD requests to arbitrary internal IP addresses. While the parallel `uploadFromURL` flow validates target IPs against private/reserved ranges via `FileUrlValidator`, the `linkURL` flow only performs a URL format check (regex for `http://` or `https://` prefix), allowing SSRF to internal network services and cloud metadata endpoints.\n\n## Details\n\nThe vulnerability is an inconsistency between two URL-handling flows in `MediaUploadService`.\n\n**Vulnerable path** (`external-link`):\n\n`MediaUploadV2Controller::externalLink()` at `src/Core/Content/Media/Api/MediaUploadV2Controller.php:66` takes a user-supplied `url` parameter and passes it to `MediaUploadService::linkURL()` at `src/Core/Content/Media/Upload/MediaUploadService.php:134`.\n\n`linkURL()` calls `getContentSizeFromValidExternalUrl($url)` at line 159, which only validates via `validateExternalUrl()`:\n\n```php\n// src/Core/Content/Media/Upload/MediaUploadService.php:207-212\npublic static function validateExternalUrl(string $url): void\n{\n    if (!preg_match('/^https?:\\/\\/.+/', $url)) {\n        throw MediaException::invalidUrl($url);\n    }\n}\n```\n\nThen makes a server-side HEAD request with no IP filtering:\n\n```php\n// src/Core/Content/Media/Upload/MediaUploadService.php:292-300\nprivate function getContentSizeFromValidExternalUrl(string $url): int\n{\n    $this-\u003evalidateExternalUrl($url);\n\n    $headers = $this-\u003ehttpClient-\u003erequest('HEAD', $url)-\u003egetHeaders();\n    if (!\\array_key_exists('content-length', $headers)) {\n        throw MediaException::fileNotFound($url);\n    }\n\n    return (int) $headers['content-length'][0];\n}\n```\n\n**Protected path** (`upload_by_url`):\n\nIn contrast, `uploadFromURL` uses `FileFetcher::fetchFromURL()` which calls `FileUrlValidator::isValid()`:\n\n```php\n// src/Core/Content/Media/File/FileFetcher.php:64\nif ($this-\u003eenableUrlValidation \u0026\u0026 !$this-\u003efileUrlValidator-\u003eisValid($url)) {\n    throw MediaException::illegalUrl($url);\n}\n```\n\n`FileUrlValidator::isValid()` resolves the hostname via `gethostbyname()` and validates the IP against private and reserved ranges using `filter_var()` with `FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE`. This protection is entirely absent from the `linkURL` flow.\n\n## Impact\n\nAn authenticated admin user can:\n\n1. **Probe cloud metadata services** — HEAD requests to `169.254.169.254` reveal whether cloud metadata endpoints exist and leak content-length values\n2. **Scan internal networks** — Differentiate open/closed/filtered ports on internal hosts (10.x, 172.16.x, 192.168.x) based on response timing and error types\n3. **Leak internal service information** — The `fileSize` field stored in the database reflects the `content-length` header from internal services\n4. **Redirect-based escalation** — Symfony HttpClient follows redirects by default (max_redirects=20), allowing an attacker-controlled external server to redirect the HEAD request to arbitrary internal destinations\n\nImpact is limited to information disclosure via HEAD requests. The admin authentication requirement (PR:H) reduces exploitability, but in multi-tenant or compromised-credential scenarios this allows network reconnaissance from the server's perspective.\n\n## Recommended Fix\n\nApply `FileUrlValidator` to the `linkURL` flow, consistent with the `uploadFromURL` flow. In `MediaUploadService`:\n\n```php\n// src/Core/Content/Media/Upload/MediaUploadService.php\n\n// Add constructor dependency:\nprivate readonly FileUrlValidatorInterface $fileUrlValidator;\n\n// In getContentSizeFromValidExternalUrl(), add IP validation:\nprivate function getContentSizeFromValidExternalUrl(string $url): int\n{\n    $this-\u003evalidateExternalUrl($url);\n\n    if (!$this-\u003efileUrlValidator-\u003eisValid($url)) {\n        throw MediaException::illegalUrl($url);\n    }\n\n    $headers = $this-\u003ehttpClient-\u003erequest('HEAD', $url)-\u003egetHeaders();\n    if (!\\array_key_exists('content-length', $headers)) {\n        throw MediaException::fileNotFound($url);\n    }\n\n    return (int) $headers['content-length'][0];\n}\n```\n\nAdditionally, consider setting `max_redirects: 0` on the HttpClient request to prevent redirect-based SSRF bypasses.","status":"published","published":"2026-06-04T19:36:07Z","modified":"2026-06-04T19:36:08Z","cvss":[{"version":"3.1","score":4.1,"vector":"CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:L/I:N/A:N","level":"medium"}],"cwes":["CWE-918"],"updated_at":"2026-11-02T14:40:16.698699Z"}],"nvd":[{"id":"CVE-2026-48013","description":"Shopware is an open commerce platform. Prior to 6.6.10.18 and 6.7.10.1, the `/api/_action/media/external-link` endpoint allows authenticated admin users to make server-side HTTP HEAD requests to arbitrary internal IP addresses. While the parallel `uploadFromURL` flow validates target IPs against private/reserved ranges via `FileUrlValidator`, the `linkURL` flow only performs a URL format check (regex for `http://` or `https://` prefix), allowing SSRF to internal network services and cloud metadata endpoints. This issue is fixed in versions 6.6.10.18 and 6.7.10.1.","status":"published","published":"2026-07-23T20:17:08.92Z","modified":"2026-07-27T20:32:11.62Z","cvss":[{"version":"3.1","score":4.1,"vector":"CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:L/I:N/A:N","level":"medium","assessor":"secondary"}],"cwes":["CWE-918"],"updated_at":"2026-11-02T14:12:32.473901Z"}],"osv":[{"id":"CVE-2026-48013","title":"Shopware: SSRF in Media External-Link Endpoint Bypasses IP Validation","description":"Shopware is an open commerce platform. Prior to 6.6.10.18 and 6.7.10.1, the `/api/_action/media/external-link` endpoint allows authenticated admin users to make server-side HTTP HEAD requests to arbitrary internal IP addresses. While the parallel `uploadFromURL` flow validates target IPs against private/reserved ranges via `FileUrlValidator`, the `linkURL` flow only performs a URL format check (regex for `http://` or `https://` prefix), allowing SSRF to internal network services and cloud metadata endpoints. This issue is fixed in versions 6.6.10.18 and 6.7.10.1.","status":"published","published":"2026-07-23T19:14:32.579Z","modified":"2026-11-05T10:45:59.116598999Z","cvss":[{"version":"3.1","score":4.1,"vector":"CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:L/I:N/A:N","level":"medium"}],"cwes":["CWE-918"],"updated_at":"2026-11-05T13:30:49.23793Z"},{"id":"GHSA-gq96-5pfx-f4vc","title":"Shopware: SSRF in Media External-Link Endpoint Bypasses IP Validation","description":"## Summary\n\nThe `/api/_action/media/external-link` endpoint allows authenticated admin users to make server-side HTTP HEAD requests to arbitrary internal IP addresses. While the parallel `uploadFromURL` flow validates target IPs against private/reserved ranges via `FileUrlValidator`, the `linkURL` flow only performs a URL format check (regex for `http://` or `https://` prefix), allowing SSRF to internal network services and cloud metadata endpoints.\n\n## Details\n\nThe vulnerability is an inconsistency between two URL-handling flows in `MediaUploadService`.\n\n**Vulnerable path** (`external-link`):\n\n`MediaUploadV2Controller::externalLink()` at `src/Core/Content/Media/Api/MediaUploadV2Controller.php:66` takes a user-supplied `url` parameter and passes it to `MediaUploadService::linkURL()` at `src/Core/Content/Media/Upload/MediaUploadService.php:134`.\n\n`linkURL()` calls `getContentSizeFromValidExternalUrl($url)` at line 159, which only validates via `validateExternalUrl()`:\n\n```php\n// src/Core/Content/Media/Upload/MediaUploadService.php:207-212\npublic static function validateExternalUrl(string $url): void\n{\n    if (!preg_match('/^https?:\\/\\/.+/', $url)) {\n        throw MediaException::invalidUrl($url);\n    }\n}\n```\n\nThen makes a server-side HEAD request with no IP filtering:\n\n```php\n// src/Core/Content/Media/Upload/MediaUploadService.php:292-300\nprivate function getContentSizeFromValidExternalUrl(string $url): int\n{\n    $this-\u003evalidateExternalUrl($url);\n\n    $headers = $this-\u003ehttpClient-\u003erequest('HEAD', $url)-\u003egetHeaders();\n    if (!\\array_key_exists('content-length', $headers)) {\n        throw MediaException::fileNotFound($url);\n    }\n\n    return (int) $headers['content-length'][0];\n}\n```\n\n**Protected path** (`upload_by_url`):\n\nIn contrast, `uploadFromURL` uses `FileFetcher::fetchFromURL()` which calls `FileUrlValidator::isValid()`:\n\n```php\n// src/Core/Content/Media/File/FileFetcher.php:64\nif ($this-\u003eenableUrlValidation \u0026\u0026 !$this-\u003efileUrlValidator-\u003eisValid($url)) {\n    throw MediaException::illegalUrl($url);\n}\n```\n\n`FileUrlValidator::isValid()` resolves the hostname via `gethostbyname()` and validates the IP against private and reserved ranges using `filter_var()` with `FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE`. This protection is entirely absent from the `linkURL` flow.\n\n## Impact\n\nAn authenticated admin user can:\n\n1. **Probe cloud metadata services** — HEAD requests to `169.254.169.254` reveal whether cloud metadata endpoints exist and leak content-length values\n2. **Scan internal networks** — Differentiate open/closed/filtered ports on internal hosts (10.x, 172.16.x, 192.168.x) based on response timing and error types\n3. **Leak internal service information** — The `fileSize` field stored in the database reflects the `content-length` header from internal services\n4. **Redirect-based escalation** — Symfony HttpClient follows redirects by default (max_redirects=20), allowing an attacker-controlled external server to redirect the HEAD request to arbitrary internal destinations\n\nImpact is limited to information disclosure via HEAD requests. The admin authentication requirement (PR:H) reduces exploitability, but in multi-tenant or compromised-credential scenarios this allows network reconnaissance from the server's perspective.\n\n## Recommended Fix\n\nApply `FileUrlValidator` to the `linkURL` flow, consistent with the `uploadFromURL` flow. In `MediaUploadService`:\n\n```php\n// src/Core/Content/Media/Upload/MediaUploadService.php\n\n// Add constructor dependency:\nprivate readonly FileUrlValidatorInterface $fileUrlValidator;\n\n// In getContentSizeFromValidExternalUrl(), add IP validation:\nprivate function getContentSizeFromValidExternalUrl(string $url): int\n{\n    $this-\u003evalidateExternalUrl($url);\n\n    if (!$this-\u003efileUrlValidator-\u003eisValid($url)) {\n        throw MediaException::illegalUrl($url);\n    }\n\n    $headers = $this-\u003ehttpClient-\u003erequest('HEAD', $url)-\u003egetHeaders();\n    if (!\\array_key_exists('content-length', $headers)) {\n        throw MediaException::fileNotFound($url);\n    }\n\n    return (int) $headers['content-length'][0];\n}\n```\n\nAdditionally, consider setting `max_redirects: 0` on the HttpClient request to prevent redirect-based SSRF bypasses.","status":"published","published":"2026-06-04T19:36:07Z","modified":"2026-09-10T03:51:08.861204121Z","cvss":[{"version":"3.1","score":4.1,"vector":"CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:L/I:N/A:N","level":"medium"}],"cwes":["CWE-918"],"updated_at":"2026-11-02T15:46:48.191583Z"}]}}
