See: https://www.drupal.org/SA-CORE-2015-003
http://cgit.drupalcode.org/drupal/commit/?h=7.x&id=731dfacab8bf39918c135...

A vulnerability was found that allows a malicious user to perform a cross-site scripting attack by invoking Drupal.ajax() on a whitelisted HTML element.

This vulnerability is mitigated on sites that do not allow untrusted users to enter HTML.

Drupal 6 core is not affected, but see the similar advisory for the Drupal 6 contributed Ctools module: SA-CONTRIB-2015-141.

Credit for the D6/D7 version of this patch (the security release):

regilero, droplet, japerry, samuel.mortenson, Pere Orga, nod_, effulgentsia, benjy, Gábor Hojtsy, greggles, Wim Leers, tim.plunkett, David_Rothstein, larowlan, pwolanin, neclimdul, EclipseGc, znerol

Comments

webchick created an issue. See original summary.

webchick’s picture

Issue summary: View changes

Adding folks from the CTools SA to the credit section as well.

tim.plunkett’s picture

Status: Active » Needs review
StatusFileSize
new11.25 KB

First pass at porting it, done with @effulgentsia.

Status: Needs review » Needs work

The last submitted patch, 3: 2554219-autocomplete-3.patch, failed testing.

larowlan’s picture

  1. +++ b/core/misc/ajax.js
    @@ -377,18 +389,36 @@ else if (this.element && element.form) {
    +        // ajax_set_verification_header() for details.
    

    this function is gone now right? - we should reference AjaxResponseSubscriber now.

  2. +++ b/core/misc/ajax.js
    @@ -377,18 +389,36 @@ else if (this.element && element.form) {
    +        //   #ajax) can bypass header verification. This is especially useful for
    

    nit: >80

Will look at the fails next

larowlan’s picture

Status: Needs work » Needs review
StatusFileSize
new3.86 KB
new12.61 KB

should fix fail, and addresses #5

nod_’s picture

Originally wanted to put that on Drupal.url.

Any objection to renaming the functions ?

Drupal.url.absolute = function () {};
Drupal.url.isLocal = function () {};
dawehner’s picture

+1 for isAbsolute and isLocal

nod_’s picture

StatusFileSize
new12.85 KB
new8.62 KB

Couple of updates:

  • After talking with dawehner on IRC, changed Drupal.url.absolute to Drupal.url.toAbsolute,
  • We don't use snake_case in JS and giving a better variable name for old_url,
  • Renamed the methods Drupal.url.isLocal and Drupal.url.toAbsolute,
  • Move the new methods just below Drupal.url declaration,
  • Changed the key name to ajaxTrustedUrl in drupalSettings to be closer to existing ajaxPageState,
  • Removed the initialization of ajaxTrustedUrl in ajax.js since that's a job for the drupal.ajax library declaration,
  • Reformated the 3 catch to make eslint happy.
tim.plunkett’s picture

Status: Needs review » Reviewed & tested by the community

My work in #3 was a straight port, the changes in #6 and #9 look great, thanks @larowlan and @nod_!

  • effulgentsia committed ce6f3ec on 8.0.x
    Issue #2554219 by nod_, larowlan, tim.plunkett, regilero, droplet,...
arlinsandbulte’s picture

Status: Reviewed & tested by the community » Fixed

Looks like this was committed, but not marked fixed...

effulgentsia’s picture

I reviewed and manually tested #9 and agree with #10, so committed and pushed to 8.0.x. Thanks for the nice improvements!

Here's some things that I think could use one or more non-critical follow-up issues, if someone cares to open it/them.

  1. +++ b/core/core.libraries.yml
    @@ -87,6 +87,7 @@ drupal.ajax:
    +    ajaxTrustedUrl: {}
    

    +1 to this name over the D7 version of urlIsAjaxTrusted. However, with this new name, should we pluralize it?

  2. +++ b/core/lib/Drupal/Core/Form/FormBuilder.php
    @@ -943,6 +943,11 @@ public function doBuildForm($form_id, &$element, FormStateInterface &$form_state
    +      $element['#attached']['drupalSettings']['ajaxTrustedUrl'][$element['#action']] = TRUE;
    +++ b/core/lib/Drupal/Core/Render/Element/RenderElement.php
    @@ -304,6 +304,7 @@ public static function preRenderAjaxForm($element) {
    +      $element['#attached']['drupalSettings']['ajaxTrustedUrl'][$settings['url']] = TRUE;
    

    Both of these could benefit from test coverage. That test coverage would be nice to backport to 7.x as well.

  3. +++ b/core/misc/ajax.js
    @@ -377,18 +387,36 @@
    +        //   #ajax) can bypass header verification. This is especially useful
    +        //   for Ajax with multipart forms. Because IFRAME transport is used,
    +        //   the response headers cannot be accessed for verification.
    

    D8 uses a version of jquery.form that only uses IFRAME transport for browsers that don't support XHR2, which I think is just IE9 at this point (among what D8 supports). Would be nice to improve this comment to mention that.

  4. +++ b/core/misc/ajax.js
    @@ -411,6 +439,9 @@
    +        throw new Error(Drupal.t('The callback URL is not local and not trusted: !url', {'!url': ajax.url}));
    

    Elsewhere in D8's JS, we don't translate the message when throwing an error. I don't see why this one needs to be different.

  5. +++ b/core/misc/drupal.js
    @@ -401,6 +401,81 @@ if (window.jQuery) {
    +  Drupal.url.toAbsolute = function (url) {
    +    var urlParsingNode = document.createElement('a');
    +
    +    // Decode the URL first; this is required by IE <= 6. Decoding non-UTF-8
    +    // strings may throw an exception.
    +    try {
    +      url = decodeURIComponent(url);
    +    }
    +    catch (e) {
    +      // Empty.
    +    }
    +
    +    urlParsingNode.setAttribute('href', url);
    +
    +    // IE <= 7 normalizes the URL when assigned to the anchor node similar to
    +    // the other browsers.
    +    return urlParsingNode.cloneNode(false).href;
    +  };
    

    D8 doesn't support IE 6 or 7, so can this function be simplified?

effulgentsia’s picture

Status: Fixed » Needs work
+++ b/core/misc/drupal.js
@@ -401,6 +401,81 @@ if (window.jQuery) {
+    var baseUrl = protocol + '//' + location.host + drupalSettings.basePath.slice(0, -1);

Oops. drupalSettings.basePath isn't a thing in D8. We have drupalSettings.path.baseUrl instead. So, this broke all the modal links in Views UI. But the nojs fallbacks of those links still seem to work, so not sure whether to revert this, or try to get a quick fix in for that line instead. I'll check back in a couple hours to see if the latter is ready, and if not, will revert.

  • effulgentsia committed 3e82ee5 on 8.0.x
    Issue #2554219 follow-up: Fix usage of obsolete drupalSettings.basePath
    
effulgentsia’s picture

Status: Needs work » Fixed
StatusFileSize
new543 bytes

I didn't want to revert, so committed this instead.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.