diff --git a/src/autolinker.ts b/src/autolinker.ts index 5c7a3c1f..48a63d67 100644 --- a/src/autolinker.ts +++ b/src/autolinker.ts @@ -913,6 +913,8 @@ export default class Autolinker { textOrHtml = textOrHtml.replace(/</g, '<').replace(/>/g, '>'); } + textOrHtml = this.stripUnsafeCharacters(textOrHtml); + let matches = this.parse(textOrHtml), newHtml: string[] = [], lastIndex = 0; @@ -1020,6 +1022,16 @@ export default class Autolinker { return tagBuilder; } + + /** + * Strips characters considered as unsafe + * SNYK-AUTOLINKER-2438289 + * @param text + * @private + */ + private stripUnsafeCharacters(text: string) { + return text.replace(/[\u202a-\u202e, \u200e-\u200f]/g, ''); + } } export interface AutolinkerConfig { diff --git a/tests/autolinker-url.spec.ts b/tests/autolinker-url.spec.ts index 440b5481..ffea02b8 100644 --- a/tests/autolinker-url.spec.ts +++ b/tests/autolinker-url.spec.ts @@ -1265,4 +1265,30 @@ describe('Autolinker Url Matching -', () => { ); }); }); + + describe('unicode exploits', () => { + it('should strip out character direction override unicodes', () => { + expect(autolinker.link('foo.combar.com')).toBe( + '<a href="http://foo.combar.com">foo.combar.com</a>' + ); + expect(autolinker.link('foo.com\u202Ebar.com')).toBe( + '<a href="http://foo.combar.com">foo.combar.com</a>' + ); + expect(autolinker.link('foo.com\u202abar.com')).toBe( + '<a href="http://foo.combar.com">foo.combar.com</a>' + ); + expect(autolinker.link('foo.com\u202bbar.com')).toBe( + '<a href="http://foo.combar.com">foo.combar.com</a>' + ); + expect(autolinker.link('foo.com\u202cbar.com')).toBe( + '<a href="http://foo.combar.com">foo.combar.com</a>' + ); + expect(autolinker.link('foo.com\u202dbar.com')).toBe( + '<a href="http://foo.combar.com">foo.combar.com</a>' + ); + expect(autolinker.link('foo.com\u202ebar.com')).toBe( + '<a href="http://foo.combar.com">foo.combar.com</a>' + ); + }); + }); });