Moderate severityNVD Advisory· Published Dec 11, 2021· Updated Aug 3, 2024
Cross-Site Request Forgery (CSRF) in yetiforcecompany/yetiforcecrm
CVE-2021-4092
Description
yetiforcecrm is vulnerable to Cross-Site Request Forgery (CSRF)
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
yetiforce/yetiforce-crmPackagist | < 6.3.0 | 6.3.0 |
Affected products
1- Range: unspecified
Patches
1585da04bb72dAdded minor improvements
10 files changed · +81 −73
app/Controller/View/Page.php+2 −2 modified@@ -175,7 +175,7 @@ protected function getMenuHeaderLinks(\App\Request $request): array 'linklabel' => 'LBL_SIGN_OUT', 'linkurl' => 'index.php?module=Users&parent=Settings&action=Logout', 'icon' => 'fas fa-power-off fa-fw', - 'linkclass' => 'btn-danger d-md-none', + 'linkclass' => 'btn-danger d-md-none js-post-action', ]; $headerLinkInstances = []; foreach ($headerLinks as $headerLink) { @@ -254,7 +254,7 @@ protected function getUserQuickMenuLinks(\App\Request $request): array 'linklabel' => 'LBL_SIGN_OUT', 'linkurl' => 'index.php?module=Users&parent=Settings&action=Logout', 'icon' => 'fas fa-power-off fa-fw', - 'linkclass' => 'd-none d-sm-none d-md-block', + 'linkclass' => 'd-none d-sm-none d-md-block js-post-action', ]; $headerLinkInstances = []; foreach ($headerLinks as $headerLink) {
config/version.php+2 −2 modified@@ -1,7 +1,7 @@ <?php return [ - 'appVersion' => '6.2.262', - 'patchVersion' => '2021.12.09', + 'appVersion' => '6.2.263', + 'patchVersion' => '2021.12.10', 'lib_roundcube' => '0.2.3', ];
layouts/basic/modules/Users/Modals/PasswordModalFooter.tpl+26 −26 modified@@ -1,29 +1,29 @@ {*<!-- {[The file is published on the basis of YetiForce Public License 4.0 that can be found in the following directory: licenses/LicenseEN.txt or yetiforce.com]} -->*} {strip} -<!-- tpl-Users-Modals-PasswordModalFooter --> -<div class="modal-footer"> - {if ($MODE === 'massReset' || $MODE === 'reset') && $ACTIVE_SMTP} - <button class="btn btn-success" type="submit" name="saveButton" - {if App\Config::main('systemMode') === 'demo'}disabled="disabled"{/if}> - <span class="fas fa-redo-alt mr-2"></span><strong>{\App\Language::translate('BTN_RESET_PASSWORD', $MODULE_NAME)}</strong> - </button> - {/if} - {if $MODE === 'change'} - <button class="btn btn-success" type="submit" name="saveButton" - {if App\Config::main('systemMode') === 'demo'}disabled="disabled"{/if}> - <span class="fas fa-redo-alt mr-2"></span><strong>{\App\Language::translate('LBL_CHANGE_PASSWORD', $MODULE_NAME)}</strong> - </button> - {/if} - {if $LOCK_EXIT} - <a class="btn btn-danger" role="button" href="index.php?module=Users&parent=Settings&action=Logout"> - <span class="fas fa-power-off mr-2"></span><strong>{\App\Language::translate('LBL_SIGN_OUT', $MODULE_NAME)}</strong> - </a> - {else} - <button class="btn btn-danger" type="reset" data-dismiss="modal"> - <span class="fas fa-times mr-2"></span><strong>{\App\Language::translate('LBL_CANCEL', $MODULE_NAME)}</strong> - </button> - {/if} -</div> -</form> -<!-- /tpl-Users-Modals-PasswordModalFooter --> + <!-- tpl-Users-Modals-PasswordModalFooter --> + <div class="modal-footer"> + {if ($MODE === 'massReset' || $MODE === 'reset') && $ACTIVE_SMTP} + <button class="btn btn-success" type="submit" name="saveButton" + {if App\Config::main('systemMode') === 'demo'}disabled="disabled" {/if}> + <span class="fas fa-redo-alt mr-2"></span><strong>{\App\Language::translate('BTN_RESET_PASSWORD', $MODULE_NAME)}</strong> + </button> + {/if} + {if $MODE === 'change'} + <button class="btn btn-success" type="submit" name="saveButton" + {if App\Config::main('systemMode') === 'demo'}disabled="disabled" {/if}> + <span class="fas fa-redo-alt mr-2"></span><strong>{\App\Language::translate('LBL_CHANGE_PASSWORD', $MODULE_NAME)}</strong> + </button> + {/if} + {if $LOCK_EXIT} + <a class="btn btn-danger js-post-action" role="button" href="index.php?module=Users&parent=Settings&action=Logout"> + <span class="fas fa-power-off mr-2"></span><strong>{\App\Language::translate('LBL_SIGN_OUT', $MODULE_NAME)}</strong> + </a> + {else} + <button class="btn btn-danger" type="reset" data-dismiss="modal"> + <span class="fas fa-times mr-2"></span><strong>{\App\Language::translate('LBL_CANCEL', $MODULE_NAME)}</strong> + </button> + {/if} + </div> + </form> + <!-- /tpl-Users-Modals-PasswordModalFooter --> {/strip}
layouts/basic/modules/Vtiger/Index.tpl+2 −2 modified@@ -20,10 +20,10 @@ <a class="btn btn-success mr-2" role="button" href="javascript:window.history.back();"> <span class="fas fa-chevron-left mr-2"></span>{\App\Language::translate('LBL_GO_BACK')} </a> - <a class="btn btn-warning mr-2" role="button" href="?module=Users&action=Logout"> + <a class="btn btn-warning mr-2 js-post-action" role="button" href="index.php?module=Users&action=Logout"> <span class="fas fa-power-off fa-fw mr-2"></span>{\App\Language::translate('LBL_SIGN_OUT')} </a> - <a class="btn btn-primary" role="button" href="?module=Users&action=Logout"> + <a class="btn btn-primary" role="button" href="index.php"> <i class="fas fa-home mr-2"></i>{\App\Language::translate('LBL_MAIN_PAGE')} </a> </p>
modules/Users/actions/Logout.php+0 −8 modified@@ -38,12 +38,4 @@ public function process(App\Request $request) //End header('location: index.php'); } - - /** - * {@inheritdoc} - */ - public function validateRequest(App\Request $request) - { - $request->validateReadAccess(); - } }
public_html/layouts/basic/modules/Vtiger/resources/List.js+5 −5 modified@@ -195,7 +195,7 @@ $.Class( let formData = container.find('.js-modal-form').serializeFormData(); const listInstance = Vtiger_List_Js.getInstance(); $.extend(formData, listInstance.getSearchParams()); - app.openUrlMethodPost('index.php', formData); + AppConnector.requestForm('index.php', formData); Vtiger_Helper_Js.showMessage({ text: app.vtranslate('JS_STARTED_GENERATING_FILE'), type: 'info' @@ -355,7 +355,7 @@ $.Class( } let params = Vtiger_List_Js.getInstance().getSearchParams(); delete params.view; - app.openUrlMethodPost(exportActionUrl, params, formAttr); + AppConnector.requestForm(exportActionUrl, params, formAttr); }, /** * Function to reload list @@ -1488,7 +1488,7 @@ $.Class( Vtiger_Helper_Js.showConfirmationBox({ message: app.vtranslate('JS_LBL_ARE_YOU_SURE_YOU_WANT_TO_DELETE_FILTER') }).done((e) => { - app.openUrlMethodPost(thisInstance.getSelectOptionFromChosenOption(liElement).data('deleteurl')); + AppConnector.requestForm(thisInstance.getSelectOptionFromChosenOption(liElement).data('deleteurl')); }); event.stopPropagation(); }); @@ -1505,7 +1505,7 @@ $.Class( //to close the dropdown thisInstance.getFilterSelectElement().data('select2').close(); const liElement = $(event.currentTarget).closest('.select2-results__option'); - app.openUrlMethodPost(thisInstance.getSelectOptionFromChosenOption(liElement).data('approveurl')); + AppConnector.requestForm(thisInstance.getSelectOptionFromChosenOption(liElement).data('approveurl')); event.stopPropagation(); }); } @@ -1521,7 +1521,7 @@ $.Class( //to close the dropdown thisInstance.getFilterSelectElement().data('select2').close(); const liElement = $(event.currentTarget).closest('.select2-results__option'); - app.openUrlMethodPost(thisInstance.getSelectOptionFromChosenOption(liElement).data('denyurl')); + AppConnector.requestForm(thisInstance.getSelectOptionFromChosenOption(liElement).data('denyurl')); event.stopPropagation(); }); }
public_html/layouts/basic/modules/Vtiger/resources/RelatedList.js+1 −1 modified@@ -86,7 +86,7 @@ jQuery.Class( data: postData }; if (type === 'sendByForm') { - app.openUrlMethodPost(massActionUrl, postData); + AppConnector.requestForm(massActionUrl, postData); progressIndicatorElement.progressIndicator({ mode: 'hide' }); } else { AppConnector.request(actionParams)
public_html/layouts/basic/modules/Vtiger/resources/Vtiger.js+1 −1 modified@@ -171,7 +171,7 @@ var Vtiger_Index_Js = { form.append($('<input>', { name: i, value: JSON.stringify(postData[i]) })); } $('body').append(form); - form.submit(); + form.trigger('submit'); } else { window.location.href = url; }
public_html/layouts/resources/app.js+16 −23 modified@@ -306,7 +306,7 @@ var App = (window.App = { $(data).removeAttr('data-validation-engine'); }); form.addClass('not_validation'); - form.submit(); + form.trigger('submit'); }, /** * Register tab events @@ -484,7 +484,7 @@ var App = (window.App = { $(data).removeAttr('data-validation-engine'); }); form.addClass('not_validation'); - form.submit(); + form.trigger('submit'); }, /** * Save quick create form @@ -2627,27 +2627,6 @@ var app = (window.app = { window.location.href = url; } }, - openUrlMethodPost(url, postData = {}, formAttr = {}) { - $.extend(formAttr, { - method: 'post', - action: url, - style: 'display:none;' - }); - let form = $('<form></form>', formAttr); - if (typeof csrfMagicName !== 'undefined') { - postData[csrfMagicName] = csrfMagicToken; - } - $.each(postData, (index, value) => { - let input = $(document.createElement('input')); - input.attr('type', 'hidden'); - input.attr('name', index); - input.val(value); - form.append(input); - }); - $('body').append(form); - form.submit(); - form.remove(); - }, /** * Convert url string to object * @@ -3177,6 +3156,19 @@ var app = (window.app = { } }); } + }, + /** + * Register POST action + * @param {jQuery} container + */ + registerPostActionEvent: function (container) { + container.on('click', '.js-post-action', function (e) { + e.preventDefault(); + let element = $(this); + if (element.attr('href')) { + AppConnector.requestForm(element.attr('href')); + } + }); } }); CKEDITOR.disableAutoInline = true; @@ -3203,6 +3195,7 @@ $(function () { app.registerFormsEvents(document); app.registerRecordActionsEvents(document); app.registerKeyboardShortcutsEvent(document); + app.registerPostActionEvent(document); App.Components.QuickCreate.register(document); App.Components.Scrollbar.initPage(); App.Clipboard.register(document);
public_html/layouts/resources/Connector.js+26 −3 modified@@ -146,8 +146,31 @@ window.AppConnector = { } return aDeferred.promise(); }, - - requestForm: function (url, params = {}) { - app.openUrlMethodPost(url, params); + /** + * Send form data + * @param {string} url + * @param {object} postData + * @param {object} formAttr + */ + requestForm: function (url, postData = {}, formAttr = {}) { + $.extend(formAttr, { + method: 'post', + action: url, + style: 'display:none;' + }); + let form = $('<form></form>', formAttr); + if (typeof csrfMagicName !== 'undefined') { + postData[csrfMagicName] = csrfMagicToken; + } + $.each(postData, (index, value) => { + let input = $(document.createElement('input')); + input.attr('type', 'hidden'); + input.attr('name', index); + input.val(value); + form.append(input); + }); + $('body').append(form); + form.trigger('submit'); + form.remove(); } };
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
4- github.com/advisories/GHSA-v4cr-m5f8-gxw8ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2021-4092ghsaADVISORY
- github.com/yetiforcecompany/yetiforcecrm/commit/585da04bb72d36a894f6ea5939ab909e53fd8c23ghsax_refsource_MISCWEB
- huntr.dev/bounties/7b58c160-bb62-45fe-ad1f-38354378b89eghsax_refsource_CONFIRMWEB
News mentions
0No linked articles in our index yet.