1

Something strange is occurring and I'm stumped.

I have a link that looks basically like this:

<a href="javascript:uploadVariantPicture('size:&#039;test2&#039');">Link</a>

As you can see, I'm calling function uploadVariantPicture with parameter "size:'test2&#039".

However, when I actually click the link, JavaScript complains that the two encoded single quotes aren't being escaped. I'm getting the following error:

SyntaxError: Unexpected identifier 'test2'. Expected ')' to end an argument list.

If I decode the two encoded single quotes and escape them using a backslash, then the function call succeeds. But the problem is I need it encoded. I cannot leave it unencoded and escape the quotes. This won't work for my situation.

Any help is greatly appreciated. I'm super confused.

Tony Friz
  • 883
  • 1
  • 10
  • 27

2 Answers2

2

HTML character entities and escapes are replaced by the HTML parser when parsing source. For quotation marks, it allows inclusion of the same kind of quotation mark in an HTML attribute that is being used to quote the attribute value in source.

E.G.

 <element attribute="&quot;">
 <element attribute='&#039;'>

in source would produce attribute values of " (double quote) and ' (single quote) respectively, despite being the delimters used to quote the attribute value in HTML source.

Hence

 <a href="javascript:uploadVariantPicture('size:&#039;test2&#039');">Link</a>

will produce an href attribute value of

  javascript:uploadVariantPicture('size:'test'');

after removal of the outer double quotes by the HTML parser.

Options could include escaping double quotes (HTML &quot;) inside the href value appropriately (it depends on the syntax accepted by uploadVariantPicture), including backslash escapes before the single quotes as mentioned in the post, or not using the javascript: pseudo protocol at all, in favor of adding an event listener in JavaScript.

Not using javascript: pseudo protocol is highly recommended - basically it's a hold over from HTML3.

traktor
  • 17,588
  • 4
  • 32
  • 53
  • Is there anything inherently wrong with using javascript: ? It's very convenient for my situation. – Tony Friz Jan 10 '21 at 22:00
  • It fell out of favor due to the security risk of being able to execute arbitrary javascript code and the fact that `javascript:` is not actually a protocol. At this point in time I would think it more regarded as obsolete usage given more modern methods to do the same thing, developed so that the need to use `javascript:` would go away. – traktor Jan 10 '21 at 22:11
1

Consider attaching an event handler properly using JavaScript instead so you don't have to worry about escaping issues, and so that you don't have to rely on the pollution of the global object for the script to work:

const uploadVariantPicture = (arg) => console.log(arg);

document.querySelector('a').addEventListener('click', () => {
  uploadVariantPicture("size:'test2'");
});
<a>Link</a>

I can't think of any situations in which an inline handler would be preferable to addEventListener, unless you were deliberately trying to exploit an XSS vulnerability.

CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
  • Would this still work if I had encoded double quotes in the call? – Tony Friz Jan 10 '21 at 21:20
  • 1
    Sure, just do `uploadVariantPicture('size:"test2"')`, or use backticks – CertainPerformance Jan 10 '21 at 21:20
  • No, I need it to be htmlspecialchars encoded. No literal quotes so I cannot back tick. – Tony Friz Jan 10 '21 at 21:32
  • What'd be wrong with backticks? ``uploadVariantPicture(`size:"test2"`)`` would be syntactically valid. If you need `uploadVariantPicture` to use an encoded string, then I'd highly recommend having `uploadVariantPicture` perform that transformation instead of having each caller do it separately. – CertainPerformance Jan 10 '21 at 21:39
  • @TonyFriz You need to take the valid JS code (whichever you choose), and then *(only) when putting it into a HTML `href` attribute* you must entity-escape the text. This means that (all!) `"` characters become `"` and (all) `'` characters become `'`. But seriously, as this answer recommends, just don't put JS code in HTML attributes in the first place. – Bergi Jan 10 '21 at 21:40
  • OK - I made it work using back ticks. Thanks for the help, you are both quite knowledgeable. – Tony Friz Jan 10 '21 at 21:56