---
type: research
title: Sentinel Fingerprint Comparison — Desktop vs OmniRoute
description: The PoW/requirements fingerprint arrays field-by-field — what each client sends, what the server validates, and the probe corrections
tags: [openai, sentinel, fingerprint, pow, protocol, comparison]
timestamp: 2026-08-25
---

# Sentinel Fingerprint — Desktop vs OmniRoute

Part of [openai-research](openai-research.md). 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

1. **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.
2. **Prekey**: desktop composes `gAAAAAC + base64(fingerprint)` **without PoW**; OmniRoute solves its own PoW (empty seed, target `0fffff`, 100k iterations).
3. **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-build` from 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](sentinel-fallback-validation.md)) and the server accepted it (lenient or not enforced for the desktop client).
4. **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)

```ts
// ── 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](chat-submode-protocol.md) — where the fingerprint enters the protocol
- [vendor-analysis](vendor-analysis.md) — the OmniRoute SHA3-512 PoW diverges from the desktop
