Skip to content

escape backslashes in single-quoted Ajax script strings - #1668

Open
fr-manvi wants to merge 2 commits into
apache:masterfrom
fr-manvi:editable-label-backslash-escape
Open

fr-manvi wants to merge 2 commits into
apache:masterfrom
fr-manvi:editable-label-backslash-escape

Conversation

@fr-manvi

Copy link
Copy Markdown
Contributor

AjaxEditableLabel.onError writes a validation error message into the single-quoted script string window.status='...' with JavaScriptUtils.escapeQuotes, which escapes ' and " but not the backslash:

  • a message that starts with a backslash and a quote (e.g. \';alert(1)//) closes that string and runs the rest, and validation messages echo the submitted value through ${input}, so those characters are attacker controlled: an XSS on an edit-in-place field
  • AjaxListPanel.append builds the same single-quoted Wicket.DOM.add(..., '...') string with the same helper
  • both now call escapeQuotesAndBackslash, which doubles the backslash too and is what Link, ExternalLink and PopupSettings already use for single-quoted script strings

Added AjaxEditableLabelErrorMessageEscapeTest: it drives the label into edit mode, submits a value that fails validation with a message beginning \', and asserts the generated window.status script keeps the quote inside the string. It fails before the change and passes after.

AjaxEditableLabel.onError placed a validation error message into the
single-quoted JavaScript string window.status='...' through
JavaScriptUtils.escapeQuotes, which escapes ' and " but leaves the
backslash untouched. A message that carries a backslash in front of a
quote therefore closes the string and runs whatever follows. Validation
messages routinely echo the value the user submitted through the
${input} variable, so those characters are attacker controlled, which
makes this a cross-site scripting hole.

AjaxListPanel.append builds the same kind of single-quoted script string
(Wicket.DOM.add(..., '...')) with the same backslash-unsafe helper.

Both now use escapeQuotesAndBackslash, the helper that also doubles the
backslash and is already used for the single-quoted script strings in
Link, ExternalLink and PopupSettings. Messages and tags that contain no
backslash render exactly as before, so an application sees no change
unless its text relied on the backslash passing through unescaped.
@reiern70

Copy link
Copy Markdown
Contributor
  • a message that starts with a backslash and a quote (e.g. \';alert(1)//) closes that string and runs the rest, and validation messages echo the submitted value through ${input}, so those characters are attacker controlled: an XSS on an edit-in-place field

Can you please add a test based on this example?

Adds a case where the submitted value \';alert(1)// reaches the
validation message through the ${input} variable, the way an
application's own message bundle would echo it. Without
escapeQuotesAndBackslash the generated window.status='...' string is
closed by the input; with it the quote stays inside the string.
@fr-manvi

Copy link
Copy Markdown
Contributor Author

Added onErrorEscapesUserInputEchoedThroughInputVariable. It submits \';alert(1)// as the editor value. A validator error resolves through a message key whose text is Invalid value: ${input}, so the payload reaches window.status the same way it would from an application's own bundle. setMessage skips variable substitution, which is why the original case had to hard-code the message.

With plain escapeQuotes the response contains Invalid value: \\';alert(1)//. JS reads the \\ as an escaped backslash, so the quote after it ends the string and alert(1) runs. With escapeQuotesAndBackslash you get \\\' and the quote stays inside the literal. I checked that the new test fails against the old helper and passes with the fix.

@pedrosans

Copy link
Copy Markdown
Contributor

Hi @fr-manvi, please report issues like this to security@apache.org

@codecov-commenter

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 61.99%. Comparing base (5cbd566) to head (d403338).
⚠️ Report is 2 commits behind head on master.

Additional details and impacted files
@@             Coverage Diff              @@
##             master    #1668      +/-   ##
============================================
+ Coverage     61.96%   61.99%   +0.03%     
- Complexity    11285    11291       +6     
============================================
  Files          1250     1250              
  Lines         48437    48437              
  Branches       6796     6796              
============================================
+ Hits          30014    30030      +16     
+ Misses        15729    15711      -18     
- Partials       2694     2696       +2     
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants