I just tried to make an issue that described an encoding issue I was experiencing with a contrib module: #359265: Instance Titles improperly escaped. As part of this, I wanted to include the literal text as shown in the first couple of lines of http://drupal.org/files/issues/Picture%204_0.JPG

ie (double-spaced): W h o & # 0 3 9 ; s O n l i n e 1

However the preview showed this as : Who's Online 1

Fine, I figured I'd replace the & with an "& a m p ;", making the string:

W h o & a m p ; # 0 3 9 ; s O n l i n e 1

But this still showed : Who's Online 1

Eh? Is htmlspecialchars_decode() called _twice_ on the text? Maybe three?!?!

W h o & a m p ; a m p ; # 0 3 9 ; s O n l i n e 1

But that shows Who's Online 1

Uugugugh

Comments

lyricnz’s picture

Project: Project » Drupal core
Version: x.y.z » 5.15
Component: Issues » filter.module

PS: wrapping the HTML in <code> doesn't help : Who&#039;s Online 1

lyricnz’s picture

Here's a string that DOES deliver the right output

Who&#38;#039;s Online 1

That's

W h o & # 3 8 ; # 0 3 9 ; s O n l i n e 1

heine’s picture

This is caused by filter_xss:

// Summary &amp;#039; is converted in filter_xss to &amp;amp;#039;
// but the named conversion turns it back in &amp;#039; the decimal conversion then turns it in & #039;

  // Defuse all HTML entities, results in &amp;amp;#039;
  $string = str_replace('&', '&amp;', $string);
  // Change back only well-formed entities in our whitelist

  // Named entities, results in &amp;#039;
  $string = preg_replace('/&amp;([A-Za-z][A-Za-z0-9]*;)/', '&\1', $string);

  // Decimal numeric entities, oops, results in & #039;
  $string = preg_replace('/&amp;#([0-9]+;)/', '&#\1', $string);

//  (idem)
  // Hexadecimal numeric entities
  $string = preg_replace('/&amp;#[Xx]0*((?:[0-9A-Fa-f]{2})+;)/', '&#x\1', $string);

heine’s picture

Status: Active » Needs review
StatusFileSize
new1013 bytes

Requires extremely thorough review.

damien tournoud’s picture

Version: 5.15 » 7.x-dev
Issue tags: +Needs tests

Bumping all the way to D7.

heine’s picture

Status: Needs review » Needs work

This isn't right either.

david strauss’s picture

Subscribing.

heine’s picture

Status: Needs work » Needs review

Slept on it, still makes sense.

c960657’s picture

I think it looks good. Now neither of the first two preg_replace() calls can generate a substring that - together with any prefix or suffix - matches the following preg_replace patterns.

As an alternative approach, the lines visible in the patch can be replaced by a single preg_replace that uses a negative look-ahead assertion (the pattern for hexadecimal entities is modified to also allow characters with an odd number of digits, e.g. &#x555;):
$string = preg_replace('/&(?![a-z][a-z0-9]*;|#[0-9]+;|#x[0-9a-f]+;)/i', '&amp;', $string);

Status: Needs review » Needs work

The last submitted patch failed testing.

Freso’s picture

Status: Needs work » Needs review

Here's the patch from #4 plus some unit testing of filter_xss(). The third test/assert currently fails, but is fixed by the patch. I can't think of any things that should break by this patch (or I would've tested them :)), nor can I think of any XSS flaws that should be introduced by this. I'm not confident enough to RTBC it though. :)

(Also, the tests probably need some touching up, so please do that. It would also be good with some more strings to test. E.g. with some HTML and stuff.)

Freso’s picture

StatusFileSize
new2.59 KB

D'oh. And the patch. -.-

catch’s picture

There's a bunch of XSS examples on this issue which never made it into the committed patch if that helps with test fodder - http://drupal.org/node/354812

Status: Needs review » Needs work

The last submitted patch failed testing.

lyricnz’s picture

StatusFileSize
new40.24 KB

Issue still exists with current D7 head (see screenshot)

lyricnz’s picture

Status: Needs review » Needs work

Implementation aside, a more fundamental question is: what is the correct post-filter text for each of these cases?

  1. Who&#039;s Online
  2. Who&amp;#039;s Online
  3. Who&amp;amp;#039;s Online

Right now, you get what was in the previous screenshot. It feels like that HTML is safe as-is, so shouldn't be modified by filter_xss(), and so should appear on the page like:

  1. Who's Online
  2. Who&#039;s Online
  3. Who&amp;#039;s Online

(ie: no changes from filtering) but.... doesn't

lyricnz’s picture

Status: Needs work » Needs review
StatusFileSize
new1.82 KB

Here's a patch that implements the actual change used in #4 and #12 above, along with a patch to the recently-committed filter module tests : #276597: TestingParty08: filter.module.

With this, the "Core Filters" test runs: 165 passes, 0 fails, and 0 exceptions

The last submitted patch failed testing.

lyricnz’s picture

Status: Needs work » Needs review

Resubmtting, "test bot issues"

chx’s picture

Status: Needs review » Reviewed & tested by the community

I do not see anything immediately wrong in here... the code looks ok, the tests pass.

dries’s picture

Status: Reviewed & tested by the community » Fixed

After looking at the function for a while, I can't see anything wrong with this either. Committed it.

heine’s picture

Version: 7.x-dev » 6.x-dev
Status: Fixed » Patch (to be ported)

Patch from #4 should apply to Drupal 6 with a 15 line offset.

heine’s picture

Status: Patch (to be ported) » Needs review

Sorry, needs review

lyricnz’s picture

Status: Needs review » Reviewed & tested by the community
StatusFileSize
new977 bytes

Rerolled patch from #4 for D6 CVS (without the whitespace change). RTBC because it's the same as already committed to D7.

gábor hojtsy’s picture

Version: 6.x-dev » 5.x-dev
Status: Reviewed & tested by the community » Patch (to be ported)

Committed to Drupal 6 too, thanks. Bug applies to Drupal 5 too as said above.

marcingy’s picture

Status: Patch (to be ported) » Closed (won't fix)

Marking as won't fix as d5 is end of life.