Merge pull request #6911 from JediKev/security/latest-patches-01-2026
Reviewed-By: JediKev <kevin@enhancesoft.com>
This commit is contained in:
@@ -68,7 +68,7 @@ if($thisclient && $thisclient->getId() && $thisclient->isValid()){
|
||||
|
||||
/******* CSRF Protectin *************/
|
||||
// Enforce CSRF protection for POSTS
|
||||
if ($_POST && !$ost->checkCSRFToken()) {
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST' && !$ost->checkCSRFToken()) {
|
||||
Http::redirect('index.php');
|
||||
//just incase redirect fails
|
||||
die('Action denied (400)!');
|
||||
|
||||
@@ -278,6 +278,11 @@ class Format {
|
||||
$props = array();
|
||||
foreach ($styles as $i=>&$s) {
|
||||
@list($prop, $val) = explode(':', $s);
|
||||
// Strip all CSS url() usages in inline styles
|
||||
if (preg_match('/\burl\s*\(/i', $val)) {
|
||||
unset($styles[$i]);
|
||||
continue;
|
||||
}
|
||||
if (isset($props[$prop])) {
|
||||
unset($styles[$i]);
|
||||
continue;
|
||||
@@ -348,7 +353,7 @@ class Format {
|
||||
'comment' => 1, //Remove html comments (OUTLOOK LOVE THEM)
|
||||
'tidy' => -1,
|
||||
'elements' => '*-form-input-button',
|
||||
'deny_attribute' => 'id, formaction, action, on*',
|
||||
'deny_attribute' => 'id, formaction, action, srcset, on*',
|
||||
'schemes' => 'href: aim, feed, file, ftp, gopher, http, https, irc, mailto, news, nntp, sftp, ssh, telnet; *:file, http, https; src: cid, http, https, data',
|
||||
'hook_tag' => function($e, $a=0) { return Format::__html_cleanup($e, $a); },
|
||||
);
|
||||
@@ -357,9 +362,12 @@ class Format {
|
||||
if ($cfg)
|
||||
$whitelist = $cfg->getIframeWhitelist();
|
||||
if (!empty($whitelist)) {
|
||||
$whitelist_quoted = array_map(function ($d) {
|
||||
return preg_quote($d, '`');
|
||||
}, $whitelist);
|
||||
$config['elements'] .= '+iframe';
|
||||
$config['spec'] = 'iframe=-*,height,width,type,style,src(match="`^(https?:)?//(www\.)?('
|
||||
.implode('|', $whitelist)
|
||||
.implode('|', $whitelist_quoted)
|
||||
.')(\?|/|#)([^@]*)$`i"),frameborder'.($options['spec'] ? '; '.$options['spec'] : '').',allowfullscreen';
|
||||
}
|
||||
|
||||
@@ -483,16 +491,17 @@ class Format {
|
||||
// Allowed Inline External Image Extensions
|
||||
$allowed = array('gif', 'png', 'jpg', 'jpeg');
|
||||
$exclude = !$cfg->allowExternalImages();
|
||||
$local = false;
|
||||
|
||||
$input = preg_replace_callback('/<img ([^>]*?)(src="([^"]+)")([^>]*)\/?>/',
|
||||
function($match) use ($local, $allowed, $exclude, $display) {
|
||||
if (strpos($match[3], 'cid:') !== false)
|
||||
$local = true;
|
||||
$input = preg_replace_callback('/<img\b([^>]*?)\bsrc\s*=\s*(["\'])(.*?)\2([^>]*)\/?>/i',
|
||||
function($match) use ($allowed, $exclude, $display) {
|
||||
$src = $match[3];
|
||||
|
||||
// CID is only valid if it is the prefix of the src value
|
||||
$local = (stripos(ltrim($src), 'cid:') === 0);
|
||||
|
||||
// Split the src URL and get the extension
|
||||
$part = parse_url($match[3], PHP_URL_PATH);
|
||||
$path = explode('.', $part);
|
||||
$part = parse_url($src, PHP_URL_PATH);
|
||||
$path = explode('.', (string) $part);
|
||||
$ext = preg_split('/[^A-Za-z]/', end($path))[0];
|
||||
|
||||
if (!$local && (($exclude && $display) || !in_array($ext, $allowed)))
|
||||
@@ -500,7 +509,8 @@ class Format {
|
||||
else
|
||||
return $match[0];
|
||||
},
|
||||
$input);
|
||||
$input
|
||||
);
|
||||
|
||||
return $input;
|
||||
}
|
||||
|
||||
@@ -5248,6 +5248,8 @@ class FileUploadWidget extends Widget {
|
||||
);
|
||||
|
||||
function render($options=array()) {
|
||||
global $ost;
|
||||
|
||||
$config = $this->field->getConfiguration();
|
||||
$name = $this->field->getFormName();
|
||||
$id = substr(md5(spl_object_hash($this)), 10);
|
||||
@@ -5333,6 +5335,7 @@ class FileUploadWidget extends Widget {
|
||||
url: 'ajax.php/form/upload/<?php echo $field_id; ?>',
|
||||
link: $('#<?php echo $id; ?>').find('a.manual'),
|
||||
paramname: 'upload[]',
|
||||
data: {"__CSRFToken__": "<?php echo $ost->getCSRF()->getToken(); ?>"},
|
||||
fallback_id: 'file-<?php echo $id; ?>',
|
||||
allowedfileextensions: <?php echo JsonDataEncoder::encode(
|
||||
$config['__extensions'] ?: array()); ?>,
|
||||
|
||||
@@ -422,7 +422,7 @@ class DatabaseSessionRecord extends VerySimpleModel
|
||||
}
|
||||
catch (DoesNotExist $e) {
|
||||
// We're auto-creating model (unsaved) when one doesn't exist?
|
||||
$record = $autocreate ? self::create($id) : null;
|
||||
$record = ($autocreate && ctype_alnum($id)) ? self::create($id) : null;
|
||||
}
|
||||
catch (OrmException | Exception $ex) {
|
||||
// This could happen if more than one record exits in the
|
||||
|
||||
@@ -26,29 +26,32 @@ class mPDFWithLocalImages extends Mpdf {
|
||||
$self = $this;
|
||||
$images = $cids = array();
|
||||
// Try and get information for all the files in one query
|
||||
if (preg_match_all('/"cid:([\w._-]{32})"/', $html, $cids)) {
|
||||
if (preg_match_all('/\bsrc\s*=\s*(["\'])\s*cid:\s*([\w._-]{32})\s*\1/i', $html, $cids)) {
|
||||
foreach (AttachmentFile::objects()
|
||||
->filter(array('key__in' => $cids[1]))
|
||||
->filter(array('key__in' => $cids[2]))
|
||||
as $file
|
||||
) {
|
||||
$images[strtolower($file->getKey())] = $file;
|
||||
}
|
||||
}
|
||||
$args[0] = preg_replace_callback('/"cid:([\w.-]{32})"/',
|
||||
$args[0] = preg_replace_callback('/\bsrc\s*=\s*(["\'])\s*cid:\s*([\w._-]{32})\s*\1/i',
|
||||
function($match) use ($self, $images, &$filenumber) {
|
||||
if (!($file = @$images[strtolower($match[1])]))
|
||||
return $match[0];
|
||||
if (!($file = @$images[strtolower($match[2])]))
|
||||
return $match[0]; // leave unchanged if not resolvable
|
||||
$key = "__attached_file_".$filenumber++;
|
||||
$self->imageVars[$key] = $file->getData();
|
||||
return 'var:'.$key;
|
||||
// Preserve attribute formatting: src="var:..."
|
||||
return 'src='.$match[1].'var:'.$key.$match[1];
|
||||
},
|
||||
$html
|
||||
);
|
||||
// unregister phar stream to mitigate vulnerability in mpdf library
|
||||
@stream_wrapper_unregister('phar');
|
||||
@stream_wrapper_unregister('php');
|
||||
call_user_func_array(array('parent', 'WriteHtml'), $args);
|
||||
// restore phar stream
|
||||
@stream_wrapper_restore('phar');
|
||||
@stream_wrapper_restore('php');
|
||||
}
|
||||
|
||||
function output($name = '', $dest = '') {
|
||||
|
||||
@@ -229,9 +229,9 @@ class Validator {
|
||||
return $error == '';
|
||||
}
|
||||
|
||||
static function is_userid($userid, &$error='') {
|
||||
static function is_userid($userid, &$error='', $verify=false) {
|
||||
if (!self::is_username($userid)
|
||||
&& !self::is_email($userid))
|
||||
&& !self::is_email($userid, false, $verify))
|
||||
$error = __('Invalid User Id ');
|
||||
return $error == '';
|
||||
}
|
||||
|
||||
@@ -48,8 +48,9 @@ if ($_POST) {
|
||||
if ($_POST && isset($_POST['luser'])) {
|
||||
if (!$_POST['luser'])
|
||||
$errors['err'] = __('Valid username or email address is required');
|
||||
elseif (($user = UserAuthenticationBackend::process(trim($_POST['luser']),
|
||||
substr($_POST['lpasswd'], 0, 128), $errors))) {
|
||||
elseif (Validator::is_userid(trim($_POST['luser']), $errors['err'], false)
|
||||
&& ($user = UserAuthenticationBackend::process(trim($_POST['luser']),
|
||||
substr($_POST['lpasswd'], 0, 128), $errors))) {
|
||||
if ($user instanceof ClientCreateRequest) {
|
||||
if ($cfg && $cfg->isClientRegistrationEnabled()) {
|
||||
// Attempt to automatically register
|
||||
|
||||
@@ -15,6 +15,7 @@ if($_POST) {
|
||||
}
|
||||
switch ($_POST['do']) {
|
||||
case 'sendmail':
|
||||
$start = microtime(true);
|
||||
$userid = (string) $_POST['userid'];
|
||||
if (Validator::is_userid($userid)
|
||||
&& ($acct=ClientAccount::lookupByUsername($userid))) {
|
||||
@@ -34,6 +35,14 @@ if($_POST) {
|
||||
else
|
||||
$inc = 'pwreset.sent.php';
|
||||
|
||||
$min = 1.4;
|
||||
$jitter = random_int(0, 250) / 1000;
|
||||
$target = $min + $jitter;
|
||||
|
||||
$elapsed = microtime(true) - $start;
|
||||
if ($elapsed < $target)
|
||||
usleep((int)(($target - $elapsed) * 1_000_000));
|
||||
|
||||
break;
|
||||
case 'reset':
|
||||
$inc = 'pwreset.login.php';
|
||||
|
||||
@@ -68,8 +68,9 @@ if ($_POST) {
|
||||
if ($_POST && isset($_POST['userid'])) {
|
||||
// Lookup support backends for this staff
|
||||
$username = trim($_POST['userid']);
|
||||
if ($user = StaffAuthenticationBackend::process($username,
|
||||
substr($_POST['passwd'], 0, 128), $errors)) {
|
||||
if (Validator::is_userid($username, $errors['err'], false)
|
||||
&& ($user = StaffAuthenticationBackend::process($username,
|
||||
substr($_POST['passwd'], 0, 128), $errors))) {
|
||||
$redirect($user->isValid() ? $dest : 'login.php');
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user