In modern web development, we often load third-party scripts—such as ads, analytics, SDKs, and plugins. For the sake of "convenience," these scripts frequently inject variables and functions directly into the global scope (window object), or even modify native objects. This practice not only pollutes the global namespace, but can also lead to variable conflicts, performance degradation, security risks, and even silent tampering with critical APIs (e.g., overriding console.log or XMLHttpRequest).
So, as developers, how can we accurately identify exactly what a third-party script adds to or changes in the window object? In this article, we’ll walk you through building a lightweight yet reliable monitoring solution.
1. Problem Scenario
Suppose we want to load an ad script:
<script src="https://cdn.wwads.cn/js/makemoney.js "></script>
We’d like to know:
- What new global variables did it introduce?
- Did it modify any existing global properties (e.g.,
Array,Promise, or custom variables)?
Relying solely on Object.keys(window).length only tells us the count has changed—it doesn’t reveal what specifically changed. We need a more granular comparison.
2. Core Approach: Snapshot + Differential Comparison
The most straightforward way to detect “changes” is:
- Take a complete snapshot of
window(property names + values) before loading the script. - Take another snapshot after the script loads.
- Compare the two snapshots to identify newly added properties and properties whose values have changed.
Key considerations:
- Use
Object.getOwnPropertyNames(window)to capture all properties, including non-enumerable ones. - Store the property-value mappings in a
Mapfor efficient lookups. - Use
Object.is()for value comparison to properly handle edge cases likeNaNand-0/+0. - Wrap access in
try...catchto avoid exceptions when reading certain special properties.
3. Full Implementation Code
// 1. Create a window snapshot: record all properties and their current values
function snapshotWindow() {
const props = Object.getOwnPropertyNames(window);
const snap = new Map();
for (const key of props) {
try {
snap.set(key, window[key]);
} catch (e) {
// Accessing certain properties (e.g., opener in cross-origin iframes) may throw errors
snap.set(key, '<ACCESS_ERROR>');
}
}
return snap;
}
// 2. Record the state before loading
const beforeSnapshot = snapshotWindow();
// 3. Dynamically load the third-party script
const script = document.createElement('script');
script.src = 'https://cdn.wwads.cn/js/makemoney.js ';
// 4. Perform comparison after the script loads
script.onload = () => {
// Add a small delay to ensure the script finishes executing (including microtasks)
setTimeout(() => {
const afterSnapshot = snapshotWindow();
const added = [];
const modified = [];
// Iterate over all properties after loading
for (const [key, newValue] of afterSnapshot) {
if (!beforeSnapshot.has(key)) {
added.push(key); // Newly added
} else {
const oldValue = beforeSnapshot.get(key);
if (!Object.is(oldValue, newValue)) {
modified.push({ key, oldValue, newValue }); // Modified
}
}
}
console.log('🟢 New global variables:', added);
console.log('🟡 Modified global variables:', modified);
}, 100);
};
script.onerror = () => console.error('Failed to load third-party script');
document.head.appendChild(script);
4. Example Output and Interpretation
After running the above code, your console might show:
🟢 New global variables: ['_AdBlockInit', '_IsTrustedClick']
🟡 Modified global variables: [
{ key: "isMobile", oldValue: [Function], newValue: [Object] }
]
This means:
- The script injected ad-related variables like
_AdBlockInit; - It likely overwrote the
isMobileobject.
Such behavior is not uncommon in ad or data-collection scripts, but it poses potential threats to your application’s stability and security.
5. Caveats and Advanced Tips
1. False Positives from Dynamic Properties
Some window properties are getters (e.g., window.devicePixelRatio), and their values may differ on each access. These can be mistakenly flagged as “modified.” You can avoid this by maintaining a whitelist:
const DYNAMIC_PROPS = new Set(['devicePixelRatio', 'innerWidth', 'innerHeight', 'scrollY']);
if (DYNAMIC_PROPS.has(key)) return; // Skip comparison
2. Deep Mutations Go Undetected
If a script only modifies internal properties of an object (e.g., window.myLib.config = {...}) without changing the object reference itself, the change won’t be detected. For deep monitoring, you’d need techniques like Proxy or recursive traversal—but these come with higher performance costs.
3. Use with Caution in Production
This approach is best suited for development debugging or security audits. Avoid running it continuously in production, as iterating over the entire window object incurs noticeable performance overhead.
4. Combine with CSP and Sandboxing
For high-security applications, we recommend:
- Enforcing a Content Security Policy (CSP) to restrict script sources;
- Running third-party scripts inside a sandboxed iframe to fully isolate them from the global scope.
5. Isolation Strategy: Auto-Restore Critical Globals After Execution
If you know a third-party script overwrites specific global variables (e.g., isMobile or config) but must load it anyway, you can use a “backup-and-restore” approach to automatically revert those variables after the script runs, containing its side effects:
function loadThirdPartyScript(src, backupGlobals = []) {
const backup = {};
backupGlobals.forEach(key => {
backup[key] = window[key];
});
const script = document.createElement('script');
script.src = src;
script.async = true;
script.onload = script.onerror = () => {
backupGlobals.forEach(key => {
window[key] = backup[key];
});
};
document.head.appendChild(script);
}
// Usage example
loadThirdPartyScript('https://cdn.wwads.cn/js/makemoney.js ', ['isMobile', 'config']);
⚠️ Note: This technique only works if the script applies its global modifications synchronously during initial execution. If the script uses
setTimeout, event listeners, or async callbacks to mutate globals later, the restore may not be effective.
6. Conclusion
Third-party scripts are essentially “black boxes”—we can’t control their implementation, but we can actively monitor their side effects. With a simple snapshot-comparison technique, you gain clear visibility into how they “intrude” on your global environment, providing valuable insights for performance tuning, security audits, and troubleshooting.
Next time you consider loading an unfamiliar script, ask yourself: “What exactly are you writing to my window?”
💡 Pro Tip: Wrap the logic above into a reusable function like
detectGlobalPollution(scriptUrl)to easily audit any third-party script.
Article URL:https://toolshu.com/en/article/f5gr8qsc
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License 。


Loading...