The browser engine is an ambitious, well-structured codebase implementing a full browser stack from TCP/TLS through rendering and JavaScript execution. The architecture follows clean patterns (pipeline observers, state machines, graceful headless degradation) and has strong type safety. However, the review uncovered 12 critical issues spanning security vulnerabilities (cookie SameSite bypass, certificate validation weaknesses, XSS in FormAutomation), correctness bugs (timers never firing, string concatenation broken, innerHTML not parsing HTML), and architectural mismatches (TCP header parsing on application-layer data). Many API-layer methods are cosmetic — returning fake data or silently no-op-ing while reporting success.
-
setTimeout/setIntervalcallbacks never fire (engine/javascript/WindowObject.ts:178–218) — Timer implementations schedule native timers but the callback body is() => {}. The captured JS callback is stored but never invoked. All timer-dependent JS behavior silently breaks. -
ADD instruction does not handle string concatenation (
engine/javascript/IgnitionInterpreter.ts:396–404) —executeADDalways callstoNumber()on both operands."hello" + " world"producesNaNinstead of"hello world". Breaks any JS using+for strings. -
innerHTMLsetter does not parse HTML (engine/javascript/DOMBindings.ts:1011–1023) — SettinginnerHTMLcreates a single text node containing the raw HTML string rather than parsing it into a subtree. Breaks React, templates, and any code injecting HTML via innerHTML. -
isTopLevelNavigationalways returnstrue(engine/storage/CookieManager.ts:303–307) — MakesSameSite=Laxcookies equivalent toSameSite=None. Cross-site sub-resource requests receive Lax cookies, violating the SameSite spec. -
isPublicSuffixuses a hardcoded 8-entry list (engine/storage/CookieManager.ts:327–331) — Onlycom,org,net,edu,gov,mil,co.uk,co.jp. An attacker can set supercookies covering entire country TLDs like.uk,.io,.de. -
OAuth2 flows return hardcoded fake tokens (
api/AuthenticationManager.ts:483,514,543,595) —oauth2ClientCredentials(),oauth2Password(), etc. all return"simulated_access_token". Returns{ success: true }with fabricated tokens that fail against any real auth server. -
JavaScript injection in FormAutomation file upload (
api/FormAutomation.ts:917–947) —uploadFile()embedsfieldSelectordirectly into JS strings via concatenation.escapeSelector()does not escape backticks, null bytes, or Unicode escapes. Exploitable with crafted selectors or filenames. -
refresh()callsoauth2RefreshToken()with emptyclientId/tokenUrl(api/AuthenticationManager.ts:700–706) — Reconstructs credentials withclientId: ""andtokenUrl: "". The stored session's original values are never captured. -
parseTCPSegmentcalled on application-layer socket data (engine/network/primitives/TCPConnection.ts:321) —receiveSegment()reads from an OS TCP socket and attempts to parse TCP headers from the data. OS TCP stacks strip headers before delivering to userspace — this interprets payload bytes as headers, corrupting all sequence/ACK processing. -
serializeTCPSegmentsends segments with zero checksum (engine/network/primitives/TCPConnection.ts:293–297) —serializeTCPSegmentWithChecksum()exists but is never called insideTCPConnection. Every outgoing TCP segment has checksum zero. -
GPU.composite()loop body is a no-op (os/graphics/GPU.ts:168–186) — The method creates a render pass, iterates layers, but never issues a draw call. The render pass clears to white and ends immediately. The core compositor entry point produces blank frames. -
Timer leak in
DNSCache— no cleanup on destruction (engine/network/resolution/DNSCache.ts:134) — 60-secondsetIntervalstarted in constructor. Nodestroy()/dispose()method, andRequestPipeline.close()never callsstopAutoCleanup(). Every pipeline instance leaks an interval timer indefinitely.
-
authenticateCookie()never sets cookies on the browser (api/AuthenticationManager.ts:348–371) — StoresCookieConfigin the session but never calls any cookie-injection API. Returns{ success: true }. -
waitForNavigationOrTimeout()caps wait at 1000ms (api/FormAutomation.ts:839–842) —Math.min(timeout, 1000)ignores the caller's configured deadline. Form submissions on slow networks fail spuriously. -
BrowserEnginedefaultsenableJavaScript: false(api/BrowserEngine.ts:31) — Primary entry point for query engine and MCP server operates in no-JS mode unless explicitly overridden. SPAs and auth flows silently break. -
BrowserEngine.newPage()never pushes tothis.pages(api/BrowserEngine.ts:41–44) — Thepagesarray is always empty. Tab/page tracking is broken. -
HARRecorder.shouldRecord()compiles new RegExp on every call (api/HARRecorder.ts:659,669) — Creates thousands of redundant regex compilations in long recording sessions. -
VisualTester.checkVisibility()reads inline styles, not computed styles (api/VisualTester.ts:432–434) — Elements hidden via stylesheet rules reportvisible: true. False positives in visual test assertions. -
HARPlayercookie/auth restoration are no-ops (api/HARPlayer.ts:706–712, 726–731) —applyCookiesFromHAR()andapplyAuthFromHAR()store data but never call any page API. -
IsolateManagersingleton leaks stale isolates (engine/javascript/V8Isolate.ts:389–403) — No cleanup path. Each isolate starts a background GCsetIntervalthat fires forever on orphaned isolates. -
CookieManagercleanup interval leaks withoutdispose()(engine/storage/CookieManager.ts:33–35) — Constructor starts 60-second interval. NoSymbol.disposesupport. -
querySelector/querySelectorAllonly support trivial selectors (engine/javascript/DOMBindings.ts:1563–1608) — Only#id,.class, tagName,*. Attribute selectors, combinators, pseudo-classes all return null/empty. Modern frameworks fail silently. -
Tree navigation properties are static snapshots (
engine/javascript/DOMBindings.ts:658–700) —parentNode,childNodes, etc. copied at wrap time. DOM mutations don't update already-wrapped nodes. DOM spec requires live references. -
structuredCloneonly shallow-copies (engine/javascript/WindowObject.ts:334–359) — Nested objects are shared, not cloned. Post-clone mutations corrupt the "clone". -
dispatchEventignores non-native listeners (engine/javascript/DOMBindings.ts:1062–1074) — Only invokesnativeImplfunctions. User-registered JS callbacks are silently skipped. -
crypto.getRandomValuesreturns empty object (engine/javascript/WindowObject.ts:516–522) — Returns{ length: 16 }with no random bytes. Cryptographic operations get all-zero data. -
OCSP requests use zero-byte issuer hashes (
engine/network/security/Certificate.ts:213–214) — Revocation checking sends 20 zero bytes. Responders can't match certificates; all checks pass silently. -
Certificate root validation uses subject+serial only (
engine/network/security/Certificate.ts:66) — No public key comparison. Crafted certificates with matching subject strings pass root validation. -
parseOIDreturns"RSA-SHA256"for unknown OIDs (engine/network/security/Certificate.ts:1021) — Security-critical code silently falls back to wrong algorithm instead of failing. -
User-agent leaks "GeoProx-Browser/1.0" (
engine/RequestPipeline.ts:693,engine/javascript/WindowObject.ts:249,main.ts:511) — Internal codename sent to every server and printed on startup. Should be "BrowserX". -
Connection not released to pool on error (
engine/RequestPipeline.ts:530–539) — Error paths never callconnectionPool.release(). 6 consecutive errors exhaust the pool permanently. -
systemCACacherace condition (engine/network/security/Certificate.ts:558) — Module-levelletwith no mutex. Concurrent first-time calls produce duplicate reads and non-atomic writes. -
OSSocket.connect()leaks previous connection (os/networking/NetworkStack.ts:46–76) — Connecting an already-connected socket overwritessocket.connwithout closing the old one. -
Browser.navigate()leaves stale URL on failure (main.ts:86–88) — History updated before render;currentURLupdated after. On failure,reload()andback()/forward()are inconsistent. -
Incompatible
LayerIDtypes inrendering.tsvswebgpu.ts— One is plainstring, other is branded. Both exported fromtypes/. -
Duplicate
HTMLCanvasElement/CanvasRenderingContext2Ddefinitions —dom.ts(30+ methods) andwebgpu.ts(5 methods) define different shapes. Callers get different types depending on import source.
-
WebScraper.extractByRule()queries global document per rule (api/WebScraper.ts:306) — Queries entire page then filters viaroot.contains(). O(n) extra work and breaks for duplicate selectors. -
PDFGenerator.estimatePageCount()decodes binary PDF as UTF-8 (api/PDFGenerator.ts:371–374) —TextDecodercorrupts multi-byte sequences; regex matches may be wrong. -
PerformanceProfiler.getMemoryInfo()returns fabricated data (api/PerformanceProfiler.ts:555–565) —usedJSHeapSize: totalResourceSize * 3. DOM node and CSS rule counts always 0. -
FormAutomation.fillSelectField()always fails (api/FormAutomation.ts:694–700) — Clicks<option>elements directly instead of setting.value. Catch block swallows errors. -
VisualTester.screenshot()restore bug (api/VisualTester.ts:190–201) — Only restores first matching hidden element per selector. Others permanently hidden. -
HARRecorder.extractSetCookies()fragile regex (api/HARRecorder.ts:701) — Split regex fails on commas inside cookie dates. -
PerformanceProfiler.getNavigationTiming()hardcoded values (api/PerformanceProfiler.ts:382–384) — DNS=5ms, TCP=15ms, TLS=10ms. Completely synthetic. -
parseUrlfallback setshostname = url(engine/storage/CookieManager.ts:336–352) — Invalid URLs cause domain matching against full URL strings. -
getRegistrableDomainnaive two-part heuristic (engine/storage/CookieManager.ts:312–321) —mail.example.co.ukreturnsco.ukinstead ofexample.co.uk. -
StorageManager.import()bypasses quota tracking (engine/storage/StorageManager.ts:384–401) — Quota manager usage stays stale after import. -
strokeRectmutatesfillStyle(types/dom.ts:737–748) — Canvas shim permanently overwrites fill color when stroking a rectangle. -
getImageData()ignores x/y/width/height (types/dom.ts:773–779) — Always returns full canvas buffer regardless of parameters. -
requestAnimationFrameusesqueueMicrotask(types/dom.ts:835–847) — Fires synchronously in microtask queue instead of frame-rate scheduling. Starves I/O in headless mode. -
Browser.clearData()doesn't clear localStorage (main.ts:244–251) — Only clears sessionStorage. -
paintreads onlyborder-top-*for all four borders (engine/rendering/RenderingOrchestrator.ts:395–402) — Non-uniform borders rendered incorrectly. -
parseTimereturnsnew Date()for unknown tags (engine/network/security/Certificate.ts:1162) — Malformed validity fields appear valid. -
RequestPipeline.requesttimeout leakssetTimeout(engine/RequestPipeline.ts:169–180) — Timer never cleared after successful request. Keeps event loop alive. -
serializeNodedoes not escape text content (engine/javascript/DOMBindings.ts:1795–1797) —<,>,&in text nodes produce invalid HTML viainnerHTML. -
transformToMatrixaddsoriginXtwice (engine/webgpu/compositor/WebGPUCompositorThread.ts:786–787) — Incorrect rendering with non-zero transform origins. -
findElementSiblingcalled twice per install (engine/javascript/DOMBindings.ts:994–1006) — Doubles tree traversal; should useconst. -
cloneNativeNodeproduces non-functionalclassList(engine/javascript/DOMBindings.ts:1874–1883) — Stubadd/removethat don't mutate attributes. -
matches()always returnsfalse(engine/javascript/DOMBindings.ts:617) — RealmatchesSelectorexists but is never wired to created/cloned elements. -
CSP
'none'handling edge case (engine/security/ContentSecurityPolicy.ts:76–87) —'none'among other sources doesn't invalidate the directive as spec requires. -
documentexport is minimal shim (types/dom.ts:825–827) — Exports{ createElement }only. MissinggetElementById,querySelector,body, etc. -
DNSResolver.queryDoHspread operator on large arrays (engine/network/resolution/DNSResolver.ts:226) —btoa(String.fromCharCode(...query))risks stack overflow on large DNS packets.
DOMElement.click()only logs to console (api/BrowserPage.ts:134–138) — No DOM event dispatched.VisualTester.decodePNGToRGBA()uses wrong decompression (api/VisualTester.ts:806) —"deflate"instead of zlib wrapper handling.PDFTemplate.build()injects<style>into header template (api/PDFGenerator.ts:478–481) — No effect on main content.HARPlayer.calculateThrottleDelay()unnecessarily async (api/HARPlayer.ts:451) — Noawait; adds microtask overhead.FormAutomation.executeMultiStepForm()uses:contains()selector (api/FormAutomation.ts:1219) — jQuery-only pseudo-selector; not standard CSS.navigator.userAgentleaks "GeoProx-Browser" (engine/javascript/WindowObject.ts:249) — Internal name in UA string.BrowserConsole.log()maps to"info"level (engine/logging/BrowserConsole.ts:27–29) — Can't distinguishlog()frominfo().- Duplicate event listener code for elements vs documents (
engine/javascript/DOMBindings.ts:1029–1075, 1115–1160) — Nearly identical implementations. IDBTransaction.abort()setsFINISHEDnotABORTED(engine/storage/IDBDatabase.ts:77) — Can't distinguish committed from aborted.StorageManager.clear()emitskey: ""notnull(engine/storage/StorageManager.ts:147–153) — Spec requiresnullfor clear events.DEBUGGERopcode logs to console unconditionally (engine/javascript/IgnitionInterpreter.ts:337–341) — Should notify debugger, not stdout.WebGPUError.tsis effectively empty (engine/WebGPUError.ts) — One line, no exports.deno.jsondisablesnoUnusedLocals/noUnusedParametersand lintno-unused-vars(deno.json:11–12,26) — All dead code detection disabled simultaneously.- Magic hex cipher suite values without named constants (
engine/network/connection/ConnectionPool.ts:384–399) —CipherSuiteenum exists but isn't used. loadSystemCAslogs success toconsole.error(engine/network/security/Certificate.ts:583) — Info message on stderr.parseDERCertificateis 400+ lines with no helpers (engine/network/security/Certificate.ts:652–961) — Difficult to test individual parsing stages.FileSystem.readDir()discards entry type metadata (os/filesystem/FileSystem.ts:125–131) — Returns only names, notisFile/isDirectory.GraphicsContext.renderBitmapChar()renders all chars as identical blocks (os/graphics/GraphicsContext.ts:395–443) — Text is indistinguishable per-character.Window.open()fragile pixpane detection (os/window/Window.ts:52–60) — AnyglobalThis.pixpaneobject triggers non-headless mode.Browserconstructor logs full config unconditionally (main.ts:67–73) — Noisy in tests and library consumers.deno.jsontest glob includessrc/**/*_test.ts(deno.json:47) — No such files exist insrc/.
-
Robust SSRF protection —
URLValidatorcovers all IPv4/IPv6 private ranges, non-HTTP protocols, and dangerous data URIs. Allowlist bypass is clearly scoped and off by default. -
Complete CSP implementation — Handles
'self', wildcard subdomains, scheme sources, nonces, hashes,'unsafe-eval', and report-only mode with full violation context. -
Inline cache for property access —
GET_PROPERTYusesWeakRef-based monomorphic IC, correctly skips getter results, invalidates on writes, and is keyed by bytecode offset. -
Observable pipeline architecture —
PipelineObserver/emitStageprovides consistent external observability across rendering and request pipelines, directly powering the doc-site visualizer. -
Graceful headless degradation — Every GPU-adjacent class (
GPU,Window,GraphicsContext,RenderingPipeline) has explicit headless fallback withisHeadless(). Never throws in headless mode. -
Full PNG decoder from scratch —
VisualTesterimplements complete chunk parsing, all 5 filter types, and 6 color type conversions to RGBA without native dependencies. -
Complete X.509 DER parser with OCSP — Full DER parsing, SAN extraction, AIA/OCSP, ECDSA signature conversion. Substantial cryptographic plumbing.
-
HTTP desync protection —
doRequestrejects multipleContent-Lengthheaders as potential desync attacks. Non-obvious security threat that many implementations miss. -
Cryptographically secure random values —
generateISN()andbuildQuery()usecrypto.getRandomValues(), preventing sequence number and DNS query ID prediction. -
Promise-based connection pool waiters — No busy-polling. Waiters correctly removed on timeout and notified on release.
-
Comprehensive test structure — Test directories mirror source structure precisely. Dedicated test files for Certificate, DNS, ConnectionPool, TCP, FileSystem, GPU, GraphicsContext, and all 14 DevTools domains.
-
Strong type safety — Strict TypeScript config enabled. Branded type identifiers prevent mixing semantically different IDs. Discriminated unions for credentials with exhaustive switches.
-
Well-documented public API —
Browseraccessors have complete JSDoc with@returns,@example, and descriptions. -
AbortSignal cancellation on all async ops — Every async method on
BrowserPageacceptssignal?: AbortSignaland checks it before and after operations. -
Robust headless software renderer — Implements alpha blending, Bresenham lines, scanline polygon fill, affine transforms, clip bounds, and save/restore state stack.
- Fix JS engine timer callbacks — Wire the stored callback
JSValueinto the native timer's fire function inWindowObject.ts - Implement string concatenation in ADD — Check operand types before defaulting to numeric addition in
IgnitionInterpreter.ts - Parse HTML in innerHTML setter — Invoke the HTML tokenizer/tree builder for fragment parsing in
DOMBindings.ts - Fix TCP architectural mismatch — Either use raw sockets (if available) or remove the TCP header parsing layer that operates on application-layer data
- Implement real OAuth2 token exchange — Replace fake tokens with actual
fetchcalls to token URLs
- Add
dispose()/Symbol.disposeto all timer-owning classes —DNSCache,CookieManager,V8Isolate,ConnectionPoolall leak intervals - Implement Public Suffix List — Replace the 8-entry hardcoded list to prevent supercookie attacks
- Fix
isTopLevelNavigation— Implement proper navigation detection for SameSite cookie enforcement - Release connections on error paths — Add
finallyblock indoRequestto release pool connections - Enable JavaScript by default in
BrowserEngineconfig - Rename "GeoProx-Browser" to "BrowserX" across all user-agent strings and startup messages
- Consolidate duplicate type definitions — Merge
HTMLCanvasElement,CanvasRenderingContext2D,LayerID,Blobinto single authoritative definitions - Make DOM tree navigation live — Use getters instead of static property copies
- Implement complex CSS selectors — At minimum compound selectors and attribute selectors for framework compatibility
- Wire
GPU.composite()draw calls — Connect the layer iteration loop to actual render pipeline draw commands - Add certificate public key comparison — Root validation should check key material, not just subject strings