diff --git a/extensions/amp-a4a/0.1/head-validation.js b/extensions/amp-a4a/0.1/head-validation.js index 3f0e86304602..942301845bfd 100644 --- a/extensions/amp-a4a/0.1/head-validation.js +++ b/extensions/amp-a4a/0.1/head-validation.js @@ -17,9 +17,13 @@ import {getMode} from '../../../src/mode'; */ export let ValidatedHeadDef; -// From validator/validator-main.protoascii +// From validator/validator-main.protoascii. The validator matches this against +// the whole attribute value (RE2::FullMatch), so anchor it here too: RegExp.test +// is a substring match, which would accept any href that merely contains an +// allowed provider (e.g. https://evil.example/#https://fast.fonts.net/). const ALLOWED_FONT_REGEX = new RegExp( - 'https://cdn\\.materialdesignicons\\.com/' + + '^(?:' + + 'https://cdn\\.materialdesignicons\\.com/' + '([0-9]+\\.?)+/css/materialdesignicons\\.min\\.css|' + 'https://cloud\\.typography\\.com/' + '[0-9]*/[0-9]*/css/fonts\\.css|' + @@ -32,7 +36,8 @@ const ALLOWED_FONT_REGEX = new RegExp( 'https://(use|pro)\\.fontawesome\\.com/releases/v([0-9]+\\.?)+' + '/css/[0-9a-zA-Z-]+\\.css|' + 'https://(use|pro)\\.fontawesome\\.com/[0-9a-zA-Z-]+\\.css|' + - 'https://use\\.typekit\\.net/[\\w\\p{L}\\p{N}_]+\\.css' + 'https://use\\.typekit\\.net/[\\w\\p{L}\\p{N}_]+\\.css' + + ')$' ); // If editing please also change: diff --git a/extensions/amp-a4a/0.1/test/test-head-validation.js b/extensions/amp-a4a/0.1/test/test-head-validation.js index bd7ca9c9642d..395c4d4a090c 100644 --- a/extensions/amp-a4a/0.1/test/test-head-validation.js +++ b/extensions/amp-a4a/0.1/test/test-head-validation.js @@ -187,6 +187,19 @@ describes.realWin('head validation', {amp: true}, (env) => { expect(preloadStub).not.to.be.called; }); + it('does not allow a foreign origin that embeds an allowlisted provider substring', () => { + const preloadStub = env.sandbox.stub( + Services.preconnectFor(env.win), + 'preload' + ); + head.innerHTML = ` + + `; + const validated = processHead(env.win, adElement, head); + expect(validated.head.querySelector('link')).not.to.exist; + expect(preloadStub).not.to.be.called; + }); + it('keeps amp styles', () => { head.innerHTML = `