BotGuard and SearchGuard, October 2026
Study published in January 2026, updated on October 19, 2026.
The original runtime corpus below is from October 17. The October 18 experiments are summarised at the end of this report and in the study document "Experiments, October 18, 2026"; denominators must not be pooled.
Google’s client-side protection evolves while BotGuard retains major version 41. In March, engines gain iframe and script-loading code. In August, the encoded background-check program grows by around 13%. In September, the background channel is associated with Google Flights.
Evolution of the protection
Dates refer to mechanisms established by this study, not necessarily their initial deployment or a rollout to all users.
| Period | Mechanism |
|---|---|
| October 2024 | BotGuard already uses version 41 |
| January 2025 | Results code handles sg_ss and a no-JavaScript fallback |
| May 2025 | Knitsail intermediate page, SG_SS cookie and navigation restart |
| October 2025 | /sgasync delivers a script, its hash and its program |
| November 2025 | QyE background-check channel |
| January 2026 | ON4 request-triggered check and retry |
| March 2026 | Engines gain iframe and script-loading code |
| July 2026 | Some background-check responses add a module that stores data in localStorage and reads it back on the next visit |
| August 2026 | Four new test families in the background program (declared browser settings, text rendering, pointer precision, WebGPU); encoded program grows by around 13% |
| September 2026 | Background channel associated with Google Flights |
| October 2026 | WebGPU test removed from the background program on October 5 |
Runtime roles
| VM | Presence in nine results pages | Observed role |
|---|---|---|
| Results | 9/9 | Click and touch listeners, visibility and timing; no observed navigator, screen or canvas reads |
| Knitsail | 5/9 | Browser and environment inspection, mouse, keyboard and wheel signals; Validate submissions |
| Advertising | 9/9 | Advertising attestation, including image requests; a distinct token destination |
| YouTube | 2/9 | Attestation inside an embedded player; code and version not preserved |
The four VMs do not occur on every page. Classic results and AI Mode both appear among the pages with knitsail. No scroll listener was observed in the traced sessions. The homepage script was analysed statically; the availability of its code does not provide a runtime trace of its browser reads.
The initial interstitial receives HTTP 200, produces SG_SS and restarts the search. The observed interval from the first search request to the retry is 63–262 ms. An unsuccessful flow can lead through a redirect to /sorry, HTTP 429 and reCAPTCHA. An HTTP status alone does not identify whether a search response contains results or an interstitial.
/sgasync envelope
The client adds 97 to every response byte modulo 256, then decodes UTF-8 and parses the result. This reversible transport transformation is distinct from token encryption.
The responses examined have eight zero-based positions:
| Position | Content |
|---|---|
| 0 | bfkj marker |
| 1 | Six-element array, with five nulls and the JavaScript at index 5 |
| 2 | null |
| 3 | Base64url SHA-256 of the embedded JavaScript |
| 4 | Encoded program, including entry-function prefix |
| 5 | knitsail namespace |
| 6 | null |
| 7 | Auxiliary string whose meaning is not established |
The embedded-script hashes examined match field 3. The engine and the program are separate artefacts. Entry-function prefixes match the first three program characters in the 26 programs captured in the runtime sessions.
Headers and local branch codes
x-sg-e advertises a request-handling mode and client capabilities. The initial captured value is 2,isrpe=1,hcs=1; the VPS pilot also captures 1,isrpe=1,hcs=1. The client preserves mode 1 when requested and otherwise uses 2. isrpe derives from isrpeEnabled or window.sglc.isrpe; hcs derives from hasCaptchaSupport or window.sglc.hcs.
X-Sg-Cs is read from responses. One handler distinguishes prefixes s and a; another tests exact s and a values. The sfl prefix receives special treatment. X-Sg-Ss carries a computed token on a retried request and is distinct from the SG_SS cookie. X-Sorry-Redirect, or a /sorry/index response URL, participates in the CAPTCHA path.
In the examined retry function, local codes mean:
- 0: compute a token and retry with
X-Sg-Ss. - 1: dispatch
sglacte. - 2: dispatch
sglhcteand awaitsglhcte_retrybefore retrying. - 3: return the response without these branches.
These are local branch codes, not confidence scores. Early and deferred wrappers around same-origin fetch/XHR requests communicate through __sg_lite_queue.
Validate message
The nine calls in the initial October 17 corpus are GET requests with a JSON array in the reqpld query parameter. Their responses are [""]; this does not establish acceptance or rejection.
| Message field | Observed content |
|---|---|
| 1, array index 0 | Text token, 1,471–1,544 characters |
| 2, array index 1 | Context; nested field 9 contains a submessage with ei in field 1 |
| 3, array index 2 | Null in the captures; code provides a binary alternative in the same exclusive group as field 1 |
| 4, array index 3 | 3 in every capture; another code path supports 1 and 2 |
Configuration switches
The analysed client derives configuration from bit fields. Its local obfuscated property names are not stable API names:
Obgates setup;Qbchooses synchronous startup versus a one-second wait and an idle callback.Ddcan trigger result production when the page becomes hidden.Bdskips VM result retrieval in its branch.Cdgates submission;vcselects/sgvalidinstead of Validate.bdandcdsupport deferred submission through a DOMContentLoaded callback or an additional one-second delay.Lcandzdcontrol separate step and timing telemetry paths.
Code availability is not evidence that a switch was enabled in every session. The synchronous request path selects ON4, the other loading branch BMW; captured background traffic uses QyE.
Engine and statistics
The engines examined declare version 41 and have extracted round counts of 14, 15 or 16. Constants and loop bounds can be arguments rather than literals. The extractor follows literal call arguments and handles both comparison orientations; reading nearby numbers alone produces incorrect results.
| Local copy | Rounds | Constant |
|---|---|---|
| Results, October 17 | 15 | 2905 |
| Advertising, October 17 | 15 | 2905 |
| Knitsail, October 17 | 16 | 1088 |
| Homepage, October 18 | 15 | 1795 |
The cipher combines addition, rotation and XOR. Its structure alone does not establish identity with a named cipher. Rotation of script hashes and constants does not reveal the server's acceptance window for older tokens.
The statistical routine computes population standard deviation, sqrt(M2/n), using incremental updates. A bounded reservoir also exists. These routines do not establish server-side detection thresholds. Register indices up to 511 are compatible with a 512-slot space; individual register roles cannot be assumed to remain stable across script variants.
Limits
The study distinguishes static code capability, observed execution and server decisions. Knitsail and YouTube inspect accessor integrity and can detect instrumentation. No accessor check was observed for the results and advertising VMs, but that does not guarantee instrumentation had no effect. The server's decision rules, risk scores, acceptance windows and detection effectiveness are not exposed by this analysis.
The published page contains the detailed observation tables and the timeline.
BotGuard / SearchGuard: experiments, October 18, 2026
Separate corpora
- October 17: four sessions, three profiles, nine SERPs, 43 Google documents. The detailed VM-read observations belong to this corpus.
- VPS pilot: 37 trial records plus one extra navigation in an open session. Three records stopped at the IP check before Google. Chromium comparison invalidated by version/control issues.
- Controlled VPS series: 21 navigations, three fresh source profiles and nine retained/deleted-NID pairs, one fixed US VPN exit.
- Offline work: 96 VM replays on four samples (64 initial matrix + 16 random-draw controls + 16 wrapper-preserving controls), plus 48 synthetic controller cases.
Access and session
On the initial Swiss VPN, fresh Camoufox obtained three SERPs after challenge; headed and headless Chrome each recorded three refusals. HTTP without JavaScript remained on a challenge in three trials. On the native VPS exit, fresh Camoufox obtained three SERPs after challenge, headed Chrome three refusals. These are configuration observations, not general success rates.
Controlled series: all three fresh sources obtained SERPs after challenge; nine retained-NID copies obtained direct SERPs; nine deleted-NID copies obtained SERPs after challenge. IP was stable before and after every navigation; observed runtime identity was identical. Eight of nine pairs differed only in NID among cookies actually transmitted; one also differed in __Secure-STRP. The waits of 5/35/120 seconds start at context opening, not SG_SS issuance, and do not establish cookie validity at 30 seconds.
Camoufox binary Firefox 135.0.1-beta.24; Python package 0.4.11; Playwright 1.51.0. Chrome 153.0.8010.52. Cached Chromium 141/revision 1194 mismatched expected missing revision 1161. Query: musée du Louvre site officiel, fr-FR, hl=fr, gl=fr. The controlled series used a fixed US exit despite requesting France; all branches share that condition.
Quality is not certified
All 21 controlled SERPs contain an identified louvre.fr domain. No videos were detected through H3 results, identifiable video-source links/cards or module headings; this heuristic can miss unlabelled cards. Three of nine pairs have disjoint extracted title sets. The homepage-title candidate appears at rank 1 on three pages, rank 7 on seventeen, and is not identified on one. Sitelink presentation also affects extraction.
The six retained-NID pages with the homepage candidate at rank 7 record Validate, while the three retained-NID pages with rank 1 do not within the observation window. This is exploratory: challenged pages also have a low homepage rank without Validate. It is not a global quality classifier.
The pilot’s nineteen captured SERPs also show ranking variation on VPN and native IP, without detected videos. No contemporaneous independent human reference exists; opaque /goto links were not followed. Neither poisoning nor its absence is established. Abundant videos remain a candidate signal, not a proved signature of detection. October 17 YouTube-VM observations belong to a different corpus.
Offline VM controls
Original A/B outputs are stable on all four samples. Bare extraction changes all four outputs. Restoring one missing Math.random draw only restores extracted IoM. Preserving the original wrapper and extracted inner code restores all four outputs; formatting that inner code changes all four again, twice per condition. This supports source-text sensitivity without locating a specific integrity mechanism. Additional accessor hooks leave original outputs unchanged in this offline harness; this does not prove invisible instrumentation online. Immediate about:blank child-frame coverage remains uncertain. No generated token was sent to Google.
All 48 synthetic controller cases match assertions and the reconstruction: totals 4092/4093/4094, old cookie present/absent, write accepted/rejected, ss_cgi true/false, ce=30/0. The strict <4093 transport condition and stale-SG_SS presence check are reproduced. The two-second fallback is a help path, not necessarily VM cancellation. Server acceptance is unknown.
Captured protocol
The pilot records X-Sg-Cs:s then a retry 678 ms later on /async/callback:6761 with added sei and X-Sg-Ss (1072 characters), followed by X-Sg-Cs:a. Method, body and other compared parameters stay identical; response bytes grow from 59 to 260350. Request mode: 1,isrpe=1,hcs=1. HAR does not identify the JavaScript initiating stack.
The controlled series records twelve intermediate documents with ce=30, ss_cgi=false, challenge_version=0, r=1. Its six Validate token lengths are 1403, 1404, 1400, 1424, 1448, 1435; the pilot had 1441 and 1417, versus 1471–1544 in nine initial-corpus calls. No X-Sg-Cs appears in the controlled series. HTTP 200, blank responses and similar token lengths do not establish acceptance.
Limits and retained evidence
Visibility testing was inconclusive: tabs, popup and actual X11 window unmapping never produced document.hidden=true. No valid visible/hidden Google comparison is claimed. Pilot instrumentation and session comparisons had one repetition per branch and unfrozen fingerprints. Existing VPS services remained active. No personal Google account; sequential trials, alternating order, 20-second pauses; explicit refusal ends a trial without switching IP to seek success. Native VPS access was tested sparingly in the pilot, not revisited in phase two.
Flow classes distinguish direct SERP, SERP after challenge, unfinished challenge, refusal and other. Network documents and JavaScript navigations supplement structural/title/link checks. 201 final private capture files were hashed and checked. VPN rotation was restored and recovery timers removed.