Breaking Down a Unique Anti-Bot Measure
While working on automating car searches for DiscoverCars, I stumbled upon a fascinating — and somewhat unusual — security measure designed to verify…

While working on automating car searches for DiscoverCars, I stumbled upon a fascinating — and somewhat unusual — security measure designed to verify legitimate users. This post details my debugging process, how I identified the key mechanism at play, and why this method is both creative and flawed.
The Initial Challenge
To retrieve car listings, the system required an initialization session flow before making a key request:
curl 'https://www.discovercars.com/en/search/get-result-list/{session_id}?gToken={recaptcha_token}' \
-H 'accept: application/json, text/javascript, */*; q=0.01' \
-H 'user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36' \
-H 'x-requested-with: XMLHttpRequest'
After multiple attempts, I encountered HTTP 400 errors. Oddly enough, reCAPTCHA v3 tokens weren’t even validated. This made me suspect that the real check was happening elsewhere.
Finding the Real Gatekeeper
I started analyzing cookies one by one and finally identified the critical piece: gtm_ga_ggbit. Unlike the other cookies, this one was actively validated. However, online searches turned up almost nothing on it—except for a one-year-old Freelancer post from a Chinese user struggling with the same issue.

With no documentation available, I shifted to a debug-first approach to understand how this cookie was set.
Tampermonkey Debugging to the Rescue
Since I suspected that JavaScript was responsible for generating gtm_ga_ggbit, I wrote a Tampermonkey script to hook into document.cookie and break execution when this specific cookie was set.
// ==UserScript==
// @name Cookie gtm_ga_ggbit Debugger
// @namespace http://tampermonkey.net/
// @version 1.0
// @description Break into debugger when gtm_ga_ggbit cookie is set by any method.
// @author glizzykingdreko
// @match *://*/*
// @run-at document-start
// @grant none
// ==/UserScript==
(function() {
'use strict';
const TARGET_NAME = 'gtm_ga_ggbit';
let lastCookieValue = document.cookie; // store initial cookies
// Helper: trigger debugger if target cookie present in document.cookie string
function triggerDebuggerIfCookieFound(source) {
// Check for the target cookie name in the cookie string
const cookieStr = document.cookie;
if (cookieStr && cookieStr.indexOf(TARGET_NAME + '=') !== -1) {
console.log(`[Tampermonkey] Cookie "${TARGET_NAME}" detected via ${source}.`);
alert(`Cookie ${TARGET_NAME} was set via ${source}!`);
debugger; // pause execution
}
}
// Periodic check (polling) as fallback for any missed events (e.g., Set-Cookie headers)
function startCookiePolling() {
setInterval(() => {
const current = document.cookie;
if (current !== lastCookieValue) { // cookies changed
if (current.indexOf(TARGET_NAME + '=') !== -1 && lastCookieValue.indexOf(TARGET_NAME + '=') === -1) {
// target cookie appeared (wasn't in last value)
triggerDebuggerIfCookieFound('polling');
}
lastCookieValue = current;
}
}, 500); // check every 500ms (adjust as needed)
}
// Hook document.cookie setter for JavaScript writes
const docCookieDesc = Object.getOwnPropertyDescriptor(Document.prototype, 'cookie');
if (docCookieDesc && docCookieDesc.configurable) {
const nativeSetter = docCookieDesc.set;
const nativeGetter = docCookieDesc.get;
Object.defineProperty(Document.prototype, 'cookie', {
configurable: true,
enumerable: true,
get() {
return nativeGetter.call(this);
},
set(value) {
if (typeof value === 'string' && value.indexOf(TARGET_NAME + '=') === 0) {
console.log(`[Tampermonkey] Cookie "${TARGET_NAME}" being set via document.cookie:`, value);
alert(`Cookie ${TARGET_NAME} is being set via script!`);
debugger;
}
// Actually set the cookie using native setter
nativeSetter.call(this, value);
}
});
}
// Hook Fetch API
if (window.fetch) {
const origFetch = window.fetch;
window.fetch = function(...args) {
return origFetch.apply(this, args).then(response => {
// After response, check cookies
triggerDebuggerIfCookieFound('fetch/XHR response');
return response;
});
};
}
// Hook XMLHttpRequest
if (window.XMLHttpRequest) {
const origOpen = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function(...args) {
// (Optional: store URL or method if needed for debugging)
this._debugUrl = args[1];
return origOpen.apply(this, args);
};
const origSend = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.send = function(...args) {
this.addEventListener('loadend', () => {
triggerDebuggerIfCookieFound('XHR response');
});
return origSend.apply(this, args);
};
}
// Hook WebSocket
if (window.WebSocket) {
const NativeWebSocket = WebSocket;
// Override WebSocket constructor
window.WebSocket = function(...args) {
const ws = new NativeWebSocket(...args);
ws.addEventListener('open', () => {
triggerDebuggerIfCookieFound('WebSocket handshake');
});
return ws;
};
// Copy prototype to maintain instanceof checks
window.WebSocket.prototype = NativeWebSocket.prototype;
window.WebSocket.CONNECTING = NativeWebSocket.CONNECTING;
window.WebSocket.OPEN = NativeWebSocket.OPEN;
window.WebSocket.CLOSING = NativeWebSocket.CLOSING;
window.WebSocket.CLOSED = NativeWebSocket.CLOSED;
}
// Use CookieStore API events if available (for modern browsers)
if (window.cookieStore && window.cookieStore.addEventListener) {
try {
window.cookieStore.addEventListener('change', event => {
// Check if our target cookie was added/changed
for (const change of event.changed) {
if (change.name === TARGET_NAME) {
console.log(`[Tampermonkey] Cookie "${TARGET_NAME}" change detected via CookieStore API.`);
alert(`Cookie ${TARGET_NAME} was set (CookieStore API)!`);
debugger;
}
}
});
} catch(e) {
console.warn('CookieStore API event registration failed:', e);
}
} else {
// Fallback to polling if CookieStore events not supported
startCookiePolling();
}
})();
With this script, I could pinpoint exactly where gtm_ga_ggbit was being set.

