Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
3 changes: 2 additions & 1 deletion tez-ui/src/main/webapp/app/models/vertex.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,8 @@ export default AMTimelineModel.extend({
description: Ember.computed("dag.vertices", "name", function () {
try {
let vertex = this.get("dag.vertices").findBy("vertexName", this.get("name"));
return JSON.parse(vertex.userPayloadAsText).desc;
let desc = JSON.parse(vertex.userPayloadAsText).desc;
return desc ? Ember.Handlebars.Utils.escapeExpression(desc) : undefined;
}catch(e) {}
}),

Expand Down
3 changes: 3 additions & 0 deletions tez-ui/src/main/webapp/app/serializers/timeline.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ import LoaderSerializer from './loader';
function getDiagnostics(source) {
var diagnostics = Ember.get(source, 'otherInfo.diagnostics') || "";

// Escape HTML entities before adding formatting markup
diagnostics = Ember.Handlebars.Utils.escapeExpression(diagnostics);

diagnostics = diagnostics.replace(/\t/g, "  ");
diagnostics = diagnostics.replace(/\[/g, "<div>&#187; ");
diagnostics = diagnostics.replace(/\]/g, "</div>");
Expand Down
51 changes: 51 additions & 0 deletions tez-ui/src/main/webapp/tests/unit/models/vertex-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,3 +96,54 @@ test('description test', function(assert) {
assert.equal(model.get("description"), testDesc);
});
});

test('description escapes HTML to prevent XSS', function(assert) {
let testVertexName = "TestVertexName",
model = this.subject({
name: testVertexName
});

Ember.run(function () {
// Script injection must be escaped
model.set("dag", Ember.Object.create({
vertices: [{
vertexName: testVertexName,
userPayloadAsText: JSON.stringify({
desc: "<script>alert(1)</script>"
})
}]
}));
assert.equal(model.get("description"), "&lt;script&gt;alert(1)&lt;/script&gt;");

// IMG onerror injection must be escaped
model.set("dag", Ember.Object.create({
vertices: [{
vertexName: testVertexName,
userPayloadAsText: JSON.stringify({
desc: "<img src=x onerror=alert(1)>"
})
}]
}));
assert.equal(model.get("description"), "&lt;img src=x onerror=alert(1)&gt;");

// Ampersands are escaped
model.set("dag", Ember.Object.create({
vertices: [{
vertexName: testVertexName,
userPayloadAsText: JSON.stringify({
desc: "a & b"
})
}]
}));
assert.equal(model.get("description"), "a &amp; b");

// Null/undefined desc returns undefined
model.set("dag", Ember.Object.create({
vertices: [{
vertexName: testVertexName,
userPayloadAsText: JSON.stringify({})
}]
}));
assert.equal(model.get("description"), undefined);
});
});
39 changes: 39 additions & 0 deletions tez-ui/src/main/webapp/tests/unit/serializers/timeline-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,42 @@ test('extractArrayPayload test', function(assert) {

assert.equal(serializer.extractArrayPayload(testPayload), testPayload.entities);
});

test('getDiagnostics escapes HTML', function(assert) {
let serializer = this.subject(),
mapper = serializer.maps.diagnostics;

// Empty/missing diagnostics
assert.equal(mapper({}), "");
assert.equal(mapper({otherInfo: {}}), "");

// Script injection must be escaped
assert.equal(
mapper({otherInfo: {diagnostics: "<script>alert(1)</script>"}}),
"&lt;script&gt;alert(1)&lt;/script&gt;"
);

// IMG onerror injection must be escaped
assert.equal(
mapper({otherInfo: {diagnostics: "<img src=x onerror=alert(1)>"}}),
"&lt;img src=x onerror=alert(1)&gt;"
);

// Tab formatting still works after escaping
assert.equal(
mapper({otherInfo: {diagnostics: "\tindented"}}),
"&emsp;&emsp;indented"
);

// Bracket formatting still works after escaping
assert.equal(
mapper({otherInfo: {diagnostics: "[section]"}}),
"<div>&#187; section</div>"
);

// Ampersands in diagnostics are escaped
assert.equal(
mapper({otherInfo: {diagnostics: "a & b"}}),
"a &amp; b"
);
});
Loading