Sentinel Fingerprint Comparison — Desktop vs OmniRoute
The PoW/requirements fingerprint arrays field-by-field — what each client sends, what the server validates, and the probe corrections
Sentinel Fingerprint — Desktop vs OmniRoute
Part of openai-research. Sources: desktop renderer (sPr, 24 slots) and OmniRoute (buildPrekeyConfig, 18 slots).
The OmniRoute codebase documents: "Sentinel's prekey check inspects whether config[5]/config[6] reference a real chatgpt.com deployment (DPL hash + a script URL from the HTML)" — which is why it scrapes the public site HTML every hour.
Slot-by-slot comparison
| Slot | Desktop (sPr) | OmniRoute (buildPrekeyConfig) |
|---|---|---|
| 0 | screen.width + screen.height | pick([3000, 4000, 3120, 4160]) |
| 1 | new Date().toString() | same |
| 2 | performance.memory.jsHeapSizeLimit (real, ~2.2GB) | 4294705152 fixed |
| 3 | Math.random() → solver mutates = counter | 0 → solver mutates = counter |
| 4 | navigator.userAgent (real Chromium webview) | configured UA |
| 5 | pick(real webview script srcs) | scriptSrc REAL from the site (scraped) |
| 6 | match c/[^/]*/_ in scripts, else data-build | DPL hash REAL from the site (scraped) |
| 7-8 | navigator.language / languages | "en-US" / "en-US,en" |
| 9 | Math.random() → solver mutates = time | 0 → solver mutates = time |
| 10 | cPr() (random navigator prototype property + value) | pick(NAVIGATOR_KEYS) (e.g. webdriver−false) |
| 11-12 | pick(keys(document)) / pick(keys(window)) | same |
| 13 | performance.now() | same |
| 14 | uuid | randomUUID() |
| 15 | search params join | "" |
| 16 | hardwareConcurrency | pick([8, 16, 24, 32]) |
| 17 | performance.timeOrigin | Date.now() - perfNow (epoch offset) |
| 18-23 | flags: ai/createPRNG/cache/data/solana/dump/InstallTrigger in window | — (absent) |
Structural divergences
- Hash: desktop = FNV-1a 32-bit murmur-finalized; OmniRoute = SHA3-512. Mutually exclusive — the server accepts one or the other per client/route. Primary source (desktop) = FNV-1a.
- Prekey: desktop composes
gAAAAAC + base64(fingerprint)without PoW; OmniRoute solves its own PoW (empty seed, target0fffff, 100k iterations). - Slots 5/6 (deployment): OmniRoute documents server-side validation against the real site deployment (DPL + script URL). The desktop sends local webview scripts + the
data-buildfrom index.html. RESOLVED at runtime (2026-08-26): the placeholder<!-- PROD_BUILD_TAG_HERE -->IS the value that leaves the client (real fingerprint, slot 6 — see sentinel-fallback-validation) and the server accepted it (lenient or not enforced for the desktop client). - Size: 24 slots on desktop vs 18 on OmniRoute.
Probe corrections applied (openai-chat-submode-flow.ts)
Fingerprint aligned to the desktop: slot 5 = a real webview chunk (index-rLYmMQgS.js — the only script in the index), slot 6 = the data-build attribute value (value TBD by runtime check), slot 2 = real Electron heap size, slots 10-12 = plausible navigator/document/window properties, slots 18-23 = zeros (flags absent outside a browser).
TypeScript types (the two builders)
// ── desktop (renderer sPr) ───────────────────────────────────────────────
export interface DesktopFingerprintBuilder {
(): FingerprintArrayV24 // see sentinel-fallback-validation types
/** gAAAAAC + base64(fingerprint) — WITHOUT PoW. The prekey. */
prekey: (fingerprint: FingerprintArrayV24) => string
/** FNV-1a 32-bit murmur-finalized — the desktop hash family. */
hash: (input: string) => string
}
export interface FingerprintArrayV24 extends Array<unknown> { [k: number]: unknown }
// ── OmniRoute (buildPrekeyConfig) ────────────────────────────────────────
export interface OmniRouteConfig {
slots: [
number, // pick([3000, 4000, 3120, 4160])
string, // new Date().toString()
number, // 4294705152 FIXED (vs real heap — a detectable deviation)
number, // counter (solver-mutated)
string, // configured UA
string, // real scriptSrc SCRAPED from the site
string, // DPL hash SCRAPED from the site
string, // 'en-US'
string, // 'en-US,en'
number, // time (solver-mutated)
string, // pick(NAVIGATOR_KEYS)
unknown, unknown, // keys(document)/keys(window)
number, // performance.now()
string, // randomUUID()
string, // ''
number, // pick([8, 16, 24, 32])
number, // Date.now() - perfNow (epoch offset)
] // 18 slots (vs 24 desktop)
PoW: 'SHA3-512' // 100k iterations, target '0fffff' — DIFFERENT family from desktop
prekey: string
}
export interface OmniRouteHash {
(input: string): string // SHA3-512 — mutually exclusive with the desktop's FNV-1a
}
Cross-references
- chat-submode-protocol — where the fingerprint enters the protocol
- vendor-analysis — the OmniRoute SHA3-512 PoW diverges from the desktop