fix(security): enforce scheme allow-list on runbackup return URL
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Universal: PR Check / Require Docs Update (pull_request) Has been skipped
Universal: PR Check / Wiki Update Reminder (pull_request) Has been skipped
Universal: PR Check / Secret Scan (pull_request) Successful in 9s
Generic: Project CI / Lint & Validate (pull_request) Successful in 14s
RC Revert / Rename rc/ back to dev/ (pull_request) Has been skipped
Branch Cleanup / Delete merged branch (pull_request) Successful in 2s
Universal: PR Check / Validate PR (pull_request) Failing after 14s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 1m8s
Generic: Project CI / Tests (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Universal: PR Check / Require Docs Update (pull_request) Has been skipped
Universal: PR Check / Wiki Update Reminder (pull_request) Has been skipped
Universal: PR Check / Secret Scan (pull_request) Successful in 9s
Generic: Project CI / Lint & Validate (pull_request) Successful in 14s
RC Revert / Rename rc/ back to dev/ (pull_request) Has been skipped
Branch Cleanup / Delete merged branch (pull_request) Successful in 2s
Universal: PR Check / Validate PR (pull_request) Failing after 14s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 1m8s
Generic: Project CI / Tests (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
The pre-update return URL is assigned to window.location.href, so a javascript:/data: URI (empty host) would have passed the host-only check and executed. Require an absolute http(s) same-host URL or a single-slash root-relative path; reject javascript:/data:/vbscript: and protocol-relative //host. Claude-Session: https://claude.ai/code/session_01WbGBN9VyRK61zczYWcCQ2i
This commit is contained in:
@@ -22,23 +22,36 @@ use Joomla\CMS\Uri\Uri;
|
||||
$ajaxToken = Session::getFormToken();
|
||||
$ajaxUrl = Route::_('index.php?option=com_mokosuitebackup&format=json', false);
|
||||
|
||||
/* Validate the return URL to prevent an open redirect: accept only a relative
|
||||
URL or one whose host matches this site. Falls back to '' (no redirect). */
|
||||
/* Validate the return URL to prevent an open redirect / javascript: XSS
|
||||
(the value ends up in window.location.href). Accept ONLY:
|
||||
- an absolute http(s) URL whose host matches this site, or
|
||||
- a root-relative path starting with a single "/" (not "//").
|
||||
This rejects javascript:, data:, vbscript: (empty host) and
|
||||
protocol-relative //evil.com. Falls back to '' (no redirect). */
|
||||
$safeReturnUrl = '';
|
||||
|
||||
if ($this->returnUrl !== '') {
|
||||
$decoded = base64_decode($this->returnUrl, true);
|
||||
$raw = ($decoded !== false && $decoded !== '') ? $decoded : $this->returnUrl;
|
||||
|
||||
try {
|
||||
$rootHost = Uri::getInstance(Uri::root())->getHost();
|
||||
$target = new Uri($raw);
|
||||
$isAbsoluteHttp = (bool) preg_match('#^https?://#i', $raw);
|
||||
$isRootRelative = isset($raw[0]) && $raw[0] === '/' && (!isset($raw[1]) || $raw[1] !== '/');
|
||||
|
||||
if ($target->getHost() === '' || strcasecmp($target->getHost(), $rootHost) === 0) {
|
||||
$safeReturnUrl = $raw;
|
||||
if ($isAbsoluteHttp || $isRootRelative) {
|
||||
try {
|
||||
$rootHost = Uri::getInstance(Uri::root())->getHost();
|
||||
$target = new Uri($raw);
|
||||
$scheme = strtolower((string) $target->getScheme());
|
||||
|
||||
$schemeOk = $scheme === '' || $scheme === 'http' || $scheme === 'https';
|
||||
$hostOk = $target->getHost() === '' || strcasecmp($target->getHost(), $rootHost) === 0;
|
||||
|
||||
if ($schemeOk && $hostOk) {
|
||||
$safeReturnUrl = $raw;
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
$safeReturnUrl = '';
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
$safeReturnUrl = '';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user