Skip to content

Releases: h4ckf0r0day/obscura

v0.1.8

11 Jun 18:55
f58bb45

Choose a tag to compare

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

Full Changelog: v0.1.7...v0.1.8

v0.1.7

06 Jun 16:00
94bd2cc

Choose a tag to compare

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

  • obscura Rust 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, 0 disables)
  • OBSCURA_FETCH_TIMEOUT_MS (default 30000)

Full changelog: v0.1.6...v0.1.7

v0.1.6

29 May 18:23
c9f32aa

Choose a tag to compare

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 exposeFunction end-to-end: real bindings, preload timing, URL coercion by @marcbachmann in #166

New Contributors

Full Changelog: v0.1.5...v0.1.6

v0.1.5

14 May 21:55
7b209dc

Choose a tag to compare

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, assign location.href = "file:///..." and read document.body from 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 return PageError::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-access to obscura serve when 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

13 May 22:36
a750797

Choose a tag to compare

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/obscura

Future 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
  • chromiumoxide and headless_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 README

Closed issues

#119

v0.1.3

13 May 21:06
f1cbd58

Choose a tag to compare

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.getBrowserContexts no longer waits behind the JS engine queue. (#120, partial #62)

Stealth & networking

  • Stealth build fixed on macOS arm64 + Rust 1.95: wreq's prefix-symbols feature gated to Linux/Android only. (#106, closes #39)
  • Stealth build fixed on macOS 26 (Tahoe): Cargo config sets CXXFLAGS/SDKROOT so boring-sys can find libc++ headers. (#138, closes #136)
  • --proxy works in stealth mode: stealth HTTP client now receives the proxy URL. (#141)
  • --proxy plumbed through fetch and scrape: global flag now applies to all CLI commands. (#88)

CDP compatibility

  • Rust CDP clients work: Target.sendMessageToTarget implemented; chromiumoxide and headless_chrome can 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 text strips nav/header/footer/aside: returns article content, not menus. (#82, closes #55)
  • fetch --output <file>: write results to file. (#95)
  • fetch --quiet suppresses JS console errors: was leaking through to stderr. (#74, closes #56)
  • scrape --quiet: suppress progress messages. (#91)
  • obscura scrape works on Windows: was looking for obscura-worker instead of obscura-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-13 queue.

Docs & ecosystem

  • AI agent skill file: skills/obscura/SKILL.md for 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 with expected string, got object. Workaround in the issue. Under investigation.

Closed issues

#19, #26, #39, #53, #54, #55, #56, #101, #108, #136, #140

v0.1.2

03 May 15:49
536072b

Choose a tag to compare

What's new

Better Puppeteer / Playwright compatibility

  • Target.attachToBrowserTarget — Playwright's connect handshake now completes (#81, closes #64)
  • Audits domain 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 — supports chromiumoxide and headless_chrome Rust clients (#83, closes #26)
  • Fetch.enable actually enables interception (was a no-op) (#50, closes #49)
  • --user-agent flag now plumbed through CDP server (#76, closes #71)

DOM/JS shim improvements

  • CharacterData, Text, Comment classes properly defined — fixes sweetalert.min.js, jQuery DataTables (#73, closes #35, #72)
  • WebAssembly.instantiateStreaming works — Response.arrayBuffer() preserves binary bytes (#48)
  • document.createEvent('CustomEvent') + initCustomEvent — fixes Starbucks China bundle (#77, closes #41)
  • document.elementFromPoint / elementsFromPoint stubs — fixes Google Publisher Tag and analytics (#75, closes #63)
  • window instanceof Window works (#48)
  • <template>.content / DocumentFragment querySelector (#48)

Accessibility

  • Accessibility.getFullAXTree returns proper tree with roles, names, and parent IDs (#44, #67, closes #12)

CLI

  • --timeout flag for obscura fetch to bound navigation time (#92)
  • obscura scrape rejects empty URL list and zero concurrency with clear errors (#93, #96)

Networking

  • Cookies with leading-dot domains now match outgoing requests correctly (#100, closes #99)

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

25 Apr 12:36

Choose a tag to compare

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

13 Apr 10:46

Choose a tag to compare

Update release.yml