From f507fe4f072ead6e67e37530aa105c7f82858486 Mon Sep 17 00:00:00 2001 From: Demetrio Girardi Date: Tue, 30 Aug 2022 13:49:54 -0600 Subject: [PATCH] Sanitize JSON for adgeneration --- modules/adgenerationBidAdapter.js | 4 +-- src/utils.js | 27 +++++++++++++++++++ .../modules/emx_digitalBidAdapter_spec.js | 4 +-- 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/modules/adgenerationBidAdapter.js b/modules/adgenerationBidAdapter.js index 21395724609..0e4e9ef6805 100644 --- a/modules/adgenerationBidAdapter.js +++ b/modules/adgenerationBidAdapter.js @@ -1,4 +1,4 @@ -import {tryAppendQueryString, getBidIdParameter} from '../src/utils.js'; +import {tryAppendQueryString, getBidIdParameter, escapeUnsafeChars} from '../src/utils.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; import {BANNER, NATIVE} from '../src/mediaTypes.js'; import {config} from '../src/config.js'; @@ -230,7 +230,7 @@ function insertVASTMethodForAPV(targetId, vastXml) { }; let script = document.createElement(`script`); script.type = 'text/javascript'; - script.innerHTML = `(function(){ new APV.VideoAd(${JSON.stringify(apvVideoAdParam)}).load('${vastXml.replace(/\r?\n/g, '')}'); })();`; + script.innerHTML = `(function(){ new APV.VideoAd(${escapeUnsafeChars(JSON.stringify(apvVideoAdParam))}).load('${vastXml.replace(/\r?\n/g, '')}'); })();`; return script.outerHTML; } diff --git a/src/utils.js b/src/utils.js index 08f06324503..de805b965fd 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1381,3 +1381,30 @@ export function setScriptAttributes(script, attributes) { } } } + +/** + * Encode a string for inclusion in HTML. + * See https://pragmaticwebsecurity.com/articles/spasecurity/json-stringify-xss.html and + * https://codeql.github.com/codeql-query-help/javascript/js-bad-code-sanitization/ + * @return {string} + */ +export const escapeUnsafeChars = (() => { + const escapes = { + '<': '\\u003C', + '>': '\\u003E', + '/': '\\u002F', + '\\': '\\\\', + '\b': '\\b', + '\f': '\\f', + '\n': '\\n', + '\r': '\\r', + '\t': '\\t', + '\0': '\\0', + '\u2028': '\\u2028', + '\u2029': '\\u2029' + }; + + return function(str) { + return str.replace(/[<>\b\f\n\r\t\0\u2028\u2029\\]/g, x => escapes[x]) + } +})(); diff --git a/test/spec/modules/emx_digitalBidAdapter_spec.js b/test/spec/modules/emx_digitalBidAdapter_spec.js index 96447968a9e..d99318b5ddc 100644 --- a/test/spec/modules/emx_digitalBidAdapter_spec.js +++ b/test/spec/modules/emx_digitalBidAdapter_spec.js @@ -251,8 +251,8 @@ describe('emx_digital Adapter', function () { it('contains a properly formatted endpoint url', function () { const url = request.url.split('?'); const queryParams = url[1].split('&'); - expect(queryParams[0]).to.match(new RegExp('^t=d*', 'g')); - expect(queryParams[1]).to.match(new RegExp('^ts=d*', 'g')); + expect(queryParams[0]).to.match(new RegExp('^t=\d*', 'g')); + expect(queryParams[1]).to.match(new RegExp('^ts=\d*', 'g')); }); it('builds bidfloor value from bid param when getFloor function does not exist', function () {