Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -748,4 +748,9 @@ class Binding extends TBinding {
BindingPath getBindingPath() { result.getBinding() = this }

BindingTarget getBindingTarget() { result.getBinding() = this }

/**
* Gets the `BindElementMethodCallNode` for this binding, if it is a context binding via `bindElement`.
*/
BindElementMethodCallNode getBindElementCall() { this = TLateJavaScriptContextBinding(result, _) }
}
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,12 @@ class DefaultODataServiceModel extends UI5ExternalModel {

override string getName() { result = "" }

Binding asBinding() { result.getBindingTarget().asDataFlowNode() = this }
/**
* Gets bindings associated with this default OData model source.
* Since `DefaultODataServiceModel` represents a `bindElement` call,
* we match context bindings whose `bindElement` call is this node.
*/
Binding asBinding() { result.getBindElementCall() = this }
}

/** Model which gains content from an SAP OData service. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,10 +133,13 @@ abstract class UI5BindingPath extends BindingPath {
not exists(this.getModelName())
)
or
/* 5. There is no call to `setModel` at all and a default model exists that is related to the binding path this refers to */
/* 5. There is no call to `setModel` in the same webapp and a default model exists that is related to the binding path this refers to */
exists(DefaultODataServiceModel defaultModel |
result = defaultModel and
not exists(MethodCallNode viewSetModelCall | viewSetModelCall.getMethodName() = "setModel") and
not exists(MethodCallNode viewSetModelCall |
viewSetModelCall.getMethodName() = "setModel" and
inSameWebApp(this.getLocation().getFile(), viewSetModelCall.getFile())
) and
/*
* this binding path can occur in a fragment that is the receiver object for the bindElement model approximation
* i.e. checks that the default model is relevant
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
nodes
| webapp/controller/App.controller.js:21:17:21:53 | oFragme ... es(1)") |
| webapp/fragments/DataDisplay.fragment.xml:7:9:7:42 | content={message} |
edges
| webapp/controller/App.controller.js:21:17:21:53 | oFragme ... es(1)") | webapp/fragments/DataDisplay.fragment.xml:7:9:7:42 | content={message} |
| webapp/fragments/DataDisplay.fragment.xml:7:9:7:42 | content={message} | webapp/controller/App.controller.js:21:17:21:53 | oFragme ... es(1)") |
#select
| webapp/fragments/DataDisplay.fragment.xml:7:9:7:42 | content={message} | webapp/controller/App.controller.js:21:17:21:53 | oFragme ... es(1)") | webapp/fragments/DataDisplay.fragment.xml:7:9:7:42 | content={message} | XSS vulnerability due to $@. | webapp/controller/App.controller.js:21:17:21:53 | oFragme ... es(1)") | user-provided value |
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
UI5Xss/UI5Xss.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "xss-fragment-odata-default-model",
"version": "1.0.0",
"description": "Test case for XSS vulnerability via default OData model in fragment with bindElement"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
specVersion: "3.1"
type: application
metadata:
name: xss-fragment-odata-default-model
framework:
name: SAPUI5
version: "1.120.0"
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
sap.ui.define([
"sap/ui/core/UIComponent"
], function (UIComponent) {
"use strict";
return UIComponent.extend("xss.fragment.odata.defaultmodel.Component", {
metadata: {
manifest: "json"
},
init: function () {
UIComponent.prototype.init.apply(this, arguments);
}
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
sap.ui.define([
"sap/ui/core/mvc/Controller",
"sap/ui/core/Fragment"
], function (Controller, Fragment) {
"use strict";

return Controller.extend("xss.fragment.odata.defaultmodel.controller.App", {
onInit: function () {
// XSS vulnerability pattern:
// 1. OData model is configured as default model in manifest.json
// 2. Fragment is loaded dynamically
// 3. Fragment is bound to OData entity via bindElement
// 4. Fragment contains HTML control that renders OData content

Fragment.load({
id: this.getView().getId(),
name: "xss.fragment.odata.defaultmodel.fragments.DataDisplay",
controller: this
}).then(function (oFragment) {
// Bind fragment to an OData entity - vulnerability is in the backend data
oFragment.bindElement("/Messages(1)");

// Add the fragment to the page content
this.byId("page").addContent(oFragment);
}.bind(this));
}
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<core:FragmentDefinition
xmlns="sap.m"
xmlns:core="sap.ui.core">
<VBox class="sapUiSmallMargin">
<Label text="Message from OData:" />
<!-- XSS vulnerability: HTML content bound to OData property containing unsanitized data -->
<core:HTML content="{message}" />
Comment thread Dismissed
</VBox>
</core:FragmentDefinition>
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>XSS Fragment OData Default Model Test</title>
<script
id="sap-ui-bootstrap"
src="https://openui5.hana.ondemand.com/resources/sap-ui-core.js"
data-sap-ui-theme="sap_fiori_3"
data-sap-ui-resourceroots='{
"xss.fragment.odata.defaultmodel": "./"
}'
data-sap-ui-oninit="module:xss/fragment/odata/defaultmodel/index"
data-sap-ui-async="true">
</script>
</head>
<body class="sapUiBody" id="content">
</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
sap.ui.define([
"sap/ui/core/ComponentContainer"
], function (ComponentContainer) {
"use strict";
new ComponentContainer({
name: "xss.fragment.odata.defaultmodel",
settings: {
id: "xss.fragment.odata.defaultmodel"
},
async: true
}).placeAt("content");
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{
"_version": "1.58.0",
"sap.app": {
"id": "xss.fragment.odata.defaultmodel",
"type": "application",
"title": "XSS Fragment OData Default Model Test",
"applicationVersion": {
"version": "1.0.0"
},
"dataSources": {
"mainService": {
"uri": "/odata/v4/catalog/",
"type": "OData",
"settings": {
"odataVersion": "4.0"
}
}
}
},
"sap.ui": {
"technology": "UI5",
"deviceTypes": {
"desktop": true,
"tablet": true,
"phone": true
}
},
"sap.ui5": {
"rootView": {
"viewName": "xss.fragment.odata.defaultmodel.view.App",
"type": "XML",
"id": "app"
},
"dependencies": {
"minUI5Version": "1.60",
"libs": {
"sap.m": {}
}
},
"models": {
"": {
"dataSource": "mainService",
"preload": true,
"settings": {}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<mvc:View
controllerName="xss.fragment.odata.defaultmodel.controller.App"
xmlns:mvc="sap.ui.core.mvc"
xmlns="sap.m"
xmlns:core="sap.ui.core"
displayBlock="true">
<App id="app">
<Page id="page" title="XSS Fragment OData Default Model Test">
<content>
<!-- Fragment will be loaded here dynamically -->
</content>
</Page>
</App>
</mvc:View>
Loading