Impersonating Grok Bot for Fun and (No) Profit A security researcher forged Grok Bot's Web Bot Auth signatures by extracting the SAND_INFERENCE_RENEWAL_CREDENTIAL token from the sand-web-bot-auth.mjs process environment and using it to call Cursor's signing API, then injected the resulting Signature, Signature-Input, and Signature-Agent headers into Chrome via the Chrome DevTools Protocol to scrape sites behind Cloudflare. The researcher found the signing script at /usr/local/bin/sand-web-bot-auth.mjs, which is also downloadable from SpaceXAI's public CDN as sand-host-bundle-latest.tgz, and noted the token is unset from the environment by /usr/local/bin/start-exec-daemon but recoverable via /proc//environ. The technique undermines Web Bot Auth, the standard that verifies AI agent identity through cryptographic signatures and a public JWK published at /.well-known/http-message-signatures-directory. Back to all posts https://nightd.dev/blog Impersonating Grok Bot for Fun and No Profit How I forged Grok Bot's Web Bot Auth signatures and used them to scrape sites behind Cloudflare. A few months ago on August 11, 2026 SpaceXAI released an AI personal assistant named Grok Bot https://x.ai/bot . According to Cloudflare Radar https://radar.cloudflare.com/bots/directory/grok-bot and browsing X it seems like it has been quite successful. However, while playing around with Grok Bot I noticed many odd things. One thing in particular drew my attention. While looking at requests in Chrome’s DevTools I noticed three headers used to cryptographically sign requests, Signature , Signature-Input , and Signature-Agent . I immediately recognized this is Web Bot Auth WBA and wondered how it was injected. What Is Web Bot Auth? what-is-web-bot-auth Web Bot Auth is a standard that verifies the identity of an automated bot such as AI agents by using Signature headers. Instead of relying on the User-Agent or IP allowlists, it requires bot operators to cryptographically sign their requests using a private key and publishing the corresponding public key JWK https://www.rfc-editor.org/info/rfc7517/ on their domain at /.well-known/http-message-signatures-directory . This allows site operators to prove a bot’s identity. You can find more details at Cloudflare’s Web Bot Auth documentation https://developers.cloudflare.com/bots/reference/bot-verification/web-bot-auth/ and their announcement post https://blog.cloudflare.com/web-bot-auth/ in partnership with Browserbase https://www.browserbase.com/blog/cloudflare-browserbase-pioneering-identity , a data acquisition company. How to Forge Signatures how-to-forge-signatures After creating a Bot and opening its desktop environment, I started digging around and I found a file of interest at /usr/local/bin/sand-web-bot-auth.mjs . This file is also contained in a package that can be directly downloaded from their CDN here https://public-asphr-vm-daemon-bucket.s3.us-east-1.amazonaws.com/sand-host-bundle/sand-host-bundle-latest.tgz . It appears to make a few calls to Cursor’s API to get the signing data and then inject them into Chrome via Chrome DevTools Protocol CDP https://chromedevtools.github.io/devtools-protocol/ : const { response, body } = await fetchWithTimeout this.fetchImpl, this.endpoint, // /sand-box/web-bot-auth-signature { method: "POST", redirect: "error", headers: { authorization: Bearer ${token} , "content-type": "application/json", }, body: JSON.stringify { url: origin } , }, this.timeoutMs, readSigningResponseBody, ; js consideredOrigin = requestUrl.origin; const signed = await signer.getHeaders { origin: requestUrl.origin } ; if signed = null && isSigningCandidate { headers = mergeRequestHeaders request.headers, signed.headers ; signatureSource = signed.source; } // ... const continuation = { requestId: params?.requestId }; if headers = null continuation.headers = headers; await browser .send "Fetch.continueRequest", continuation, sessionId .catch = {} ; Alright, but how do we get an auth token to call the API with? My first instinct was to run printenv . However, it didn’t contain the token. This is because in /usr/local/bin/start-exec-daemon they run: unset SAND GATEWAY TOKEN SAND INFERENCE RENEWAL CREDENTIAL SAND EGRESS TUNNEL BEARER This deletes the required token from the environment. However, the sand-web-bot-auth.mjs still needs the token to run. You can get the token by getting the process ID and then dumping the process environment variables: ps -aux | grep sand-web-bot-auth.mjs strings /proc/