Skip to content

Commit 9d9b46a

Browse files
committed
Merge branch '4.x' of https://github.com/craftcms/cms into 5.x
# Conflicts: # CHANGELOG.md
2 parents e002aa3 + e838a22 commit 9d9b46a

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
@@ -15,6 +15,7 @@
1515
- Fixed a JavaScript error that could occur if two control panel animations were triggered simultaneously.
1616
- Fixed a bug where it wasn’t possible to copy/paste nested entries within Matrix fields set to the inline-editable blocks view mode, for unpublished owner elements. ([#18185](https://github.com/craftcms/cms/pull/18185))
1717
- Fixed a bug where custom fields’ checkboxes weren’t getting removed from field layouts’ “Card Attributes” lists when removed from the layout.
18+
- Fixed an SSRF vulnerability. (GHSA-96pq-hxpw-rgh8)
1819

1920
## 5.8.21 - 2025-12-04
2021

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

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

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

0 commit comments

Comments
 (0)