2

I'm using Firefox 101.0.1 with the extension AdGuard from the official Firefox add-ons page. When this extension is activated, I find strange adware like JavaScript code with the dev tools, evaluated for each page render.

Evidence: Logs in the console

When I search for the origin of this logs I find the following:

Evidence: Sandbox eval code

            (function () {
                try {
                    var AG_onLoad=function(func){if(document.readyState==="complete"||document.readyState==="interactive")func();else if(document.addEventListener)document.addEventListener("DOMContentLoaded",func);else if(document.attachEvent)document.attachEvent("DOMContentLoaded",func)};
var AG_removeElementById = function(id) { var element = document.getElementById(id); if (element && element.parentNode) { element.parentNode.removeChild(element); }};
var AG_removeElementBySelector = function(selector) { if (!document.querySelectorAll) { return; } var nodes = document.querySelectorAll(selector); if (nodes) { for (var i = 0; i < nodes.length; i++) { if (nodes[i] && nodes[i].parentNode) { nodes[i].parentNode.removeChild(nodes[i]); } } } };
var AG_each = function(selector, fn) { if (!document.querySelectorAll) return; var elements = document.querySelectorAll(selector); for (var i = 0; i < elements.length; i++) { fn(elements[i]); }; };
var AG_removeParent = function(el, fn) { while (el && el.parentNode) { if (fn(el)) { el.parentNode.removeChild(el); return; } el = el.parentNode; } };
var AG_removeCookie=function(a){var e=/./;/^\/.+\/$/.test(a)?e=new RegExp(a.slice(1,-1)):""!==a&&(e=new RegExp(a.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")));a=function(){for(var a=document.cookie.split(";"),g=a.length;g--;){cookieStr=a[g];var d=cookieStr.indexOf("=");if(-1!==d&&(d=cookieStr.slice(0,d).trim(),e.test(d)))for(var h=document.location.hostname.split("."),f=0;f<h.length-1;f++){var b=h.slice(f).join(".");if(b){var c=d+"=",k="; domain="+b;b="; domain=."+b;document.cookie=c+"; expires=Thu, 01 Jan 1970 00:00:00 GMT";document.cookie=c+k+"; expires=Thu, 01 Jan 1970 00:00:00 GMT";document.cookie=c+b+"; expires=Thu, 01 Jan 1970 00:00:00 GMT";document.cookie=c+"; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT";document.cookie=c+k+"; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT";document.cookie=c+b+"; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"}}}};a();window.addEventListener("beforeunload",a)};
var AG_defineProperty=function(){var p,q=Object.defineProperty;if("function"==typeof WeakMap)p=WeakMap;else{var r=0,t=function(){this.a=(r+=Math.random()).toString()};t.prototype.set=function(a,b){var d=a[this.a];d&&d[0]===a?d[1]=b:q(a,this.a,{value:[a,b],writable:!0});return this};t.prototype.get=function(a){var b;return(b=a[this.a])&&b[0]===a?b[1]:void 0};t.prototype.has=function(a){var b=a[this.a];return b?b[0]===a:!1};p=t}function u(a){this.b=a;this.h=Object.create(null)}function v(a,b,d,e){this.a=a;this.i=b;this.c=d;this.f=e}function w(){this.g=/^([^\\\.]|\\.)*?\./;this.j=/\\(.)/g;this.a=new p}function x(a,b){var d=b.f;if(d&&!("beforeGet"in d||"beforeSet"in d))return z(d);var e={get:function(){var c=b.f;c&&c.beforeGet&&c.beforeGet.call(this,b.a.b);a:if(c=b.g)c=A(c)?c.value:c.get?c.get.call(this):void 0;else{c=b.a.b;if(b.i in c&&(c=B(c),null!==c)){var d=C.call(c,b.i);c=d?d.call(this):c[b.i];break a}c=void 0}(this===b.a.b||D.call(b.a.b,this))&&E(a,c,b.c);return c},set:function(c){if(this===b.a.b||D.call(b.a.b,this)){b.f&&b.f.beforeSet&&(c=b.f.beforeSet.call(this,c,this));var d=b.g;d&&A(d)&&d.value===c?c=!0:(d=F(b,c,this),G(c)&&(c=H(a,c),I(a,c,b.c)),c=d)}else c=F(b,c,this);return c}};d&&J(d,e,K);return e}function I(a,b,d){for(var e in d.h){var c=d.h[e];if(b.h[e]){var h=a,g=b.h[e],k=c;!k.f||g.f||"undefined"===typeof g.a.b||g.g||(g.g=z(k.f));g.c&&k.c&&g.c!==k.c&&I(h,g.c,k.c)}else{g=h=void 0;k=a;var f=b,l=c.i,m="undefined"!==typeof f.b,y=!1;m&&(g=L(f.b,l))&&!g.configurable&&(y=!0,h=f.b[l]);var n=y?H(k,h):new u(c.c.b);I(k,n,c.c);n=new v(f,l,n,c.f);f.h[l]=n;m&&(n.g=g,m=x(k,n),y?E(k,h,c.c):(q(f.b,l,m),g&&A(g)&&(M(m,g.value,f.b),E(k,g.value,c.c))))}}}function E(a,b,d){G(b)&&(b=H(a,b),I(a,b,d))}function F(a,b,d){var e=a.g;if(!e){e=B(a.a.b);if(null!==e&&(e=N.call(e,a.i)))return e.call(d,b);if(!O(a.a.b))return!1;a.g={value:b,configurable:!0,writable:!0,enumerable:!0};return!0}return M(e,b,d)}function H(a,b){var d=a.a.get(b);d||(d=new u(b),a.a.set(b,d));return d}function A(a){return"undefined"!==typeof a.writable}function J(a,b,d){for(var e=0,c=d.length;e<c;e++){var h=d[e];h in a&&(b[h]=a[h])}}function z(a){if(a){var b={};J(a,b,P);return b}}function M(a,b,d){if(A(a))return a.writable?(a.value=b,!0):!1;if(!a.set)return!1;a.set.call(d,b);return!0}var P="configurable enumerable value get set writable".split(" "),K=P.slice(0,2),L=Object.getOwnPropertyDescriptor,O=Object.isExtensible,B=Object.getPrototypeOf,D=Object.prototype.isPrototypeOf,C=Object.prototype.__lookupGetter__||function(a){return(a=Q(this,a))&&a.get?a.get:void 0},N=Object.prototype.__lookupSetter__||function(a){return(a=Q(this,a))&&a.set?a.set:void 0};function Q(a,b){if(b in a){for(;!w.hasOwnProperty.call(a,b);)a=B(a);return L(a,b)}}function G(a){var b=typeof a;return"function"===b||"object"===b&&null!==a?!0:!1}var R;return function(a,b,d){R||(R=new w);var e=R;d=d||window;var c=new u;a+=".";var h=c||new u;for(var g=e.g,k=e.j,f,l,m;a;){f=g.exec(a);if(null===f)throw 1;f=f[0].length;l=a.slice(0,f-1).replace(k,"$1");a=a.slice(f);(f=h.h[l])?m=f.c:(m=new u,f=new v(h,l,m),h.h[l]=f);h=m}if(!f)throw 1;a=f;a.f=b;E(e,d,c)};}();
var AG_abortOnPropertyWrite=function(a,b){var c=Math.random().toString(36).substr(2,8);AG_defineProperty(a,{beforeSet:function(){b&&console.warn("AdGuard aborted property write: "+a);throw new ReferenceError(c);}});var d=window.onerror;window.onerror=function(e){if("string"===typeof e&&-1!==e.indexOf(c))return b&&console.warn("AdGuard has caught window.onerror: "+a),!0;if(d instanceof Function)return d.apply(this,arguments)}};
var AG_abortOnPropertyRead=function(a,b){var c=Math.random().toString(36).substr(2,8);AG_defineProperty(a,{beforeGet:function(){b&&console.warn("AdGuard aborted property read: "+a);throw new ReferenceError(c);}});var d=window.onerror;window.onerror=function(e){if("string"===typeof e&&-1!==e.indexOf(c))return b&&console.warn("AdGuard has caught window.onerror: "+a),!0;if(d instanceof Function)return d.apply(this,arguments)}};
var AG_abortInlineScript=function(g,b,c){var d=function(){if("currentScript"in document)return document.currentScript;var a=document.getElementsByTagName("script");return a[a.length-1]},e=Math.random().toString(36).substr(2,8),h=d();AG_defineProperty(b,{beforeGet:function(){var a=d();if(a instanceof HTMLScriptElement&&a!==h&&""===a.src&&g.test(a.textContent))throw c&&console.warn("AdGuard aborted execution of an inline script"),new ReferenceError(e);}});var f=window.onerror;window.onerror=function(a){if("string"===typeof a&&-1!==a.indexOf(e))return c&&console.warn("AdGuard has caught window.onerror: "+b),!0;if(f instanceof Function)return f.apply(this,arguments)}};
var AG_setConstant=function(e,a){if("undefined"===a)a=void 0;else if("false"===a)a=!1;else if("true"===a)a=!0;else if("noopFunc"===a)a=function(){};else if("trueFunc"===a)a=function(){return!0};else if("falseFunc"===a)a=function(){return!1};else if(/^\d+$/.test(a)){if(a=parseFloat(a),isNaN(a)||32767<Math.abs(a))return}else return;var b=!1;AG_defineProperty(e,{get:function(){return a},set:function(c){if(b)var d=!0;else void 0!==c&&void 0!==a&&typeof c!==typeof a&&(b=!0),d=b;d&&(a=c)}})};
(function(source, args){
function setConstant(source, property, value, stack) {
          if (!property || !matchStackTrace(stack, new Error().stack)) {
            return;
          }
          var log = console.log.bind(console);
          var emptyArr = noopArray();
          var emptyObj = noopObject();
          var constantValue;
          if (value === 'undefined') {
            constantValue = undefined;
          } else if (value === 'false') {
            constantValue = false;
          } else if (value === 'true') {
            constantValue = true;
          } else if (value === 'null') {
            constantValue = null;
          } else if (value === 'emptyArr') {
            constantValue = emptyArr;
          } else if (value === 'emptyObj') {
            constantValue = emptyObj;
          } else if (value === 'noopFunc') {
            constantValue = noopFunc;
          } else if (value === 'trueFunc') {
            constantValue = trueFunc;
          } else if (value === 'falseFunc') {
            constantValue = falseFunc;
          } else if (value === 'noopPromiseResolve') {
            constantValue = noopPromiseResolve;
          } else if (value === 'noopPromiseReject') {
            constantValue = noopPromiseReject;
          } else if (/^\d+$/.test(value)) {
            constantValue = parseFloat(value);
            if (nativeIsNaN(constantValue)) {
              return;
            }
            if (Math.abs(constantValue) > 0x7FFF) {
              return;
            }
          } else if (value === '-1') {
            constantValue = -1;
          } else if (value === '') {
            constantValue = '';
          } else if (value === 'yes') {
            constantValue = 'yes';
          } else if (value === 'no') {
            constantValue = 'no';
          } else {
            return;
          }
          var getCurrentScript = function getCurrentScript() {
            if ('currentScript' in document) {
              return document.currentScript;
            }
            var scripts = document.getElementsByTagName('script');
            return scripts[scripts.length - 1];
          };
          var ourScript = getCurrentScript();
          var canceled = false;
          var mustCancel = function mustCancel(value) {
            if (canceled) {
              return canceled;
            }
            canceled = value !== undefined && constantValue !== undefined && typeof value !== typeof constantValue;
            return canceled;
          };
          var trapProp = function trapProp(base, prop, configurable, handler) {
            if (!handler.init(base[prop])) {
              return false;
            }
            var origDescriptor = Object.getOwnPropertyDescriptor(base, prop);
            var prevGetter;
            var prevSetter;
            if (origDescriptor instanceof Object) {
              if (!origDescriptor.configurable) {
                if (source.verbose) {
                  log("set-constant: property '".concat(prop, "' is not configurable"));
                }
                return false;
              }
              base[prop] = constantValue;
              if (origDescriptor.get instanceof Function) {
                prevGetter = origDescriptor.get;
              }
              if (origDescriptor.set instanceof Function) {
                prevSetter = origDescriptor.set;
              }
            }
            Object.defineProperty(base, prop, {
              configurable: configurable,
              get: function get() {
                if (prevGetter !== undefined) {
                  prevGetter();
                }
                return handler.get();
              },
              set: function set(a) {
                if (prevSetter !== undefined) {
                  prevSetter(a);
                }
                handler.set(a);
              }
            });
            return true;
          };
          var setChainPropAccess = function setChainPropAccess(owner, property) {
            var chainInfo = getPropertyInChain(owner, property);
            var base = chainInfo.base;
            var prop = chainInfo.prop,
                chain = chainInfo.chain;
            var undefPropHandler = {
              factValue: undefined,
              init: function init(a) {
                this.factValue = a;
                return true;
              },
              get: function get() {
                return this.factValue;
              },
              set: function set(a) {
                if (this.factValue === a) {
                  return;
                }
                this.factValue = a;
                if (a instanceof Object) {
                  setChainPropAccess(a, chain);
                }
              }
            };
            var endPropHandler = {
              factValue: undefined,
              init: function init(a) {
                if (mustCancel(a)) {
                  return false;
                }
                this.factValue = a;
                return true;
              },
              get: function get() {
                return document.currentScript === ourScript ? this.factValue : constantValue;
              },
              set: function set(a) {
                if (!mustCancel(a)) {
                  return;
                }
                constantValue = a;
              }
            };
            if (!chain) {
              var isTrapped = trapProp(base, prop, false, endPropHandler);
              if (isTrapped) {
                hit(source);
              }
              return;
            }
            var propValue = owner[prop];
            if (propValue instanceof Object || typeof propValue === 'object' && propValue !== null) {
              setChainPropAccess(propValue, chain);
            }
            trapProp(owner, prop, true, undefPropHandler);
          };
          setChainPropAccess(window, property);
        }
function hit(source, message) {
          if (source.verbose !== true) {
            return;
          }
          try {
            var log = console.log.bind(console);
            var trace = console.trace.bind(console);
            var prefix = source.ruleText || '';
            if (source.domainName) {
              var AG_SCRIPTLET_MARKER = '#%#//';
              var UBO_SCRIPTLET_MARKER = '##+js';
              var ruleStartIndex;
              if (source.ruleText.indexOf(AG_SCRIPTLET_MARKER) > -1) {
                ruleStartIndex = source.ruleText.indexOf(AG_SCRIPTLET_MARKER);
              } else if (source.ruleText.indexOf(UBO_SCRIPTLET_MARKER) > -1) {
                ruleStartIndex = source.ruleText.indexOf(UBO_SCRIPTLET_MARKER);
              }
              var rulePart = source.ruleText.slice(ruleStartIndex);
              prefix = "".concat(source.domainName).concat(rulePart);
            }
            var LOG_MARKER = 'log: ';
            if (message) {
              if (message.indexOf(LOG_MARKER) === -1) {
                log("".concat(prefix, " message:\n").concat(message));
              } else {
                log(message.slice(LOG_MARKER.length));
              }
            }
            log("".concat(prefix, " trace start"));
            if (trace) {
              trace();
            }
            log("".concat(prefix, " trace end"));
          } catch (e) {
          }
          if (typeof window.__debug === 'function') {
            window.__debug(source);
          }
        }
function noopArray() {
          return [];
        }
function noopObject() {
          return {};
        }
function noopFunc() {}
function trueFunc() {
          return true;
        }
function falseFunc() {
          return false;
        }
function noopPromiseReject() {
          return Promise.reject();
        }
function noopPromiseResolve() {
          return Promise.resolve(new Response());
        }
function getPropertyInChain(base, chain) {
          var pos = chain.indexOf('.');
          if (pos === -1) {
            return {
              base: base,
              prop: chain
            };
          }
          var prop = chain.slice(0, pos);
          if (base === null) {
            return {
              base: base,
              prop: prop,
              chain: chain
            };
          }
          var nextBase = base[prop];
          chain = chain.slice(pos + 1);
          if (nextBase !== undefined) {
            return getPropertyInChain(nextBase, chain);
          }
          Object.defineProperty(base, prop, {
            configurable: true
          });
          return {
            base: nextBase,
            prop: prop,
            chain: chain
          };
        }
function setPropertyAccess(object, property, descriptor) {
          var currentDescriptor = Object.getOwnPropertyDescriptor(object, property);
          if (currentDescriptor && !currentDescriptor.configurable) {
            return false;
          }
          Object.defineProperty(object, property, descriptor);
          return true;
        }
function toRegExp() {
          var input = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
          var DEFAULT_VALUE = '.?';
          var FORWARD_SLASH = '/';
          if (input === '') {
            return new RegExp(DEFAULT_VALUE);
          }
          if (input[0] === FORWARD_SLASH && input[input.length - 1] === FORWARD_SLASH) {
            return new RegExp(input.slice(1, -1));
          }
          var escaped = input.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
          return new RegExp(escaped);
        }
function matchStackTrace(stackMatch, stackTrace) {
          if (!stackMatch || stackMatch === '') {
            return true;
          }
          var stackRegexp = toRegExp(stackMatch);
          var refinedStackTrace = stackTrace.split('\n').slice(2)
          .map(function (line) {
            return line.trim();
          })
          .join('\n');
          return stackRegexp.test(refinedStackTrace);
        }
function nativeIsNaN(num) {
          var native = Number.isNaN || window.isNaN;
          return native(num);
        };
        const updatedArgs = args ? [].concat(source).concat(args) : [source];
        try {
            setConstant.apply(this, updatedArgs);
        } catch (e) {
            console.log(e);
        }
    
})({"args":["PartnersCoupang","undefined"],"engine":"extension","name":"set-constant","ruleText":"~coupang.com,~coupangcdn.com#%#//scriptlet(\"set-constant\", \"PartnersCoupang\", \"undefined\")","verbose":true,"version":"4.0.181"}, ["PartnersCoupang","undefined"]);
                } catch (ex) {
                    console.error('Error executing AG js: ' + ex);
                }
            })();

I've troubles to find the origin for this inside the AdGuard extension and is quite fishy to me, as "coupang" is a South Korean e commerce company and I have no ties with them. I also started to search inside the blocking list subscriptions I have, but no clue so far. How can I investigate this further?

enter image description here

5
  • Might have something to do with this, but I have not looked into the source (if it even exists) to see which commit added that line.
    – user
    Jun 14 at 15:29
  • 1
    Isn't the trace just logging what it does when it uses a filter? What makes you think this looks like adware? Jun 14 at 15:37
  • Well its a huge Javascript which is loaded additionally, with references to a South Korean e-commerce platform. It's suspicious to me.
    – Robin
    Jun 14 at 15:53
  • does it go away when disabling ad guard? if so, well, there you go.
    – dandavis
    Jun 14 at 21:15
  • Yes it goes away if I disable adguard.
    – Robin
    Jun 15 at 21:31

1 Answer 1

2

A quick skim-through of the code suggests to me that this script is part of AdGuard, used to implement their scriptlet filter list rules.

The AdGuard documentation has this to say about scriptlets:

Scriptlet is a JavaScript function that provides extended capabilities for content blocking. These functions can be used in a declarative manner in AdGuard filtering rules.

Syntax:

rule = [domains] "#%#//scriptlet(" scriptletName arguments ")"

The end of the script you posted references the following rule, which seems to match the syntax in the AdGuard documentation:

~coupang.com,~coupangcdn.com#%#//scriptlet("set-constant", "PartnersCoupang", "undefined")

In this case the rule appears to be using the set-constant scriptlet to undefine the PartnersCoupang constant in the context of the page you're viewing, probably as part of some effort to block functionality of a tracking or ad script on the host page.

Not the answer you're looking for? Browse other questions tagged or ask your own question.