Releases: h4ckf0r0day/obscura
v0.1.8
What's Changed
- feat(mcp): add --host flag for MCP HTTP transport bind address by @ousamabenyounes in #254
- Give relList and sandbox their supported tokens by @SGavrl in #256
- perf: DOM read fast paths (constant nodeType, borrowed op reads, base64 table) by @SGavrl in #259
- fix: resolve element .src to an absolute URL (#255) by @SGavrl in #260
- Fix/issues 257 258 by @SGavrl in #261
- perf: bound slow ES modules with a DOM-rendered-aware budget by @SGavrl in #262
- perf: cut RSS with a V8 young-gen cap and optimize-for-size by @SGavrl in #263
- Add --quiet to serve by @SGavrl in #265
- Make AbortSignal a real constructor (prototype, throwIfAborted, events) by @SGavrl in #267
- Stealth profile consistency by @johnnogueira in #269
- Make navigator.geolocation coordinates configurable by @SGavrl in #272
- Drop unused context field from obscura::Page by @SGavrl in #274
- fix(js): implement CSS.supports() feature detection by @fabdelgado in #209
- fix(js): serialize dynamic module imports + re-land base href for SPA lazy chunks (#246) by @zhangyang-crazy-one in #275
- Add Target.targetInfoChanged and DOMSnapshot.captureSnapshot for DOM agents by @SGavrl in #282
- Implement DOM.focus for keyboard input by @SGavrl in #283
- fix(js): add insertAdjacentText/insertAdjacentElement polyfills (#285) by @ousamabenyounes in #286
- Security: block SSRF DNS-rebinding and widen the IP deny-set by @charlesmamane26-sketch in #279
- fix(cookies): normalize SameSite value to title-case on parse by @johnnogueira in #270
- Security: cap MCP HTTP request bodies and add optional Origin allowlist by @charlesmamane26-sketch in #280
- fix(js): console.log(Error) must not trigger Error.prepareStackTrace by @SGavrl in #287
- docs: document new flags, stealth identity vars, MCP/SSRF hardening, and DOM-agent CDP methods by @SGavrl in #288
- fix(stealth): synchronize TLS and JS fingerprints to Chrome 145 by @SGavrl in #289
New Contributors
- @johnnogueira made their first contribution in #269
- @fabdelgado made their first contribution in #209
- @charlesmamane26-sketch made their first contribution in #279
Full Changelog: v0.1.7...v0.1.8
v0.1.7
This release hardens the engine so one page cannot hang, crash, or wedge a worker, adds an embeddable Rust library, and lands a batch of standards and performance work.
Reliability
- V8 watchdog terminates runaway scripts and microtask storms.
- Panic-safe DOM ops, and cyclic DOM mutations are rejected instead of looping forever.
- Per-command CDP deadline so one hung session can't stall the others.
- Scripted fetch/XHR now times out instead of stranding the request.
New
obscuraRust crate: drive the engine in-process (Browser / Page / Element + cookies).- Big WPT conformance gains (DOM, URL, Ranges, FileAPI, Storage, Shadow DOM).
- Faster querySelector, CDP network path, and promise resolution. Still ~12x faster and ~6x lighter than headless Chrome on framework pages.
- Stealth and TLS improvements, multi-arch images (amd64 + arm64), MCP agent skill.
New env knobs
OBSCURA_CDP_COMMAND_TIMEOUT_MS(default 60000,0disables)OBSCURA_FETCH_TIMEOUT_MS(default 30000)
Full changelog: v0.1.6...v0.1.7
v0.1.6
What's Changed
- feat(cli): add --v8-flags plumbing to configure V8 at startup (#130) by @adamma1024 in #131
- docs(readme): document --v8-flags and add Tuning V8 section (#152) by @adamma1024 in #153
- Fix CDP click submit navigation parity by @blockedby in #69
- fix(cdp): keep HTTP control plane reachable while V8 JS evaluation blocks by @ousamabenyounes in #173
- fix(js,dom): add Storage global, CharacterData ChildNode methods, fix remove/isConnected by @ousamabenyounes in #176
- feat(cli): add --dump assets to inventory page sub-resources (124) by @ousamabenyounes in #174
- fix(cdp,js): playwright actionability stubs and objectId resolve by @SGavrl in #178
- fix(mcp): allow browser MCP clients through CORS preflight by @SGavrl in #179
- fix(js,dom): scope element queries, real timers, form/prepend/equal by @SGavrl in #180
- fix(cdp): unblock puppeteer connect, bound Runtime.evaluate, full Tar… by @SGavrl in #181
- fix(net,browser): detect response charset, decode non-UTF-8 pages by @SGavrl in #182
- feat(cdp): implement Network.setCookie + deleteCookies, full field fidelity by @ousamabenyounes in #170
- fix(net): use bundled webpki roots in stealth client (#184) by @SGavrl in #185
- fix(js): Element.attributes, on* event defaults, per-nid getBoundingC… by @SGavrl in #186
- feat: cookie jar persistence + --storage-dir flag + fix HTTP cookie header filtering by @zhangyang-crazy-one in #114
- fix(cdp): page.goto returns Response over Puppeteer and Playwright (#… by @SGavrl in #190
- fix(cdp): allocate fresh execution context ids per isolated world (#192) by @SGavrl in #200
- feat(cli): default V8 heap to 4 GB on 64-bit so heavy SPAs don't OOM … by @SGavrl in #202
- feat(cli): --allow-private-network for localhost development (#33) by @SGavrl in #203
- Fix puppeteer
exposeFunctionend-to-end: real bindings, preload timing, URL coercion by @marcbachmann in #166
New Contributors
- @blockedby made their first contribution in #69
- @marcbachmann made their first contribution in #166
Full Changelog: v0.1.5...v0.1.6
v0.1.5
Security release
Three advisories closed, no behavior changes for the common HTTP scraping path. Upgrade is recommended for anyone running obscura serve against untrusted input or on a network-reachable port.
Fixed
-
GHSA-6pj9-j389-226p: a page on http(s) could set
window.onload, assignlocation.href = "file:///..."and readdocument.bodyfrom the loaded local file because the JS runtime was reused across navigations.JS-initiated cross-scheme nav into
file://is now refused, and the V8 realm is rebuilt per navigation so window state from the prior page does not survive.Reported by @byte16384.
-
GHSA-4789-rq5x-jv3c: three findings.
-
Sub-resource fetches (
<script src>,<link rel=stylesheet href>) had no scheme gate, so an http page could include<script src="file:///etc/passwd">and the body came back as script source. Sub-resources now have to match the page's scheme family. -
CSS pulled from the network was string-formatted into a JS template literal with a partial escaper that did not handle U+2028 / U+2029, letting attacker CSS break out and run arbitrary code in V8. Escape is now thorough.
-
JS-driven navigation chains capped at ten steps but returned
Ok(())when the limit was hit. They now returnPageError::TooManyRedirects.
Reported by @linuxdevel.
-
-
GHSA-q55h-vfv9-qcr5: anyone able to reach the CDP port could send:
Page.navigate {"url":"file:///etc/shadow"}and read any file the obscura process can read.
The CDP path now refuses
file://by default. Pass--allow-file-accesstoobscura servewhen local-HTML testing is the intended workflow.The CLI
obscura fetch file://...path is unaffected because it does not go through the CDP server.Reported by @UserB1ank.
Upgrade notes
If you currently rely on a CDP client (Playwright, Puppeteer, custom) to navigate to file:// URLs against obscura serve, add --allow-file-access to your serve command.
The flag prints a startup warning so the relaxed posture is visible in logs.
Thanks
Three independent security researchers found and reported these:
🐳 v0.1.4: MCP + Docker
Major features
MCP server (#65)
obscura mcp exposes 12 browser tools over Model Context Protocol with both stdio and HTTP transports. Drop into Claude Code, Cursor, Aider, or any MCP client to drive Obscura directly from an AI agent. No Playwright glue code needed.
Tools: browser_navigate, browser_snapshot, browser_click, browser_fill, browser_type, browser_press_key, browser_select_option, browser_evaluate, browser_wait_for, browser_network_requests, browser_console_messages, browser_close.
Docker support
Official image on Docker Hub. Multi-stage build on distroless/cc, around 57 MB compressed, no shell, no package manager.
docker run -d -p 127.0.0.1:9222:9222 h4ckf0r0day/obscuraFuture releases auto-publish to Docker Hub via GitHub Actions.
--host flag for obscura serve
Defaults to 127.0.0.1 for safety (loopback only). Set --host 0.0.0.0 to expose the port externally, which is what the Docker image does internally so docker run -p 9222:9222 actually works.
Compatibility
Works as a drop-in CDP replacement for:
- Playwright via
connect_over_cdp - Puppeteer via
browserWSEndpoint chromiumoxideandheadless_chrome(Rust CDP clients)- Any MCP client
Install
# Docker (new)
docker run -d -p 127.0.0.1:9222:9222 h4ckf0r0day/obscura
# Binary (Linux, macOS arm64, macOS Intel, Windows)
# See assets below or the READMEClosed issues
v0.1.3
What's new
Reliability
- V8 fatal crash fixed: process no longer aborts under concurrent CDP work with
Fetch.enable(Check failed: heap->isolate() == Isolate::TryGetCurrent()). (#36, closes #19) - CDP fast-path for Puppeteer connect:
Target.getBrowserContextsno longer waits behind the JS engine queue. (#120, partial #62)
Stealth & networking
- Stealth build fixed on macOS arm64 + Rust 1.95:
wreq'sprefix-symbolsfeature gated to Linux/Android only. (#106, closes #39) - Stealth build fixed on macOS 26 (Tahoe): Cargo config sets
CXXFLAGS/SDKROOTsoboring-syscan find libc++ headers. (#138, closes #136) --proxyworks in stealth mode: stealth HTTP client now receives the proxy URL. (#141)--proxyplumbed throughfetchandscrape: global flag now applies to all CLI commands. (#88)
CDP compatibility
- Rust CDP clients work:
Target.sendMessageToTargetimplemented;chromiumoxideandheadless_chromecan connect. (#83, closes #26) - Descriptive error for
Page.printToPDF: explains PDF isn't supported with workaround pointer. (#112, closes #53)
CLI improvements
--dump markdown: clean markdown output from rendered pages. (#78, closes #54)--dump textstrips nav/header/footer/aside: returns article content, not menus. (#82, closes #55)fetch --output <file>: write results to file. (#95)fetch --quietsuppresses JS console errors: was leaking through to stderr. (#74, closes #56)scrape --quiet: suppress progress messages. (#91)obscura scrapeworks on Windows: was looking forobscura-workerinstead ofobscura-worker.exe. (#140)
Build & release
- Zero build warnings: from 18 on v0.1.2 to 0. (#126, closes #101)
- Intel macOS build cross-compiles from arm64 runner: no more slow
macos-13queue.
Docs & ecosystem
- AI agent skill file:
skills/obscura/SKILL.mdfor Claude Code, Cursor, etc. (#34) - Arch Linux AUR install:
yay -S obscura-browser. (#134)
Known issues
- #107: Playwright's
page.title()/page.content()fail wire validation on certain pages withexpected string, got object. Workaround in the issue. Under investigation.
Closed issues
v0.1.2
What's new
Better Puppeteer / Playwright compatibility
Target.attachToBrowserTarget— Playwright's connect handshake now completes (#81, closes #64)Auditsdomain accepted as no-op — no more "Unknown domain: Audits" (#80, closes #57)Page.getLayoutMetrics— returns viewport so screenshot calls don't fail (#79, closes #52)Target.sendMessageToTarget— supportschromiumoxideandheadless_chromeRust clients (#83, closes #26)Fetch.enableactually enables interception (was a no-op) (#50, closes #49)--user-agentflag now plumbed through CDP server (#76, closes #71)
DOM/JS shim improvements
CharacterData,Text,Commentclasses properly defined — fixes sweetalert.min.js, jQuery DataTables (#73, closes #35, #72)WebAssembly.instantiateStreamingworks —Response.arrayBuffer()preserves binary bytes (#48)document.createEvent('CustomEvent')+initCustomEvent— fixes Starbucks China bundle (#77, closes #41)document.elementFromPoint/elementsFromPointstubs — fixes Google Publisher Tag and analytics (#75, closes #63)window instanceof Windowworks (#48)<template>.content/ DocumentFragment querySelector (#48)
Accessibility
Accessibility.getFullAXTreereturns proper tree with roles, names, and parent IDs (#44, #67, closes #12)
CLI
--timeoutflag forobscura fetchto bound navigation time (#92)obscura scraperejects empty URL list and zero concurrency with clear errors (#93, #96)
Networking
Release & build
- Release archives now include
obscura-worker(#94, addresses part of #39) - Linux release built on Ubuntu 22.04 for GLIBC 2.35+ compatibility (#87)
- License metadata corrected to Apache-2.0 in Cargo.toml (#89)
Closed issues
#12, #26, #35, #41, #49, #52, #56, #57, #61, #63, #64, #71, #72, #99
v0.1.1
Fixes
- Load balancer no longer panics on unwrap; /json round-robins through workers; dead workers return 502 instead of silent drops (#1, #2, #3)
- --stealth flag actually takes effect in serve mode; log message reflects what's compiled in (#5)
- Shadow DOM polyfill no longer throws TypeError on parentNode assignment (Cloudflare Turnstile and similar) (#15)
v0.1.0
Update release.yml