Guides

How safe am I?

Test your detection footprint in real-time. Our educational scanner mimics The West's 3-layer anti-cheat system to show you exactly what gets logged:

  • Global variables exposed by your scripts
  • CSS fingerprints from injected stylesheets
  • WebDriver automation detection
  • Script identification with confidence scores

Run scanTWScripts() in console. Get instant results. Learn what's being tracked about you—before the admins do. Educational demonstration tool.
Install, scan, understand.

JavaScript
Copied!
js
		
// ==UserScript==
// @name         TW Scripts Scanner
// @namespace    TW-Cheats
// @author       TW-Cheats
// @description  Checks for globals, injected styles and webdriver usage
// @include      https://*.the-west.*/game.php*
// @version      3.1
// @grant        GM_xmlhttpRequest
// @grant        unsafeWindow
// @grant        GM_setClipboard
// @run-at       document-idle
// ==/UserScript==

(function () {
    'use strict';

    const initialVarCount = Object.keys(unsafeWindow).length;

    // Browser / engine noise we don't care about
    const ignoreList = new Set([
        'addEventListener',
        'removeEventListener',
        'dispatchEvent',
        'setTimeout',
        'setInterval',
        'clearTimeout',
        'clearInterval',
        'requestAnimationFrame',
        'cancelAnimationFrame',
        'fetch',
        'XMLHttpRequest',
        'Promise',
        'console',
        'localStorage',
        'sessionStorage',
        'getDefaultComputedStyle',
        'scrollByLines',
        'scrollByPages',
        'updateCommands',
        'dump',
        'setResizable',
        'requestIdleCallback',
        'cancelIdleCallback',
        'external',
        'mozInnerScreenX',
        'mozInnerScreenY',
        'scrollMaxX',
        'scrollMaxY',
        'fullScreen',
        'ondevicemotion',
        'ondeviceorientation',
        'ondeviceorientationabsolute',
        'InstallTrigger',
        'originAgentCluster',
        'onbeforematch',
        'oncontextlost',
        'oncommand',
        'oncontextrestored',
        'ondragexit',
        'onscrollend',
        'onpointerrawupdate',
        'onmozfullscreenchange',
        'onmozfullscreenerror',
        'scheduler'
    ]);

    let allowedVariables = null;
    let lastScanResults = null;

    GM_xmlhttpRequest({
        method: 'GET',
        url: 'https://tw-cheats.com/files/vars.json',
        onload(res) {
            try {
                allowedVariables = JSON.parse(res.responseText);
            } catch {
                console.error('[Scanner] Invalid allowed vars list');
                return;
            }

            setTimeout(() => {
                console.log('[Scanner] Auto scan');
                console.log(
                    'Globals:',
                    initialVarCount,
                    '→',
                    Object.keys(unsafeWindow).length
                );
                runScan('auto');
            }, 10000);
        },
        onerror() {
            console.error('[Scanner] Failed to load allowed vars list');
        }
    });

    // exposed only through console, no globals
    console.scan = function () {
        if (!allowedVariables) {
            console.warn('[Scanner] Not ready yet');
            return;
        }
        runScan('manual');
    };

    console.export = function () {
        if (!lastScanResults) {
            console.warn('[Scanner] No scan data');
            return;
        }
        GM_setClipboard(buildTextReport(lastScanResults));
        console.log('[Scanner] Report copied');
    };

    console.report = function () {
        if (!lastScanResults) {
            console.warn('[Scanner] No scan data');
            return;
        }
        printReport(lastScanResults);
    };

    function scanStyles() {
        return Array.from(document.styleSheets)
            .filter(s => {
                if (!s.href) return true;
                const h = s.href.toLowerCase();
                return !h.includes('the-west') && !h.includes('innogames');
            })
            .map(s => {
                if (s.href) {
                    return `external: ${s.href}`;
                }
                try {
                    return `inline (${s.cssRules.length} rules)`;
                } catch {
                    return 'inline (blocked)';
                }
            });
    }

    function runScan(label) {
        const vars = Object.keys(unsafeWindow)
            .slice(unsafeWindow.Chat.Router.varPos);

        const allowed = new Set(allowedVariables);

        const illegal = vars.filter(v =>
            !allowed.has(v) && !ignoreList.has(v)
        );

        const varInfo = illegal.map(name => {
            const val = unsafeWindow[name];
            const type = typeof val;

            let preview;
            if (type === 'function') preview = 'function';
            else if (Array.isArray(val)) preview = `array(${val.length})`;
            else if (type === 'object' && val) preview = 'object';
            else preview = String(val).slice(0, 50);

            return { name, type, preview };
        });

        const styles = scanStyles();
        const webdriver = navigator.webdriver === true;

        lastScanResults = {
            time: new Date().toISOString(),
            label,
            illegal: varInfo,
            styles,
            webdriver
        };

        console.log('[Scanner]', label);
        console.log('globals:', illegal.length);
        console.log('styles:', styles.length);
        console.log('webdriver:', webdriver);
    }

    function buildTextReport(r) {
        let out = '';
        out += 'TW Scripts Scanner\n\n';
        out += `Time: ${r.time}\n`;
        out += `Scan: ${r.label}\n\n`;

        out += `Globals: ${r.illegal.length}\n`;
        out += `Styles: ${r.styles.length}\n`;
        out += `WebDriver: ${r.webdriver}\n\n`;

        if (r.illegal.length) {
            out += 'Globals:\n';
            r.illegal.forEach((v, i) => {
                out += `${i + 1}. ${v.name} (${v.type}) ${v.preview}\n`;
            });
            out += '\n';
        }

        if (r.styles.length) {
            out += 'Styles:\n';
            r.styles.forEach((s, i) => {
                out += `${i + 1}. ${s}\n`;
            });
            out += '\n';
        }

        if (r.webdriver) {
            out += 'navigator.webdriver = true\n';
        }

        return out;
    }

    function printReport(r) {
        console.clear();
        console.log('TW Scripts Scanner');
        console.log('Time:', r.time);
        console.log('Scan:', r.label);
        console.log('');

        if (r.webdriver) {
            console.log('webdriver detected');
        }

        if (r.styles.length) {
            console.log('styles:');
            r.styles.forEach(s => console.log(' -', s));
        }

        if (r.illegal.length) {
            console.log('globals:');
            r.illegal.forEach(v =>
                console.log(` - ${v.name} (${v.type})`, v.preview)
            );
        }

        if (!r.webdriver && !r.styles.length && !r.illegal.length) {
            console.log('clean');
        }
    }

    console.log('[Scanner] Loaded (10 seconds)');
})();