Uncovering the SVG-Based Obfuscation
The key revelation came from observing a strange JavaScript function that generated gtm_ga_ggbit using color attributes from SVG elements embedded in the frontend.

JavaScript Logic
var svgConvertor = [
[109, 97, 105, 110, 45, 119, 114, 97, 112, 112, 101, 114, 45, 98, 111, 100, 121],
[102, 97, 118, 105, 99, 111, 110, 95, 49, 54, 120, 49, 54],
[102, 97, 118, 105, 99, 111, 110, 95, 51, 50, 120, 51, 50],
[97, 112, 112, 108, 101, 95, 116, 111, 117, 99, 104, 95, 105, 99, 111, 110, 95, 49, 56, 48, 120, 49, 56, 48]
];
var svgContent = '';
for (let i in svgConvertor) {
let s = '';
for (let j in svgConvertor[i]) {
s += String.fromCharCode(svgConvertor[i][j]);
}
s = $('#' + s).attr('colour');
svgContent += s.split('').reverse().join('');
}
if (typeof myCookie !== 'undefined') {
myCookie.setCookie('gtm_ga_ggbit', svgContent);
}
Breaking It Down
- The svgConvertor array deciphers into the IDs of four frontend elements: main-wrapper-body, favicon_16x16, favicon_32x32, apple_touch_icon_180x180
- Each of these elements has a colour attribute containing a seemingly random hex string.
- The script **extracts these values, reverses them, concatenates them, and assigns them to **gtm_ga_ggbit.
Example:
<div class="main-wrapper" id="main-wrapper-body" colour="#d61805d3"></div>
<link id="favicon_16x16" colour="#8585e694">
<link id="favicon_32x32" colour="#7b589a35">
<link id="apple_touch_icon_180x180" colour="#5dae22af">
This approach is unique because it dynamically obfuscates the cookie value based on frontend-rendered elements, likely making it harder for automated tools to predict.
Bypassing It in Python
Despite its creativity, this method is easy to reverse-engineer. We can simply parse the frontend, extract the necessary values, and reconstruct the cookie.
soup = BeautifulSoup(frontend_response.text, 'html.parser')
svg_content = ''
for element in [
"main-wrapper-body",
"favicon_16x16",
"favicon_32x32",
"apple_touch_icon_180x180"
]:
data = soup.find(id=element).get('colour')
svg_content += ''.join(reversed(data))
svg_content = svg_content.replace('#', '')
session.cookies.set("gtm_ga_ggbit", svg_content)
Final Thoughts
This was one of the most creative anti-bot techniques I’ve encountered. While it’s a clever way to obfuscate authentication, it’s ultimately ineffective because:
- The values are client-side and can be extracted effortlessly.
- The logic is predictable once analyzed.
- It adds complexity without significantly improving security.
Nonetheless, this approach could trick less experienced devs into wasting time debugging other factors, making it an amusing case study in security-through-obscurity.
Would love to hear if anyone else has encountered similar techniques!
Follow & Contact Me
If you enjoyed this breakdown, feel free to follow me on:
- GitHub: glizzykingdreko
- Medium: glizzykingdreko
Or reach out directly:
- Discord: glizzykingdreko
- Email: [email protected]
Skip the reverse-engineering.
Takion returns fresh cookies, headers, and tokens for every major antibot wall. One POST, no browser, first call within the hour.