Skip to content

Commit e838a22

Browse files
authored
Merge commit from fork
Fixed GHSA-96pq-hxpw-rgh8
2 parents 0b8e225 + 76ad184 commit e838a22

File tree

2 files changed

+42
-6
lines changed

2 files changed

+42
-6
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
- The `utils/fix-field-layout-uids` command now checks for duplicate top-level field layout UUIDs. ([#18193](https://github.com/craftcms/cms/pull/18193))
66
- Fixed a bug where all plugin settings were being saved to the project config, rather than just posted settings. ([craftcms/commerce#4006](https://github.com/craftcms/commerce/issues/4006))
77
- Fixed a bug where custom selects could be positioned incorrectly after the window was resized. ([#18179](https://github.com/craftcms/cms/issues/18179))
8+
- Fixed an SSRF vulnerability. (GHSA-96pq-hxpw-rgh8)
89

910
## 4.16.17 - 2025-12-0421
1011

src/gql/resolvers/mutations/Asset.php

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -242,12 +242,7 @@ protected function handleUpload(AssetElement $asset, array $fileInformation): bo
242242
} elseif (!empty($fileInformation['url'])) {
243243
$url = $fileInformation['url'];
244244

245-
// make sure the hostname is alphanumeric and not an IP address
246-
$hostname = parse_url($url, PHP_URL_HOST);
247-
if (
248-
!filter_var($hostname, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME) ||
249-
filter_var($hostname, FILTER_VALIDATE_IP)
250-
) {
245+
if (!$this->validateHostname($url)) {
251246
throw new UserError("$url contains an invalid hostname.");
252247
}
253248

@@ -283,6 +278,46 @@ protected function handleUpload(AssetElement $asset, array $fileInformation): bo
283278
return true;
284279
}
285280

281+
private function validateHostname(string $url): bool
282+
{
283+
// make sure the hostname is alphanumeric and not an IP address
284+
$hostname = parse_url($url, PHP_URL_HOST);
285+
if (
286+
!filter_var($hostname, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME) ||
287+
filter_var($hostname, FILTER_VALIDATE_IP)
288+
) {
289+
return false;
290+
}
291+
292+
// Check against well-known cloud metadata domains/IPs
293+
// h/t https://gist.github.com/BuffaloWill/fa96693af67e3a3dd3fb
294+
if (in_array($hostname, [
295+
'kubernetes.default',
296+
'kubernetes.default.svc',
297+
'kubernetes.default.svc.cluster.local',
298+
'metadata',
299+
'metadata.google.internal',
300+
'metadata.packet.net',
301+
])) {
302+
return false;
303+
}
304+
305+
// make sure the hostname doesn’t resolve to a known cloud metadata IP
306+
$ip = gethostbyname($hostname);
307+
308+
if (in_array($ip, [
309+
'169.254.169.254',
310+
'169.254.170.2',
311+
'169.254.169.254',
312+
'100.100.100.200',
313+
'192.0.0.192',
314+
])) {
315+
return false;
316+
}
317+
318+
return true;
319+
}
320+
286321
/**
287322
* Create the guzzle client.
288323
*

0 commit comments

Comments
 (0)