T07 · Tool Hijacking and Spoofing
Warning
- Location
- scripts/Scroll-Performance.js:2
- Finding
- Persistent Global Wrapping of EventTarget.addEventListener<![CDATA[ ## Vulnerability Details **File Location**: `scripts/Scroll-Performance.js:2` **Vulnerability Type**: Global browser API modification without restoration **Risk Level**: Medium ### Vulnerable Code ```js const n = EventTarget.prototype.addEventListener; EventTarget.prototype.addEventListener = function (l, s, o) { return ( t.has(l) && ( !0 !== o && "object" == typeof o && null !== o && !0 === o.passive || e.push({ type: l, element: this.tagName || this.constructor?.name || "unknown", id: this.id || "", passive: !1 }) ), n.call(this, l, s, o) ); }; ``` ### Technical Analysis The script replaces `EventTarget.prototype.addEventListener` for the entire inspected page. The wrapper records metadata about future `scroll`, `wheel`, and touch-event listener registrations before forwarding each call to the previously captured implementation. The modification is not isolated to the audit code. Every subsequent event-listener registration made by application code, frameworks, browser extensions operating in the same JavaScript world, or other diagnostic snippets passes through this wrapper. No cleanup mechanism restores the original method. Re-executing the script captures the existing wrapper as the new delegate and installs another wrapper around it. This can create a chain of persistent wrappers, retain multiple instrumentation closures, duplicate collected observations, and alter the observable identity of the native method. It may also conflict with application or monitoring code that expects the original API or independently instruments it. The reviewed implementation continues to call the original method and does not capture callback contents, transmit information, or intentionally execute malicious logic. The risk is therefore limited to page integrity, compatibility, measurement accuracy, and runtime stability rather than credenti ...[truncated 1653 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. **Make installation idempotent.** Store instrumentation state under a private `Symbol` or uniquely named property and refuse to install another wrapper when one is already active. 2. **Preserve the actual original method.** Record the native implementation once rather than treating a previously installed wrapper as the original method. 3. **Provide explicit cleanup.** Expose a cleanup function that: - Restores `EventTarget.prototype.addEventListener`. - Removes the installed scroll listener. - Cancels active animation frames. - Clears pending timers. - Releases collected state where appropriate. 4. **Use `try/finally` for bounded audits.** If listener inspection only needs to occur during a defined measurement period, restore the API in a `finally` block after collection. 5. **Avoid prototype modification where possible.** Prefer Chrome DevTools Protocol facilities or other diagnostic mechanisms that inspect listeners without changing page-wide native APIs. 6. **Document side effects.** Clearly warn that the snippet instruments a global browser API and specify the cleanup procedure. A hardened installation pattern should resemble: ```js const STATE = Symbol.for("webperf.scrollPerformance"); const prototype = EventTarget.prototype; if (!prototype[STATE]) { const originalAddEventListener = prototype.addEventListener; const wrappedAddEventListener = function (type, listener, options) { // Collect only the minimum required metadata. return Reflect.apply(originalAddEventListener, this, [ type, listener, options ]); }; prototype[STATE] = { originalAddEventListener, wrappedAddEventListener }; prototype.addEventListener = wrappedAddEventListener; } window.cleanupScrollPerformanceAudit = () => { const state = prototype[STATE]; if (state && prototype.addEventListener === state.wrappedAddEventListener) { prototype.addEventListener = state.originalAddEv ...[truncated 135 chars]
