From f131a616eb990e2b070a8381c3106ae979d40989 Mon Sep 17 00:00:00 2001 From: Kijin Sung Date: Mon, 16 Feb 2026 21:56:44 +0900 Subject: [PATCH 1/2] Fix RVE-2026-1 arbitrary file association by extra var --- common/lang/en.php | 1 + common/lang/ko.php | 1 + modules/document/document.controller.php | 35 ++++++++++++++---------- modules/document/document.model.php | 1 + modules/extravar/models/Value.php | 26 ++++++++++++++---- 5 files changed, 44 insertions(+), 20 deletions(-) diff --git a/common/lang/en.php b/common/lang/en.php index b63f049ac..885c2057a 100644 --- a/common/lang/en.php +++ b/common/lang/en.php @@ -359,6 +359,7 @@ $lang->filter['invalid_alpha_number'] = 'The format of %s is invalid. Please ent $lang->filter['invalid_mid'] = 'The format of %s is invalid. Module ID should be begun with a letter. Subsequent characters may be letters, digits or underscore characters.'; $lang->filter['invalid_number'] = 'The format of %s is invalid. Please enter numbers only.'; $lang->filter['invalid_float'] = 'The format of %s is invalid. Please enter numbers only.'; +$lang->filter['invalid_file'] = 'The value of %s is not a valid file upload.'; $lang->filter['invalid_extension'] = 'The format of %s is invalid. e.g. gif, jpg, png'; $lang->security_warning_embed = 'Due to security concern, administrators are not allowed to view embedded items.
To view them, please use another non-administrator ID.'; $lang->msg_pc_to_mobile = 'View mobile optimized version of this page'; diff --git a/common/lang/ko.php b/common/lang/ko.php index d12c63646..f744f30c3 100644 --- a/common/lang/ko.php +++ b/common/lang/ko.php @@ -359,6 +359,7 @@ $lang->filter['invalid_alpha_number'] = '%s의 형식이 잘못되었습니다. $lang->filter['invalid_mid'] = '%s의 형식이 잘못되었습니다. 첫 글자는 영문으로 시작해야 하며 \'영문+숫자+_\'로만 입력해야 합니다.'; $lang->filter['invalid_number'] = '%s의 형식이 잘못되었습니다. 숫자로만 입력해야 합니다.'; $lang->filter['invalid_float'] = '%s의 형식이 잘못되었습니다. 숫자로만 입력해야 합니다.'; +$lang->filter['invalid_file'] = '%s의 값은 올바르게 업로드된 파일이 아닙니다.'; $lang->filter['invalid_extension'] = '%s의 형식이 잘못되었습니다. gif, jpg, png 등 쉼표로 구분하여 입력해야 합니다.'; $lang->security_invalid_session = '바르지 않은 접근입니다. 인증을 위해 다시 로그인해야 합니다.'; $lang->security_warning_embed = '보안 문제로 관리자 아이디로는 embed를 볼 수 없습니다. 확인하려면 다른 아이디로 접속하세요'; diff --git a/modules/document/document.controller.php b/modules/document/document.controller.php index dc3e0506b..72608b49f 100644 --- a/modules/document/document.controller.php +++ b/modules/document/document.controller.php @@ -897,7 +897,7 @@ class DocumentController extends Document } // Handle extra vars that support file upload. - if ($extra_item->type === 'file' && is_array($value)) + if ($extra_item->type === 'file' && $value) { $ev_output = $extra_item->uploadFile($value, $obj->document_srl, 'doc'); if (!$ev_output->toBool()) @@ -1295,16 +1295,20 @@ class DocumentController extends Document if ($extra_item->type === 'file') { // New upload - if (is_array($value) && isset($value['name'])) + if (is_array($value) && isset($value['tmp_name'])) { // Delete old file if (isset($old_extra_vars[$idx]->value)) { - $fc_output = FileController::getInstance()->deleteFile($old_extra_vars[$idx]->value); - if (!$fc_output->toBool()) + $old_file = FileModel::getFile($old_extra_vars[$idx]->value); + if ($old_file && $old_file->upload_target_srl == $obj->document_srl) { - $oDB->rollback(); - return $fc_output; + $fc_output = FileController::getInstance()->deleteFile($old_file->file_srl); + if (!$fc_output->toBool()) + { + $oDB->rollback(); + return $fc_output; + } } } // Insert new file @@ -1329,21 +1333,22 @@ class DocumentController extends Document return $ev_output; } // Delete old file - $fc_output = FileController::getInstance()->deleteFile($old_extra_vars[$idx]->value); - if (!$fc_output->toBool()) + $old_file = FileModel::getFile($old_extra_vars[$idx]->value); + if ($old_file && $old_file->upload_target_srl == $obj->document_srl) { - $oDB->rollback(); - return $fc_output; + $fc_output = FileController::getInstance()->deleteFile($old_file->file_srl); + if (!$fc_output->toBool()) + { + $oDB->rollback(); + return $fc_output; + } } } } // Leave current file unchanged - elseif (!$value) + elseif (isset($old_extra_vars[$idx]->value)) { - if (isset($old_extra_vars[$idx]->value)) - { - $value = $old_extra_vars[$idx]->value; - } + $value = $old_extra_vars[$idx]->value; } } } diff --git a/modules/document/document.model.php b/modules/document/document.model.php index 6a3137c03..e95bcb32d 100644 --- a/modules/document/document.model.php +++ b/modules/document/document.model.php @@ -111,6 +111,7 @@ class DocumentModel extends Document foreach($GLOBALS['XE_EXTRA_KEYS'][$module_srl] as $idx => $key) { $document_extra_vars[$idx] = clone($key); + $document_extra_vars[$idx]->parent_srl = $document_srl; // set variable value in user language if(isset($document_extra_values[$idx][$user_lang_code])) diff --git a/modules/extravar/models/Value.php b/modules/extravar/models/Value.php index 5bf9d2dd3..4e3a21bc8 100644 --- a/modules/extravar/models/Value.php +++ b/modules/extravar/models/Value.php @@ -25,6 +25,7 @@ class Value public $input_id = ''; public $input_name = ''; public $parent_type = 'document'; + public $parent_srl = null; public $type = 'text'; public $value = null; public $name = ''; @@ -159,7 +160,7 @@ class Value */ public function getValueHTML(): string { - return self::_getTypeValueHTML($this->type, $this->value); + return self::_getTypeValueHTML($this->type, $this->value, $this->parent_type, $this->parent_srl); } /** @@ -280,7 +281,7 @@ class Value $values = [$value]; } - // Check if a required value is empty. + // Check that a required value is not empty. if ($this->is_required === 'Y') { if ($this->type === 'file' && !$value && $old_value) @@ -298,7 +299,7 @@ class Value } } - // Check if a strict value is not one of the specified options. + // Check that a strict value equals one of the specified options. if ($this->is_strict === 'Y' && $value) { if ($this->canHaveOptions()) @@ -321,6 +322,15 @@ class Value } } + // Check that a file value is actually an uploaded file. + if ($this->type === 'file' && $value) + { + if (!isset($value['tmp_name']) || !is_uploaded_file($value['tmp_name'])) + { + return new BaseObject(-1, sprintf(lang('common.filter.invalid_file'), Context::replaceUserLang($this->name))); + } + } + return new BaseObject; } @@ -442,9 +452,11 @@ class Value * * @param string $type * @param string|array $value + * @param string $parent_type + * @param ?int $parent_srl * @return string */ - protected static function _getTypeValueHTML(string $type, $value): string + protected static function _getTypeValueHTML(string $type, $value, string $parent_type, ?int $parent_srl = null): string { // Return if the value is empty. $value = self::_getTypeValue($type, $value); @@ -511,10 +523,14 @@ class Value if ($value) { $file = FileModel::getFile($value); - if ($file) + if ($file && $file->upload_target_srl == $parent_srl) { return sprintf('%s (%s)', \RX_BASEURL . ltrim($file->download_url, './'), $file->source_filename, FileHandler::filesize($file->file_size)); } + elseif ($file) + { + return sprintf('%s (%s)', $file->source_filename, FileHandler::filesize($file->file_size)); + } else { return ''; From 187bffe9d281f14dbd20ccaab40de2602b912543 Mon Sep 17 00:00:00 2001 From: Kijin Sung Date: Mon, 16 Feb 2026 21:59:14 +0900 Subject: [PATCH 2/2] Fix unit test for Validator --- tests/unit/classes/validator/condition.en.js | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/unit/classes/validator/condition.en.js b/tests/unit/classes/validator/condition.en.js index 5801af061..d0e51a57a 100644 --- a/tests/unit/classes/validator/condition.en.js +++ b/tests/unit/classes/validator/condition.en.js @@ -18,5 +18,6 @@ v.cast('ADD_MESSAGE',['invalid_alpha_number','%s의 형식이 잘못되었습니 v.cast('ADD_MESSAGE',['invalid_mid','%s의 형식이 잘못되었습니다. 첫 글자는 영문으로 시작해야 하며 \'영문+숫자+_\'로만 입력해야 합니다.']); v.cast('ADD_MESSAGE',['invalid_number','%s의 형식이 잘못되었습니다. 숫자로만 입력해야 합니다.']); v.cast('ADD_MESSAGE',['invalid_float','%s의 형식이 잘못되었습니다. 숫자로만 입력해야 합니다.']); +v.cast('ADD_MESSAGE',['invalid_file','%s의 값은 올바르게 업로드된 파일이 아닙니다.']); v.cast('ADD_MESSAGE',['invalid_extension','%s의 형식이 잘못되었습니다. gif, jpg, png 등 쉼표로 구분하여 입력해야 합니다.']); })(jQuery);