-
Notifications
You must be signed in to change notification settings - Fork 3
Ensure sanitizeContent attribute is respected #257
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control sanitized/UI5Xss.qlref
Fixed
Show fixed
Hide fixed
...script/frameworks/ui5/test/queries/UI5Xss/xss-html-control-df sanitized-disable/UI5Xss.qlref
Fixed
Show fixed
Hide fixed
javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control-df sanitized/UI5Xss.qlref
Fixed
Show fixed
Hide fixed
...pt/frameworks/ui5/test/queries/UI5Xss/xss-html-control-df sanitized/webapp/view/app.view.xml
Fixed
Show fixed
Hide fixed
javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-view sanitized/UI5Xss.qlref
Fixed
Show fixed
Hide fixed
javascript/frameworks/ui5/test/queries/UI5Xss/xss-js-view sanitized/UI5Xss.qlref
Fixed
Show fixed
Hide fixed
javascript/frameworks/ui5/test/queries/UI5Xss/xss-json-view sanitized/UI5Xss.qlref
Fixed
Show fixed
Hide fixed
javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-view sanitized/webapp/view/app.view.html
Fixed
Show fixed
Hide fixed
javascript/frameworks/ui5/test/queries/UI5Xss/xss-js-view sanitized/webapp/view/app.view.js
Fixed
Show fixed
Hide fixed
javascript/frameworks/ui5/test/queries/UI5Xss/xss-json-view sanitized/webapp/view/app.view.json
Fixed
Show fixed
Hide fixed
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
javascript/frameworks/ui5/lib/advanced_security/javascript/frameworks/ui5/UI5Control.qll
Fixed
Show fixed
Hide fixed
javascript/frameworks/ui5/lib/advanced_security/javascript/frameworks/ui5/UI5Control.qll
Fixed
Show fixed
Hide fixed
javascript/frameworks/ui5/lib/advanced_security/javascript/frameworks/ui5/UI5Control.qll
Fixed
Show fixed
Hide fixed
javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control/webapp/view/app.view.xml
Dismissed
Show dismissed
Hide dismissed
javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control/webapp/view/app.view.xml
Dismissed
Show dismissed
Hide dismissed
javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control/webapp/view/app.view.xml
Dismissed
Show dismissed
Hide dismissed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR enhances the CodeQL analysis for UI5 applications by ensuring the sanitizeContent attribute is properly respected when detecting HTML injection vulnerabilities. The changes extract control-related logic into a dedicated module and improve the detection of sanitized vs. unsanitized HTML controls across all view types (XML, JSON, and JavaScript).
Key changes:
- Extracted
UI5ControlandUI5ControlPropertyclasses fromUI5View.qllinto a newUI5Control.qllfile - Introduced
isSanitizedControl()predicate to identify controls with sanitization enabled/disabled both declaratively and programmatically - Updated HTML injection sink detection to exclude sanitized controls from vulnerability reports
- Enhanced test coverage with scenarios for declarative and programmatic sanitization control
- Upgraded CodeQL GitHub Actions from v3 to v4
Reviewed changes
Copilot reviewed 15 out of 16 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| javascript/frameworks/ui5/lib/advanced_security/javascript/frameworks/ui5/UI5Control.qll | New file containing extracted UI5Control and UI5ControlProperty classes with isSanitizedControl() predicate for sanitization detection |
| javascript/frameworks/ui5/lib/advanced_security/javascript/frameworks/ui5/UI5View.qll | Removed UI5Control and UI5ControlProperty class definitions (moved to UI5Control.qll) and removed XML-specific sanitization checks |
| javascript/frameworks/ui5/lib/advanced_security/javascript/frameworks/ui5/UI5.qll | Added import for new UI5Control module |
| javascript/frameworks/ui5/lib/advanced_security/javascript/frameworks/ui5/dataflow/DataFlow.qll | Added sanitization check to filter sanitized controls from HTML injection sinks |
| javascript/frameworks/ui5/test/models/sink/UI5ViewSinkTest.ql | Updated query to exclude sanitized controls from sink detection |
| javascript/frameworks/ui5/test/models/sink/sink1.xml | Added test case for sanitized HTML control |
| javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control/webapp/view/app.view.xml | Added comprehensive test cases for declarative and programmatic sanitization scenarios |
| javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control/webapp/controller/app.controller.js | Added controller logic to test programmatic sanitization control via setProperty() |
| javascript/frameworks/ui5/test/queries/UI5Xss/xss-html-control/UI5Xss.expected | Updated expected results to reflect proper sanitization detection |
| javascript/frameworks/ui5/test/queries/UI5Xss/xss-json-view/webapp/view/app.view.json | Added test case for sanitized HTML control in JSON view |
| javascript/frameworks/ui5/test/queries/UI5Xss/xss-json-view/UI5Xss.expected | Updated expected results for JSON view sanitization |
| javascript/frameworks/ui5/test/queries/UI5Xss/xss-js-view/webapp/view/app.view.js | Added test case for sanitized HTML control in JS view |
| javascript/frameworks/ui5/test/queries/UI5Xss/xss-js-view/UI5Xss.expected | Updated expected results for JS view sanitization |
| javascript/frameworks/ui5/test/README.md | Updated documentation to describe sanitization testing scenarios |
| .github/workflows/code_scanning.yml | Upgraded CodeQL Actions from v3 to v4 |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
javascript/frameworks/ui5/lib/advanced_security/javascript/frameworks/ui5/UI5Control.qll
Outdated
Show resolved
Hide resolved
javascript/frameworks/ui5/lib/advanced_security/javascript/frameworks/ui5/dataflow/DataFlow.qll
Outdated
Show resolved
Hide resolved
javascript/frameworks/ui5/lib/advanced_security/javascript/frameworks/ui5/UI5Control.qll
Outdated
Show resolved
Hide resolved
javascript/frameworks/ui5/lib/advanced_security/javascript/frameworks/ui5/UI5Control.qll
Outdated
Show resolved
Hide resolved
javascript/frameworks/ui5/lib/advanced_security/javascript/frameworks/ui5/UI5Control.qll
Outdated
Show resolved
Hide resolved
javascript/frameworks/ui5/lib/advanced_security/javascript/frameworks/ui5/UI5Control.qll
Outdated
Show resolved
Hide resolved
...ript/frameworks/ui5/test/queries/UI5Xss/xss-html-control/webapp/controller/app.controller.js
Show resolved
Hide resolved
javascript/frameworks/ui5/lib/advanced_security/javascript/frameworks/ui5/UI5View.qll
Outdated
Show resolved
Hide resolved
jeongsoolee09
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Second round!
…meworks/ui5/UI5View.qll Co-authored-by: Jeongsoo Lee <[email protected]>
|
The property names for
So, I suggest these:
|
Good catch! I have fixed the implementation and added sink tests for both the controls (with their specific property names)
I think that the presence of the sanitizing property should be modelled in the Control not in the Query.
The link between the sink and the primarysink is only established at the very end in |
| /* 2. `sanitizeContent` attribute is set programmatically using setProperty(). */ | ||
| exists(CallNode node | node = this.getAReference().getAMemberCall("setProperty") | | ||
| node.getArgument(0).getStringValue() = propName and | ||
| not node.getArgument(1).mayHaveBooleanValue(val.booleanNot()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can straighten out the double negation.
| not node.getArgument(1).mayHaveBooleanValue(val.booleanNot()) | |
| node.getArgument(1).mayHaveBooleanValue(val) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is not equivalent!
There are cases where we don't know what the value may be, so not mayHaveVal(true) would be equivalent to mustHaveVal(false) but that doesn't exist
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still believe there's a bug in this predicate. If you quick-evaluate the body of this test predicate:
private predicate test(int startline) {
this.isSanitizePropertySetTo("sanitizeContent", true) and
this.hasLocationInfo(_, _, startline, _, _) // for easy inspection
}It finds the HTML control at line 50 (id="htmUnsanitized") with this API call attached:
// disable sanitization programmatically
this.getView().byId("htmUnsanitized").setProperty("sanitizeContent", false);...when this.isSanitizePropertySetTo("sanitizeContent", true) shouldn't hold here.
| bindingset[propName, val] | ||
| private predicate isSanitizePropertySetTo(string propName, boolean val) { | ||
| /* 1. `sanitizeContent` attribute is set declaratively. */ | ||
| this.getProperty(propName).toString() = val.toString() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very minor, but I guess getValue conveys the meaning better (and we should avoid using .toString() on non-primitive QL types anyways).
| this.getProperty(propName).toString() = val.toString() | |
| this.getProperty(propName).getValue() = val.toString() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree in principle, but getValue() does not return what you'd expect for an XmlElement
|
|
||
| // enable sanitization programmatically | ||
| this.getView().byId("htmlJsSanitized2").setProperty("sanitizeContent", true); | ||
|
|
||
| // setting the property directly is not sufficient | ||
| this.getView().byId("htmlJsSanitized3").sanitizeContent = true; | ||
|
|
||
| // disable sanitization programmatically | ||
| this.getView().byId("htmUnsanitized").setProperty("sanitizeContent", false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Two things:
- Since we have "false sanitization" here (
.sanitizeContent = true), can we say in the comment if it's really sanitized usingSAFEandUNSAFElike we're doing for model tests, like/* SAFE: {reason} */and/* UNSAFE: {reason} */? HTML.setSanitizeContentandRichTextEditor.setSanitizeValueare missing. Please add those in the test codes (query + model) and support them in the QL code as well.- Minor, I noticed the missing
linhtmUnsanitized. Can you fix the typo?
jeongsoolee09
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Left another round.
| } | ||
|
|
||
| bindingset[propName, val] | ||
| private predicate isSanitizePropertySetTo(string propName, boolean val) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I found it helps to draw a table like this (this is also what I'm using when reviewing this PR):
| sanitizeContent=true | sanitizeContent=false | sanitizeContent= N/A | |
|---|---|---|---|
| setSanitizeContent(true) | SAFE | SAFE | SAFE |
| setSanitizeContent(false) | UNSAFE | UNSAFE | UNSAFE |
| setSanitizeContent N/A | SAFE | UNSAFE | UNSAFE |
For now, I find it hard to understand what table the isSanitizePropertySetTo + isHTMLSanitized combination infers, mainly because some of the rows are filtered on isHTMLSanitized and in isHTMLSanitized: isSanitizePropertySetTo negates rows, and this result is negated once again in isHTMLSanitized.
I strongly recommend encoding the above table only in one predicate and make the other predicate simply use its result directly.
Then, what we need is to just encode this table (again, all in a single predicate!), but in a principled way: we can exploit the fact that setProperty/setSanitizeContent take precedence over setting the attribute of UI5Control. So, you can encode the rows in the above table in a broad stroke by filtering first with what value is set through setProperty/setSanitizeContent, and take out the remaining edge cases.
Key changes:
UI5 Control and Sanitization Logic
UI5Control::isHTMLSanitizedto identify controls where sanitization is enabled or disabled via thesanitizeContent/sanitizeValueproperty.UI5 Control and Sanitization Logic
models/sinkxss-html-controlxss-js-viewxss-json-viewREADME)CodeQL Workflow Updates