mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
fix(core): escape overlapping comment delimiters in escapeCommentText
`COMMENT_DISALLOWED` is matched globally, so overlapping delimiter sequences are skipped: `<!-->` only escapes the leading `<!--` and leaves a live `-->` that can close a programmatically created comment node early. Drop the `^` anchors so a standalone `>`/`->` is escaped wherever it appears, which neutralizes the trailing delimiter left behind by an earlier match.
This commit is contained in:
committed by
Jessica Janiuk
parent
ea18ab24dd
commit
ea1a3ed64c
@@ -11,7 +11,7 @@
|
||||
*
|
||||
* see: https://html.spec.whatwg.org/multipage/syntax.html#comments
|
||||
*/
|
||||
const COMMENT_DISALLOWED = /^>|^->|<!--|-->|--!>|<!-$/g;
|
||||
const COMMENT_DISALLOWED = />|->|<!--|-->|--!>|<!-$/g;
|
||||
/**
|
||||
* Delimiter in the disallowed strings which needs to be wrapped with zero with character.
|
||||
*/
|
||||
|
||||
@@ -40,10 +40,35 @@ describe('comment node text escaping', () => {
|
||||
expect(escapeCommentText('--!>')).toEqual('--!\u200b>\u200b');
|
||||
expect(escapeCommentText('<!-')).toEqual('\u200b<\u200b!-');
|
||||
|
||||
// Things which are OK
|
||||
expect(escapeCommentText('.>')).toEqual('.>');
|
||||
expect(escapeCommentText('.->')).toEqual('.->');
|
||||
// A standalone `>` or `->` is escaped regardless of position so that a delimiter which
|
||||
// overlaps an earlier match (e.g. the `-->` in `<!-->`) can't survive a single pass.
|
||||
expect(escapeCommentText('.>')).toEqual('.\u200b>\u200b');
|
||||
expect(escapeCommentText('.->')).toEqual('.-\u200b>\u200b');
|
||||
expect(escapeCommentText('<!-.')).toEqual('<!-.');
|
||||
});
|
||||
|
||||
it('should escape delimiters that overlap an earlier match', () => {
|
||||
// `<!-->` contains both `<!--` and a `-->` that shares its `--`; both must be neutralized.
|
||||
expect(escapeCommentText('<!-->')).toEqual('\u200b<\u200b!--\u200b>\u200b');
|
||||
expect(escapeCommentText('<!--!>')).toEqual('\u200b<\u200b!--!\u200b>\u200b');
|
||||
expect(escapeCommentText('a<!-->b')).toEqual('a\u200b<\u200b!--\u200b>\u200bb');
|
||||
});
|
||||
|
||||
it('should keep an injected payload inside a programmatically created comment', () => {
|
||||
// `<!-->` closes a comment immediately (the `-->` overlaps the `<!--`), so without escaping
|
||||
// the trailing markup leaks out of the comment and runs. Round-trip a comment node through
|
||||
// serialization + re-parsing to confirm the payload stays inert comment text.
|
||||
const host = document.createElement('div');
|
||||
host.appendChild(
|
||||
document.createComment(escapeCommentText('<!--><img src=x onerror="alert(1)">')),
|
||||
);
|
||||
|
||||
const reparsed = document.createElement('div');
|
||||
reparsed.innerHTML = host.innerHTML;
|
||||
|
||||
expect(reparsed.childNodes.length).toBe(1);
|
||||
expect(reparsed.firstChild!.nodeType).toBe(Node.COMMENT_NODE);
|
||||
expect(reparsed.getElementsByTagName('img').length).toBe(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user