On Tue, Oct 20, 2026 at 08:48:52AM -0500, Andreas Røsdal wrote: > Thank you for your feedback. I would appreciate feedback from more people > to get a more nuanced and neutral view, > preferably from someone who actually works on real software development in > 2026, someone with education in computer science, > also considering that software development has changed with the > introduction of AI llms.
Normally I tend not to do the full brag sheet, since I believe that technical arguments should not be resolved using argumentation by credentials / authority. But since you asked.... (and for more details feel free to look at the Wikipedia entry describing my humble self, although it is a bit outdated these days :-). I graduated from MIT in 1990 with a degree in Computer Science and Electrical Engineering, with a specialization in Computer Science and a minor in Economics. I was the first North American Linux Kernel developer, and am currently serving as the ext4 file system maintainer, so I've been working on the Linux kernel for 35 years. I have also served on the Internet Engineering Task Force, as one of the working group chairs for the IP Security Working Group, and was one of the members of the Security Area Directorate. In my day job, I am one of the senior technical leads on my employer's data center kernel team, where we have teams working on agentic-aided kernel review (Sashiko), agentic cherry-picking and merge conflict resolution. agentic-assisted kernel debugging, and agentic assisted kernel live-patching. I personally use Large Language Models in my work. For example, just recently I created a prompt[1] to create LLM-generated Kernel Unit tests[2]. [1] https://lore.kernel.org/all/[email protected]/2-writing-kunit-tests.md [2] https://lore.kernel.org/all/[email protected]/ So with my credentials established... 1. I agree with the concerns expressed by others, most notably by Gard Spreemann. 2. It seems strange that you have recently established a "No AI" policy starting in October 2026, given that previous to that pretty much all of the code base was created using AI. Why is that? (There was also a commit that was authored by Claude *after* the no AI policy, although it appeared to be deleting tests.) 3. I didn't see any tests in the repo, which was strange. Maybe they are located elsewhere? I *hope* they were used as part of the agentic coding loop, but why did you recently delete the cute-tests directory? 4. The use of C instead of Rust for a software package where you are starting from scratch and which was vibe coded was strange. Rust allows the compiler to find many bugs autpomatically, which is really useful for agentic code harnesses. It's especially interesting when you try to claim that it is more secure than all other browser code bases, apparently because AI(tm) and because it was coded from scratch, since C is susceptible to use-after-free bugs (for a not-hypothetical example). 5. Because I'm a paranoid SOB, and given your hyperbolic security claims, I decided to run a little experiment. So I asked a frontier model developed by my employer, "Look for potential security issues in the Northstar Web Browser. Not just whether it adheres to the security model found in SECURITY.md but also look for the possibility of deliberate back doors that were introduced by the authors." 5 subagents, 4 million uncached input tokens, 14.5 million cached input tokens, and 217k output tokens later, I received the report which I've attached as FINDINGS.md. It is also available here[3] which may be easier for people to read. [3] https://docs.google.com/document/d/1sNxSNDpsaLXO-WsKpeKCWajH1nfCkjLg/edit#heading=h.kkp50pksh0c7 The short version is that multiple severe security vulnerabilities were found, including multiple use-after-free that could be used to attack a user using the Northstar browser. The "Arbitrary Local File Disclosure from JS" was also somewhat amusing given the assertions that this was more secure than Firefox and Chrome. As a result, I would **not** recommend that any user depend on Northstar Browser if they cared about their security. And perhaps the Debian FTP Masters might want to take this into consideration when deciding whether or not to accept this package in its current form, and whether the Debian release team would be willing to release it as part of a future Debian Stable release. I'd also recommend that you consider rescinding your "No AI policy" and get help from your AI agents to fix the 8 Critical, 7 High, 3 Medium, and 1 Low severity vulnerabilities identified in FINDINGS.md[3]. Cheers, - Ted
# Northstar Web Browser — Comprehensive Security & Backdoor Audit (`FINDINGS.md`) **Target Repository:** `/home/tytso/northstar-web-browser` **Audited Commit:** `a2a1a136cffe0e126cdd3848dbfe786f6f433c45` (`HEAD`, `main`) **Audit Date:** 2026-10-23 **Scope:** Full source tree (`src/`, `subprojects/`, `scripts/`, `debian/`, `data/`, `.github/`), [SECURITY.md](file:///home/tytso/northstar-web-browser/SECURITY.md) verification, and complete Git object/commit history (`git fsck --full`, reflogs, all branches). --- ## Executive Summary Northstar (formerly Nordstjernen) does **not** provide a functional security boundary against untrusted web content. Because the browser runs UI chrome, network stacks, storage backends, and all web origins inside a **single OS process** and relies on ad-hoc JavaScript property conventions and URL string checks to enforce isolation, single logic flaws collapse the entire browser security model. Our audit reached three overarching conclusions: 1. **No Obfuscated C2 Implant or Cryptographic Backdoor, But Serious Undocumented Hooks & Project Deception:** - We found **no covert remote command-and-control (C2) beacon, reverse shell, obfuscated payload, or rigged RNG/WebCrypto primitive** in the C source code, bundled JavaScript (`data/js/polyfills.js`, `data/js/wpt-hook.js`), subproject patches (`subprojects/packagefiles/*`), or Git object store. - However, we found **undocumented production environment hooks** that act as local persistence or silent security-bypass primitives (`NS_EARLY_JS_FILE` injects arbitrary local JS into every page's main world; `NS_CAMERA_ALLOW=1` silently grants webcam access to all sites; `NS_EXTENSIONS_DIR` autoloads unpacked extensions; `NS_NO_SANDBOX=0` disables the sandbox because `g_getenv()` only checks for non-`NULL`). - We also uncovered **deceptive project claims and history manipulation**: on October 22, 2026 (`520c7be`), the author deleted `.claude/` (which had `"defaultMode": "bypassPermissions"`), `CLAUDE.md`, and `AGENTS.md` and added a *"No AI Policy"* to `README.md` claiming no AI-generated code is accepted—only for the very next commit (`a2a1a13`, `HEAD`, two hours later) to carry `Co-Authored-By: Claude Opus 5.5 <[email protected]>`. Furthermore, the advertised Safe Browsing blocklist (`data/safebrowsing.list`) is a 4-entry dummy file, and packaging scripts hijack `/usr/bin/internet-browser` and download unverified binaries over mutable URLs. 2. **Major Discrepancies Between `SECURITY.md` and the Actual Codebase:** - `SECURITY.md` explicitly claims `<video>` only decodes MPEG-1 (`pl_mpeg`) with *"no MP4/ISO-BMFF or WebM/Matroska container demuxers, no H.264/HEVC/VP8/VP9/AV1 codecs, no adaptive-streaming (MSE / HLS / DASH) state machines"*, and that `<audio>` only decodes MP3 and Ogg Opus/Vorbis. In reality, Northstar compiles a **1,565-line hand-rolled MP4/fMP4 demuxer (`src/mp4.c`)**, a **1,249-line hand-rolled WebM demuxer (`src/webm.c`)**, a **1,735-line hand-rolled AAC-LC decoder (`src/audio/aac.c`)**, a **745-line MSE engine (`src/mse.c`)**, **AV1, VP9, and H.264 video decoders**, and **V4L2 `/dev/video*` webcam capture (`src/camera.c`)**—none of which are disclosed in `SECURITY.md`. 3. **8 Critical and 8 High-Severity Exploitable Vulnerabilities:** - **Arbitrary Local File Disclosure from JS:** Bypassing `ns_attr_name_is_internal` via `setAttributeNode()` or `DOMParser` (`data-nd-file-path` on `<input type="file">`) lets any webpage read arbitrary local files without user interaction. - **Universal Cross-Site Cookie Read/Write:** `iframe.contentDocument.URL` is a writable JS property (`JS_PROP_C_W_E`) trusted by `document.cookie` to select the cookie partition. - **Complete Cross-Origin & Sandboxed `<iframe>` Escape:** Parent pages can read `iframe.__ndRealmDoc` and `iframe.__ndRealmWindow` directly; child scripts in `<iframe sandbox="allow-scripts">` can escape to the parent window via copied parent constructors (`HTMLElement.constructor("return window")()`). - **Universal CSRF Defense Bypass:** `ns_page_session_open` strips `referrer` (`top_url`) to `NULL` on cross-origin navigations, causing cross-site `POST` form submissions to forge `Origin: <target-origin>`, `Sec-Fetch-Site: none`, and `Sec-Fetch-User: ?1` with first-party cookies attached. - **Browser Settings Takeover & File Navigation via `northstar-unsafe-continue:`:** `browser_allows_navigation_url` fails to block `northstar-unsafe-continue:`, allowing any webpage to POST to `northstar-unsafe-continue:about:settings-save` (overwriting `~/.config/northstar/northstar.conf`, including `doh_url` and `home_url`) or navigate to `file://` URLs. - **Memory Corruption Primitives:** Deterministic Heap Use-After-Free in `ns_js_buffer_source_bytes` (leaking raw freed heap memory into JS strings via `TextDecoder`), Heap Buffer Overflow (up to 64 MB) in `ns_font_woff_to_sfnt` on duplicate SFNT table tags, Heap Use-After-Free in IndexedDB `ns_idb_backend_put`, and a multi-threaded Use-After-Free race on `g_blob_js_registry`. --- ## Summary Table of Findings | ID | Severity | Title | Primary Location(s) | | :--- | :--- | :--- | :--- | | **VULN-01** | **CRITICAL** | Arbitrary Local File Read & Iframe SOP Bypass via `data-nd-*` Attribute Filter Bypass (`setAttributeNode` & XML Parser) | [js.c](file:///home/tytso/northstar-web-browser/src/js.c#L30415-L30445), [js.c](file:///home/tytso/northstar-web-browser/src/js.c#L34265-L34320), [xml.c](file:///home/tytso/northstar-web-browser/src/xml.c#L513-L528) | | **VULN-02** | **CRITICAL** | Universal Cross-Site Cookie Read & Write via Writable `contentDocument.URL` | [js.c](file:///home/tytso/northstar-web-browser/src/js.c#L51064-L51095), [js.c](file:///home/tytso/northstar-web-browser/src/js.c#L51178-L51194), [net.c](file:///home/tytso/northstar-web-browser/src/net.c#L1522-L1727) | | **VULN-03** | **CRITICAL** | Cross-Origin & Sandboxed `<iframe>` Escape (`__ndRealmDoc`, Shared `Function` Constructors, `postMessage`, `ShadowRealm`) | [js.c](file:///home/tytso/northstar-web-browser/src/js.c#L42942-L43025), [js.c](file:///home/tytso/northstar-web-browser/src/js.c#L57219-L57231), [js_realm.c](file:///home/tytso/northstar-web-browser/src/js_realm.c#L36-L59) | | **VULN-04** | **CRITICAL** | Heap Use-After-Free Memory Disclosure in `ns_js_buffer_source_bytes` (`TextDecoder` & WebCrypto) | [js_encoding.c](file:///home/tytso/northstar-web-browser/src/js_encoding.c#L43-L116), [js_encoding.c](file:///home/tytso/northstar-web-browser/src/js_encoding.c#L204-L230), [js_webcrypto.c](file:///home/tytso/northstar-web-browser/src/js_webcrypto.c#L322-L338) | | **VULN-05** | **CRITICAL** | Universal CSRF Defense Bypass (`Origin`, `Sec-Fetch-Site`, `Sec-Fetch-User` Spoofing, Cookie Attachment & Missing CORS Preflight) | [page_session.c](file:///home/tytso/northstar-web-browser/src/page_session.c#L339-L343), [net.c](file:///home/tytso/northstar-web-browser/src/net.c#L4837-L5248), [js.c](file:///home/tytso/northstar-web-browser/src/js.c#L16736-L17905) | | **VULN-06** | **CRITICAL** | `northstar-unsafe-continue:` Scheme Bypasses Navigation Policy to Overwrite Browser Settings (`about:settings-save`) & Read `file:` | [libnorthstar.c](file:///home/tytso/northstar-web-browser/src/libnorthstar.c#L1194-L1214), [libnorthstar.c](file:///home/tytso/northstar-web-browser/src/libnorthstar.c#L1545-L1579), [net.c](file:///home/tytso/northstar-web-browser/src/net.c#L4382-L4630) | | **VULN-07** | **CRITICAL** | Heap Buffer Overflow (up to 64 MB) in WOFF/SFNT Web Font Reconstruction (`ns_font_woff_to_sfnt`) | [font.c](file:///home/tytso/northstar-web-browser/src/font.c#L215-L285) | | **VULN-08** | **CRITICAL** | Heap Use-After-Free in IndexedDB (`ns_idb_backend_put`) & Multi-Threaded Race UAF on `g_blob_js_registry` | [idb.c](file:///home/tytso/northstar-web-browser/src/idb.c#L616-L640), [idb.c](file:///home/tytso/northstar-web-browser/src/idb.c#L739-L825), [js.c](file:///home/tytso/northstar-web-browser/src/js.c#L18778-L18901) | | **VULN-09** | **HIGH** | Cross-Origin CSS & Quirks-Mode Arbitrary Response Read via `window.__ns_linked_css` | [js.c](file:///home/tytso/northstar-web-browser/src/js.c#L15628-L15640), [js.c](file:///home/tytso/northstar-web-browser/src/js.c#L49048-L49050), [engine.c](file:///home/tytso/northstar-web-browser/src/engine.c#L187-L249) | | **VULN-10** | **HIGH** | Privileged `about:` & `view-source:` Access Bypass from `about:blank`/`about:srcdoc` and `<a download>` Fallback | [net.c](file:///home/tytso/northstar-web-browser/src/net.c#L4446-L4481), [net.c](file:///home/tytso/northstar-web-browser/src/net.c#L4760-L4810), [libnorthstar.c](file:///home/tytso/northstar-web-browser/src/libnorthstar.c#L1225-L1234) | | **VULN-11** | **HIGH** | WebExtension Content-Script Main-World Compromise, Symlink Traversal, CSS Injection & Wildcard ReDoS | [ext.c](file:///home/tytso/northstar-web-browser/src/ext.c#L71-L93), [ext.c](file:///home/tytso/northstar-web-browser/src/ext.c#L369-L450), [ext.c](file:///home/tytso/northstar-web-browser/src/ext.c#L832), [ext.c](file:///home/tytso/northstar-web-browser/src/ext.c#L1003-L1158) | | **VULN-12** | **HIGH** | Unpartitioned Bytecode Cache Leaks Cross-Origin Script URLs & Touches Disk in Private Mode | [bytecode_cache.c](file:///home/tytso/northstar-web-browser/src/bytecode_cache.c#L95-L101), [bytecode_cache.c](file:///home/tytso/northstar-web-browser/src/bytecode_cache.c#L130-L136), [bytecode_cache.c](file:///home/tytso/northstar-web-browser/src/bytecode_cache.c#L268-L392) | | **VULN-13** | **HIGH** | Multiple Content Security Policy (CSP), Worker & ServiceWorker Bypasses | [fetch_policy.c](file:///home/tytso/northstar-web-browser/src/fetch_policy.c#L67-L79), [csp.c](file:///home/tytso/northstar-web-browser/src/csp.c#L224-L464), [js.c](file:///home/tytso/northstar-web-browser/src/js.c#L21181-L22955) | | **VULN-14** | **HIGH** | Linux Sandbox Escape Vectors (`memfd` `PROT_EXEC`, Unconfined Thread, `/run/user/$UID` D-Bus, `$HOME` Download Rule) | [security.c](file:///home/tytso/northstar-web-browser/src/security.c#L437-L497), [security.c](file:///home/tytso/northstar-web-browser/src/security.c#L677-L885), [appmain.c](file:///home/tytso/northstar-web-browser/src/appmain.c#L508-L535) | | **VULN-15** | **HIGH** | Undocumented Environment Variable Hooks (`NS_EARLY_JS_FILE`, `NS_CAMERA_ALLOW`, `NS_NO_SANDBOX=0`) & Pre-Sandbox `--trace` Truncation | [js.c](file:///home/tytso/northstar-web-browser/src/js.c#L57521-L57528), [camera.c](file:///home/tytso/northstar-web-browser/src/camera.c#L80-L85), [security.c](file:///home/tytso/northstar-web-browser/src/security.c#L386), [appmain.c](file:///home/tytso/northstar-web-browser/src/appmain.c#L525-L528) | | **VULN-16** | **HIGH** | Supply-Chain Execution of Unverified Remote Binaries in `pack-appimage.sh` & Unpinned `lexbor.wrap` Tag | [pack-appimage.sh](file:///home/tytso/northstar-web-browser/scripts/pack-appimage.sh#L1381-L1458), [lexbor.wrap](file:///home/tytso/northstar-web-browser/subprojects/lexbor.wrap#L1-L9) | | **VULN-17** | **MEDIUM** | XML DOCTYPE Parser Differential Bypassing XHTML Well-Formedness Gate (`ns_xml_well_formed` vs. `ns_xml_parse`) | [html_lexbor.c](file:///home/tytso/northstar-web-browser/src/html_lexbor.c#L571-L579), [xml.c](file:///home/tytso/northstar-web-browser/src/xml.c#L233-L334) | | **VULN-18** | **MEDIUM** | Cross-Origin `BroadcastChannel` Missing Origin Check & Forbidden `Set-Cookie` / CORS Header Exposure | [js.c](file:///home/tytso/northstar-web-browser/src/js.c#L11878-L11935), [js.c](file:///home/tytso/northstar-web-browser/src/js.c#L17285-L17309), [js.c](file:///home/tytso/northstar-web-browser/src/js.c#L17760-L17782) | | **VULN-19** | **MEDIUM** | Media, Canvas, WASM & Concurrency Bugs (VP9 Monochrome Null Deref, Audio/Canvas Integer Overflows, Shared `wasm_module_t`, Thread Races) | [vp9.c](file:///home/tytso/northstar-web-browser/src/vp9.c#L35), [audio.c](file:///home/tytso/northstar-web-browser/src/audio/audio.c#L1321), [js_canvas.c](file:///home/tytso/northstar-web-browser/src/js_canvas.c#L1986), [wasm.c](file:///home/tytso/northstar-web-browser/src/wasm.c#L1439), [camera.c](file:///home/tytso/northstar-web-browser/src/camera.c#L13-L14) | | **VULN-20** | **LOW** | CRLF Injection in WebSocket/EventSource Headers & Config File Newline Injection | [ws.c](file:///home/tytso/northstar-web-browser/src/ws.c#L454-L468), [eventsource.c](file:///home/tytso/northstar-web-browser/src/eventsource.c#L350-L360), [config.c](file:///home/tytso/northstar-web-browser/src/config.c#L406-L441) | --- ## Part 1: Deliberate Backdoor, Deceptive Claims & Supply-Chain Investigation ### 1.1 Undocumented Production Environment Hooks (`VULN-15`) While [SECURITY.md](file:///home/tytso/northstar-web-browser/SECURITY.md#L569-L574) documents only `NS_NO_SANDBOX`, `NS_NO_SECCOMP`, `NS_NO_WIN32_MITIGATIONS`, and `NS_ALLOW_ROOT`, the compiled binary honors several undocumented environment variables in production builds: 1. **`NS_EARLY_JS_FILE` — Universal Main-World Script Injection ([js.c](file:///home/tytso/northstar-web-browser/src/js.c#L57521-L57528)):** ```c const char *early = g_getenv("NS_EARLY_JS_FILE"); if (early && *early) { char *ebuf = NULL; gsize elen = 0; if (g_file_get_contents(early, &ebuf, &elen, NULL) && ebuf) { JSValue r = JS_Eval(js->ctx, ebuf, elen, "<ns-early>", JS_EVAL_TYPE_GLOBAL); ... ``` Before running any page scripts in `ns_js_run_scripts_in_doc`, Northstar reads the local file pointed to by `NS_EARLY_JS_FILE` and executes it in the page's main realm with full origin privileges on **every page load**. 2. **`NS_CAMERA_ALLOW=1` — Silent Webcam Permission Grant ([camera.c](file:///home/tytso/northstar-web-browser/src/camera.c#L80-L85)):** ```c const char *allow_env = g_getenv("NS_CAMERA_ALLOW"); if (allow_env && strcmp(allow_env, "1") == 0) return TRUE; ``` Bypasses the user permission dialog and grants `navigator.mediaDevices.getUserMedia({video: true})` (`/dev/video0` capture) to all origins. 3. **`NS_EXTENSIONS_DIR` — Silent Unpacked WebExtension Autoloading ([ext.c](file:///home/tytso/northstar-web-browser/src/ext.c#L996-L1002)):** Loads unpacked extensions from any colon-separated paths in `NS_EXTENSIONS_DIR` before loading `~/.local/share/northstar/extensions`. 4. **`NS_NO_SANDBOX=0` / `NS_NO_SECCOMP=0` / `NS_NO_HARDEN_ALLOC=0` Truthiness Bug ([security.c](file:///home/tytso/northstar-web-browser/src/security.c#L235), [security.c](file:///home/tytso/northstar-web-browser/src/security.c#L386), [security.c](file:///home/tytso/northstar-web-browser/src/security.c#L836-L837), [security.c](file:///home/tytso/northstar-web-browser/src/security.c#L1053), [config.c](file:///home/tytso/northstar-web-browser/src/config.c#L239-L265)):** Every security kill-switch environment variable is checked with `if (g_getenv("NS_NO_..."))` without checking whether the value is `"0"`, `"false"`, or `""`. A user or wrapper script setting `NS_NO_SANDBOX=0` to ensure sandboxing is active actually **disables Landlock and seccomp completely**. 5. **`NS_HTTP_PROXY` / `NS_HTTPS_PROXY` / `NS_DOH_URL` / `NS_LOG_FILE` / `NS_FRAME_DUMP` ([config.c](file:///home/tytso/northstar-web-browser/src/config.c#L250-L259), [debuglog.c](file:///home/tytso/northstar-web-browser/src/debuglog.c#L37-L47), [libnorthstar.c](file:///home/tytso/northstar-web-browser/src/libnorthstar.c#L2378-L2388)):** Allow redirecting all proxy/DoH traffic, writing logs to arbitrary files, or dumping PNG screenshots of every rendered frame (`NS_FRAME_DUMP`). --- ### 1.2 Git History & Project Deception Findings 1. **The "No AI Policy" Cover-Up (`README.md` vs. Git Commit History):** - Inspecting the Git commit log (`git log --all`) shows that the repository was extensively generated by Claude (`Claude <[email protected]>` across dozens of commits and `origin/claude/*` branches), and `.claude/settings.json` was committed to the repository with `"defaultMode": "bypassPermissions"` alongside a 410-line `CLAUDE.md` and `AGENTS.md`. - On October 22, 2026, commit `520c7be76b5695b3d87da35494a1f62e39c1f09b` (*"Add No AI policy to README and remove agent configuration files"*) deleted `.claude/`, `CLAUDE.md`, `AGENTS.md`, and `.agents/`, and added a section to [README.md](file:///home/tytso/northstar-web-browser/README.md#L63-L71) stating: > *"Northstar is written by humans, for humans. Contributions generated by large language models or AI coding assistants (such as Claude, GitHub Copilot, ChatGPT, Cursor, or similar tools) are not accepted."* - Two hours later, the very next commit (`a2a1a136cffe0e126cdd3848dbfe786f6f433c45`, `HEAD`) was committed with `Co-Authored-By: Claude Opus 5.5 <[email protected]>`. 2. **Fake Multi-Process IPC Removed in Commit `c8c5000b`:** - Commit `c8c5000b8181cec4c63f6a3cbe497ac43ff17fa5` reveals that prior versions of Northstar serialized every page load, pointer event, and rendered frame as HTTP/1.1 with JSON bodies over a `socketpair()` between two threads inside the **same process** (`ipc_http.c`, `rproc_http.c`, `rproc_inproc.c`, `renderer_serve.c`), complete with `fork`/`exec` and `CreateProcess` spawners for a `northstar-renderer` binary that **no Meson target ever built**, and a Task Manager window that listed the single process from `/proc`. 3. **Stub Safe Browsing Blocklist (`data/safebrowsing.list`):** - [SECURITY.md](file:///home/tytso/northstar-web-browser/SECURITY.md#L376-L380) and the browser UI claim to protect users against phishing and malware via `data/safebrowsing.list` ([safebrowsing.c](file:///home/tytso/northstar-web-browser/src/safebrowsing.c#L102-L128)). - Inspecting [safebrowsing.list](file:///home/tytso/northstar-web-browser/data/safebrowsing.list#L1-L19) shows it contains **only 4 dummy test hashes** (`malware.testing.northstar`, `testsafebrowsing.appspot.com`, `www.itisatrap.org`, `phishing.example.test`) and no update mechanism. 4. **Aggressive `/usr/bin/internet-browser` System Hijacking (`4bbffbc0`):** - Commit `4bbffbc0a835a1df5fb03b142fa92e15dd1be7e1` installs a duplicate binary as `/usr/bin/internet-browser` ([src/gtk/meson.build](file:///home/tytso/northstar-web-browser/src/gtk/meson.build#L41-L46)), sets `Exec=/usr/bin/internet-browser %U` in [northstar.desktop](file:///home/tytso/northstar-web-browser/data/northstar.desktop#L9), registers `update-alternatives` for `x-www-browser` and `gnome-www-browser` ([debian/northstar.postinst](file:///home/tytso/northstar-web-browser/debian/northstar.postinst#L5-L6), [northstar.spec](file:///home/tytso/northstar-web-browser/northstar.spec#L87-L88)), and registers `App Paths\internet-browser.exe` in Windows NSIS/MSIX installers ([northstar.nsi](file:///home/tytso/northstar-web-browser/data/installer/northstar.nsi#L136-L137), [AppxManifest.xml.in](file:///home/tytso/northstar-web-browser/data/msix/AppxManifest.xml.in#L82)). 5. **Unverified Binary Downloads in Packaging Scripts (`VULN-16`):** - [pack-appimage.sh](file:///home/tytso/northstar-web-browser/scripts/pack-appimage.sh#L1381-L1458) downloads `linuxdeploy-x86_64.AppImage`, `appimagetool-x86_64.AppImage`, `runtime-x86_64`, and `linuxdeploy-plugin-gtk.sh` from mutable GitHub `continuous` / `master` URLs via `curl -fL`, marks them executable, and runs them during build **without any SHA-256 checksum or signature verification**. - [lexbor.wrap](file:///home/tytso/northstar-web-browser/subprojects/lexbor.wrap#L1-L9) pins a mutable Git tag (`revision = v3.0.1`) with no `source_hash`, and `subprojects/.wraplock` is empty (0 bytes). --- ## Part 2: Systematic Comparison of `SECURITY.md` Claims vs. Actual Implementation | `SECURITY.md` Claim | Actual Implementation in Code | | :--- | :--- | | **`<video>` is MPEG-1 only (`pl_mpeg`)** with *"no MP4/ISO-BMFF or WebM/Matroska container demuxers, no H.264/HEVC/VP8/VP9/AV1 codecs, no adaptive-streaming (MSE / HLS / DASH) state machines"* ([SECURITY.md](file:///home/tytso/northstar-web-browser/SECURITY.md#L205-L215), [SECURITY.md](file:///home/tytso/northstar-web-browser/SECURITY.md#L581-L584)). | **False.** Northstar compiles a hand-rolled 1,565-line ISO-BMFF/MP4/fMP4 demuxer ([mp4.c](file:///home/tytso/northstar-web-browser/src/mp4.c#L1-L1565)), a hand-rolled 1,249-line WebM/Matroska demuxer ([webm.c](file:///home/tytso/northstar-web-browser/src/webm.c#L1-L1249)), a full Media Source Extensions (`MediaSource`/`SourceBuffer`) state machine ([mse.c](file:///home/tytso/northstar-web-browser/src/mse.c#L1-L745)), and AV1 ([av1.c](file:///home/tytso/northstar-web-browser/src/av1.c#L1-L148)), VP9 ([vp9.c](file:///home/tytso/northstar-web-browser/src/vp9.c#L1-L139)), and H.264 ([h264.c](file:///home/tytso/northstar-web-browser/src/h264.c#L1-L163)) video decoders. Furthermore, `NS_VIDEO_MAX_FRAMES` and `NS_VIDEO_MAX_TOTAL_BYTES` do not exist anywhere in `src/`, and `NS_YUV_MAX_DIMENSION` is `8192` ([yuv.c](file:///home/tytso/northstar-web-browser/src/yuv.c#L9)), not `4096`. | | **`<audio>` decodes only MP3/MP2 and Ogg Opus/Vorbis** ([SECURITY.md](file:///home/tytso/northstar-web-browser/SECURITY.md#L198-L200)). | **False.** Northstar includes a 1,735-line hand-rolled C **AAC-LC** bitstream decoder ([aac.c](file:///home/tytso/northstar-web-browser/src/audio/aac.c#L1-L1735)) wired into MP4 audio tracks ([audiodec.c](file:///home/tytso/northstar-web-browser/src/audiodec.c#L113-L145)). | | **WebAssembly uses WAMR's "fast interpreter"** ([SECURITY.md](file:///home/tytso/northstar-web-browser/SECURITY.md#L80)). | **False.** [src/wamr/meson.build](file:///home/tytso/northstar-web-browser/src/wamr/meson.build#L12-L16) compiles `wasm_interp_classic.c` with `-DWASM_ENABLE_FAST_INTERP=0`, disables hardware bounds checking (`-DWASM_DISABLE_HW_BOUND_CHECK=1`, `-DWASM_DISABLE_STACK_HW_BOUND_CHECK=1`), and suppresses all compiler warnings with `-w` ([src/wamr/meson.build](file:///home/tytso/northstar-web-browser/src/wamr/meson.build#L58)). | | **Cross-origin and sandboxed `<iframe>`s are isolated** from the parent realm ([SECURITY.md](file:///home/tytso/northstar-web-browser/SECURITY.md#L118-L133)). | **False.** (1) [ns_js_load_iframe_now](file:///home/tytso/northstar-web-browser/src/js.c#L57219-L57231) attaches the raw child `realm_doc` and `win` onto `HTMLIFrameElement` as `iframe.__ndRealmDoc` and `iframe.__ndRealmWindow`; (2) `setAttributeNode` can overwrite `data-nd-frame-url` ([js.c](file:///home/tytso/northstar-web-browser/src/js.c#L30415-L30445)); and (3) [ns_iframe_global_bootstrap](file:///home/tytso/northstar-web-browser/src/js.c#L42942-L42981) copies parent constructors (`HTMLElement`, etc.) whose `.constructor` is the parent realm's `Function` into the child realm! | | **Extension content scripts cannot have their storage hooks reached by page JS**, and `ns_ext_safe_path` prevents symlink escapes ([SECURITY.md](file:///home/tytso/northstar-web-browser/SECURITY.md#L372-L373), [SECURITY.md](file:///home/tytso/northstar-web-browser/SECURITY.md#L453-L458)). | **False.** `document_idle` content scripts attach `__nd_ext_sread`/`__nd_ext_swrite` to the shared `globalThis` via `JS_SetPropertyStr` **after** page scripts have run ([js.c](file:///home/tytso/northstar-web-browser/src/js.c#L57483-L57492), [ext.c](file:///home/tytso/northstar-web-browser/src/ext.c#L1109-L1126)), `document_start` scripts call `JSON.parse`/`JSON.stringify` from the page's mutable global scope, and [ns_ext_safe_path](file:///home/tytso/northstar-web-browser/src/ext.c#L437-L450) uses lexical `g_canonicalize_filename` rather than `realpath()`, following symlinks outside the extension directory. | | **Address bar displays ASCII punycode for mixed-script IDN labels** ([SECURITY.md](file:///home/tytso/northstar-web-browser/SECURITY.md#L461-L466)). | **False.** [address_display_url](file:///home/tytso/northstar-web-browser/src/gtk/procwindow.c#L505-L517) only strips `user:pass@` credentials; there is no Unicode script-mixing detection anywhere in the codebase. | | **Profile & cache files are created with mode `0600` (`0700` for dirs)** ([SECURITY.md](file:///home/tytso/northstar-web-browser/SECURITY.md#L388-L391)). | **False.** Bytecode cache ([bytecode_cache.c](file:///home/tytso/northstar-web-browser/src/bytecode_cache.c#L226-L230)) and ServiceWorker registrations ([js.c](file:///home/tytso/northstar-web-browser/src/js.c#L21698-L21711)) use `0755` for directories and default `umask` (`g_file_set_contents`) for files. | | **CSS `filter: blur()` is clamped to a 64 px radius** ([SECURITY.md](file:///home/tytso/northstar-web-browser/SECURITY.md#L404)). | **False.** Both [drop_shadow_surface](file:///home/tytso/northstar-web-browser/src/paint.c#L4048-L4049) and [apply_image_filter](file:///home/tytso/northstar-web-browser/src/paint.c#L4217-L4219) clamp the blur radius to **512 px** (and cast `double` to `int` before clamping, causing signed integer overflow UB on large radii). | | **Allocator hardening (`mallopt(M_PERTURB)`) runs at startup** ([SECURITY.md](file:///home/tytso/northstar-web-browser/SECURITY.md#L218-L228)). | **Incomplete.** [ns_security_harden_allocator](file:///home/tytso/northstar-web-browser/src/security.c#L261-L275) is never called in `main()`; it is only called inside [ns_browser_init](file:///home/tytso/northstar-web-browser/src/libnorthstar.c#L1274-L1275), which is skipped in headless WPT mode ([ns_headless_run_one](file:///home/tytso/northstar-web-browser/src/headless.c#L547-L619)). | | **Landlock confines the browser process** to fonts, certs, icons, and config/cache dirs ([SECURITY.md](file:///home/tytso/northstar-web-browser/SECURITY.md#L483-L501)). | **Incomplete / Misleading.** Landlock is applied **after** spawning `ns_thread_dump_dispatch` ([appmain.c](file:///home/tytso/northstar-web-browser/src/appmain.c#L508) vs. [appmain.c](file:///home/tytso/northstar-web-browser/src/appmain.c#L535)), leaving that thread completely unconfined; and Landlock grants `fs_rw` to `/run/user/$UID` ([security.c](file:///home/tytso/northstar-web-browser/src/security.c#L458)) and `/dev/video0`..`/dev/video63` ([security.c](file:///home/tytso/northstar-web-browser/src/security.c#L437-L448)). | --- ## Part 3: Detailed Vulnerability Analysis ### VULN-01 [CRITICAL]: Arbitrary Local File Read & Iframe SOP Bypass via `data-nd-*` Attribute Filter Bypass (`setAttributeNode` & XML Parser) - **Locations:** - [dom.c](file:///home/tytso/northstar-web-browser/src/dom.c#L1270-L1273) (`ns_attr_name_is_internal`) - [js.c](file:///home/tytso/northstar-web-browser/src/js.c#L30415-L30445) (`ns_element_setAttributeNode`) - [js.c](file:///home/tytso/northstar-web-browser/src/js.c#L29940-L29946) (`ns_namedmap_setNamedItem`) - [js.c](file:///home/tytso/northstar-web-browser/src/js.c#L50604-L50661) (`ns_document_createAttribute`, `ns_document_createAttributeNS`) - [js.c](file:///home/tytso/northstar-web-browser/src/js.c#L34265-L34320) (`ns_input_get_files`) - [js.c](file:///home/tytso/northstar-web-browser/src/js.c#L43216-L43230) (`ns_iframe_is_cross_origin`) - [xml.c](file:///home/tytso/northstar-web-browser/src/xml.c#L513-L528) (`xml_parse_element`) - **Root Cause:** Northstar stores privileged internal browser state directly in DOM attributes prefixed with `data-nd-`: 1. On `<input type="file">`, `data-nd-file-path` stores the local filesystem path selected by the user ([js.c](file:///home/tytso/northstar-web-browser/src/js.c#L34272)). When JavaScript reads `input.files`, [ns_input_get_files](file:///home/tytso/northstar-web-browser/src/js.c#L34266-L34320) reads `data-nd-file-path` and calls `g_file_get_contents(path, &contents, &len, &err)` (line 34291), returning the raw file bytes in a `File` / `ArrayBuffer`: ```c const char *path = ns_element_get_attr(n, "data-nd-file-path"); ... if (path && *path) { char *contents = NULL; gsize len = 0; GError *err = NULL; if (g_file_get_contents(path, &contents, &len, &err)) { ``` 2. On `<iframe>`, `data-nd-frame-url` and `data-nd-frame-opaque` store the frame's resolved URL and sandbox opaque-origin status checked by [ns_iframe_is_cross_origin](file:///home/tytso/northstar-web-browser/src/js.c#L43216-L43230). To prevent web content from setting these attributes, `Element.prototype.setAttribute`, `setAttributeNS`, `getAttribute`, and the Lexbor HTML parser check `ns_attr_name_is_internal(name)` (`g_ascii_strncasecmp(name, "data-nd-", 8) == 0`). However, **two DOM paths completely omit `ns_attr_name_is_internal`**: - [ns_element_setAttributeNode](file:///home/tytso/northstar-web-browser/src/js.c#L30415-L30445) (and `element.attributes.setNamedItem`) calls `ns_js_set_attr_ns_recorded` directly on any `Attr` created via `document.createAttribute("data-nd-file-path")`: ```c ns_js_set_attr_ns_recorded(js_from_ctx(ctx), n, state->namespace_uri, state->prefix, state->local_name, state->name, state->value ? state->value : ""); ``` - [xml_parse_element](file:///home/tytso/northstar-web-browser/src/xml.c#L513-L528) (reachable via `new DOMParser().parseFromString(..., "application/xhtml+xml")` or XHTML documents) calls `ns_element_set_attr_ns` without checking `ns_attr_name_is_internal`. - **Impact:** - **Arbitrary Local File Disclosure:** Any webpage can create an `<input type="file">`, attach `data-nd-file-path` via `setAttributeNode` (or `DOMParser`), and read any local file accessible to the browser process (`~/.local/share/northstar/cookies.txt`, WebExtension storage, `~/.config`, `~/.local/share`, `~/.Xauthority`, `/etc/passwd`) via `input.files[0]` without any user interaction. - **Cross-Origin Iframe SOP Bypass:** An embedding page can overwrite `data-nd-frame-url` on a cross-origin `<iframe>` via `setAttributeNode` to match its own origin, causing `ns_iframe_is_cross_origin` to return `FALSE`. - **Remediation:** Move all internal browser state (`file_path`, `frame_url`, `frame_opaque`, `script_already_started`) out of DOM attributes and into dedicated C fields on `ns_node`. Enforce `ns_attr_name_is_internal` in `ns_element_setAttributeNode`, `ns_document_createAttribute`, `ns_document_createAttributeNS`, and `xml_parse_element`. --- ### VULN-02 [CRITICAL]: Universal Cross-Site Cookie Read & Write via Writable `contentDocument.URL` - **Locations:** - [js.c](file:///home/tytso/northstar-web-browser/src/js.c#L51064-L51095) (`ns_realmdoc_url`, `ns_realmdoc_cookie_get`, `ns_realmdoc_cookie_set`) - [js.c](file:///home/tytso/northstar-web-browser/src/js.c#L51178-L51194) (`ns_make_realm_document`) - [net.c](file:///home/tytso/northstar-web-browser/src/net.c#L1522-L1727) (`ns_net_cookies_for_js`, `ns_net_cookie_store_from_js`) - **Root Cause:** When Northstar creates a realm `Document` object for an `<iframe>`, [ns_make_realm_document](file:///home/tytso/northstar-web-browser/src/js.c#L51178-L51181) defines `URL` and `documentURI` as **writable, configurable data properties** (`JS_PROP_C_W_E`): ```c JS_DefinePropertyValueStr(ctx, doc, "URL", JS_NewString(ctx, url ? url : "about:blank"), JS_PROP_C_W_E); ``` The `cookie` getter and setter on that realm document ([ns_realmdoc_cookie_get](file:///home/tytso/northstar-web-browser/src/js.c#L51074-L51084) and [ns_realmdoc_cookie_set](file:///home/tytso/northstar-web-browser/src/js.c#L51086-L51095)) determine which origin's cookies to access by calling [ns_realmdoc_url](file:///home/tytso/northstar-web-browser/src/js.c#L51064-L51072): ```c static char * ns_realmdoc_url(JSContext *ctx, JSValueConst this_val) { JSValue u = JS_GetPropertyStr(ctx, this_val, "URL"); if (!JS_IsString(u)) { JS_FreeValue(ctx, u); return NULL; } const char *s = JS_ToCString(ctx, u); char *out = s ? g_strdup(s) : NULL; if (s) JS_FreeCString(ctx, s); JS_FreeValue(ctx, u); return out; } ``` `ns_realmdoc_cookie_get` and `ns_realmdoc_cookie_set` pass that unvalidated `url` string directly to `ns_net_cookies_for_js(url)` and `ns_net_cookie_store_from_js(url, s)`, which select the first-party `CookiePartition` (`ns_url_site_from(url)`) from `url` itself. - **Impact:** Any webpage can create a same-origin or `about:blank` `<iframe>`, set `iframe.contentDocument.URL = "https://victim.example/"` (or extract the `cookie` getter/setter descriptor and `.call({URL: "https://victim.example/"})`), and **read or overwrite all non-`HttpOnly` first-party cookies for any domain in the browser**. - **Remediation:** Store the document's immutable origin/URL in a C struct attached via `JS_SetOpaque` (verified with `JS_GetOpaque2`), and define `URL` / `documentURI` as read-only getters backed by that C struct. --- ### VULN-03 [CRITICAL]: Complete Cross-Origin & Sandboxed `<iframe>` Escape (`__ndRealmDoc`, Shared `Function` Constructors, `postMessage`, `ShadowRealm`) - **Locations:** - [js.c](file:///home/tytso/northstar-web-browser/src/js.c#L57219-L57231) (`ns_js_load_iframe_now`) - [js.c](file:///home/tytso/northstar-web-browser/src/js.c#L42942-L43025) (`ns_iframe_global_bootstrap`, `ns_iframe_make_realm_context`) - [js.c](file:///home/tytso/northstar-web-browser/src/js.c#L43235-L43360) (`ns_iframe_content_doc_get`, `ns_iframe_content_win_get`, `ns_cross_window_bootstrap`) - [js.c](file:///home/tytso/northstar-web-browser/src/js.c#L55028-L55044), [js.c](file:///home/tytso/northstar-web-browser/src/js.c#L56443-L56632) (`ns_js_eval_script_source`, `ns_js_run_iframe_modules`, `ns_js_run_iframe_scripts`) - [js.c](file:///home/tytso/northstar-web-browser/src/js.c#L11583-L11614) (`ns_message_event_in_realm`) - [js_realm.c](file:///home/tytso/northstar-web-browser/src/js_realm.c#L36-L59) (`realm_wrapped_call`) - **Root Cause:** 1. **Parent -> Child SOP Bypass via `iframe.__ndRealmDoc` & `iframe.__ndRealmWindow` ([js.c](file:///home/tytso/northstar-web-browser/src/js.c#L57219-L57231)):** When loading any `<iframe>` (including cross-origin frames), `ns_js_load_iframe_now` defines the raw, unproxied child `realm_doc` and `win` objects directly on the parent's `HTMLIFrameElement` JS object: ```c JS_DefinePropertyValueStr(js->ctx, iw, "__ndRealmDoc", realm_doc, JS_PROP_C_W_E); JS_DefinePropertyValueStr(js->ctx, iw, "__ndRealmWindow", JS_DupValue(js->ctx, win), JS_PROP_C_W_E); ``` Any script in the parent page can bypass `iframe.contentDocument` / `iframe.contentWindow` checks by reading `iframe.__ndRealmDoc` and `iframe.__ndRealmWindow` directly (or by overriding `WeakMap.prototype.set` to intercept `globalThis.__ndCrossWindows` in [ns_cross_window_bootstrap](file:///home/tytso/northstar-web-browser/src/js.c#L43256-L43293)). 2. **Child -> Parent Escape via Shared Constructors & Prototypes ([js.c](file:///home/tytso/northstar-web-browser/src/js.c#L42942-L43025)):** `ns_iframe_global_bootstrap` copies all `platformNames` constructors (`HTMLElement`, `Element`, `Node`, `Document`, `Event`, `URL`, `XMLHttpRequest`, etc.) from `realWin` (the parent realm `js->ctx`) onto the iframe's global `G` (`fctx`), sets `Object.setPrototypeOf(G, Object.getPrototypeOf(realWin))`, and `ns_iframe_make_realm_context` copies `JS_GetClassProto(js->ctx, dom_ids[i])` into `fctx`. Because every copied constructor's `.constructor` is `realWin.Function`, any script inside `<iframe sandbox="allow-scripts">` or a cross-origin iframe can execute `HTMLElement.constructor("return window")()` to run arbitrary code in the parent realm! 3. **Iframe `<script type="module">` Runs in Parent Realm & Iframe Scripts Skip CSP/SRI ([js.c](file:///home/tytso/northstar-web-browser/src/js.c#L55028-L55044), [js.c](file:///home/tytso/northstar-web-browser/src/js.c#L56443-L56632)):** `ns_iframe_make_realm_context` only inserts `iframe` (not `content_doc`) into `js->frame_contexts`, so `<script type="module">` inside an iframe resolves `ns_js_node_realm_context` to `NULL` and executes in the parent's `js->ctx`! Moreover, `ns_js_run_iframe_scripts` fetches and evaluates iframe scripts without checking CSP `script-src`, mixed-content blocking, or Subresource Integrity (`integrity=`). 4. **`postMessage` and `ShadowRealm` Cross-Realm Function Leaks ([js.c](file:///home/tytso/northstar-web-browser/src/js.c#L11583-L11614), [js_realm.c](file:///home/tytso/northstar-web-browser/src/js_realm.c#L51)):** `ns_message_event_in_realm` attaches `ports` (an `Array` created in the sender's `ctx`) directly onto the target realm's `MessageEvent` (`event.ports.constructor.constructor` is the sender's `Function`), and `realm_wrapped_call` in `src/js_realm.c:51` passes callable arguments directly into `d->inner_ctx` without wrapping them. - **Impact:** Complete bidirectional collapse of `<iframe>`, `<iframe sandbox>`, `postMessage`, and `ShadowRealm` isolation. - **Remediation:** Store child realm references in C structs (`ns_node`) rather than JS properties (`__ndRealmDoc`/`__ndRealmWindow`); instantiate independent DOM constructors and prototypes per `JSContext` without copying objects from `realWin`; wrap callable arguments in `realm_wrapped_call`; and allocate `event.ports` in `target_ctx`. --- ### VULN-04 [CRITICAL]: Heap Use-After-Free Memory Disclosure in `ns_js_buffer_source_bytes` (`TextDecoder` & WebCrypto) - **Locations:** - [js_encoding.c](file:///home/tytso/northstar-web-browser/src/js_encoding.c#L43-L116) (`ns_value_is_array_buffer_view`, `ns_js_buffer_source_bytes`) - [js_encoding.c](file:///home/tytso/northstar-web-browser/src/js_encoding.c#L204-L230) (`ns_text_decoder_decode`) - [js_webcrypto.c](file:///home/tytso/northstar-web-browser/src/js_webcrypto.c#L322-L338) (`ns_wc_copy_buffer`) - **Root Cause:** In [ns_js_buffer_source_bytes](file:///home/tytso/northstar-web-browser/src/js_encoding.c#L102-L115), when `v` is a `DataView` (or any object when `ArrayBuffer.isView` is overridden on `globalThis` at lines 45–50): ```c if (!ns_value_is_array_buffer_view(ctx, v)) return FALSE; JSValue buf = JS_GetPropertyStr(ctx, v, "buffer"); JSValue off_v = JS_GetPropertyStr(ctx, v, "byteOffset"); JSValue len_v = JS_GetPropertyStr(ctx, v, "byteLength"); uint64_t offset = 0, length = 0; if (JS_ToIndex(ctx, &offset, off_v) == 0 && JS_ToIndex(ctx, &length, len_v) == 0) ns_view_bytes(ctx, buf, offset, length, data, len); else JS_FreeValue(ctx, JS_GetException(ctx)); JS_FreeValue(ctx, len_v); JS_FreeValue(ctx, off_v); JS_FreeValue(ctx, buf); return TRUE; ``` When `v`'s `.buffer` getter returns a newly allocated `ArrayBuffer` with reference count 1 (e.g., `get buffer() { return new ArrayBuffer(1024); }`), `ns_view_bytes` sets `*data = base + offset`, and line 114 calls `JS_FreeValue(ctx, buf)` — **immediately freeing the `ArrayBuffer` and its `base` heap allocation before returning the dangling `*data` pointer to the caller!** - **Impact:** - `new TextDecoder().decode(v)` ([ns_text_decoder_decode](file:///home/tytso/northstar-web-browser/src/js_encoding.c#L204-L230)) reads `*len` bytes from the freed heap chunk `bytes` and constructs a JavaScript string from it, providing an immediate **Heap Use-After-Free memory disclosure primitive** (leaking heap pointers and metadata to defeat ASLR, as well as reading sensitive freed data in the single-process heap). - `crypto.subtle` operations ([ns_wc_copy_buffer](file:///home/tytso/northstar-web-browser/src/js_webcrypto.c#L326-L332)) likewise copy from the freed pointer. - **Remediation:** Do not call `globalThis.ArrayBuffer.isView` or `JS_GetPropertyStr(ctx, v, "buffer")`; use QuickJS C APIs (`JS_GetTypedArrayBuffer`) and keep the `JSValue buf` reference alive until the caller has finished reading `*data` (or return a `g_memdup2` copy allocated before `JS_FreeValue(ctx, buf)`). --- ### VULN-05 [CRITICAL]: Universal CSRF Defense Bypass (`Origin`, `Sec-Fetch-Site`, `Sec-Fetch-User` Spoofing, Cookie Attachment & Missing CORS Preflight) - **Locations:** - [page_session.c](file:///home/tytso/northstar-web-browser/src/page_session.c#L339-L343) (`ns_page_session_open`) - [libnorthstar.c](file:///home/tytso/northstar-web-browser/src/libnorthstar.c#L1540-L1605) (`browser_open_common`) - [net.c](file:///home/tytso/northstar-web-browser/src/net.c#L4837-L4841) (`ns_net_set_navigation_fetch`) - [net.c](file:///home/tytso/northstar-web-browser/src/net.c#L4914-L4925) (`ns_net_request_origin`) - [net.c](file:///home/tytso/northstar-web-browser/src/net.c#L5010-L5051), [net.c](file:///home/tytso/northstar-web-browser/src/net.c#L5210-L5248) (`ns_fetch_sync_hop`) - [js.c](file:///home/tytso/northstar-web-browser/src/js.c#L16736-L16845), [js.c](file:///home/tytso/northstar-web-browser/src/js.c#L17805-L17905) (`ns_xhr_send`, `ns_window_fetch`) - **Root Cause:** 1. When a webpage on `https://evil.example` navigates or submits a `<form method="POST" action="https://victim.example/transfer">`, [ns_page_session_open](file:///home/tytso/northstar-web-browser/src/page_session.c#L339-L343) executes: ```c if (!restored) ns_browser_set_next_navigation( referrer && url && ns_url_same_origin(referrer, url) ? referrer : NULL, user_activated != 0); ``` Because `referrer` (`https://evil.example`) and `url` (`https://victim.example/transfer`) are cross-origin, `ns_page_session_open` passes **`referrer = NULL`** to `ns_browser_set_next_navigation`! 2. In [browser_open_common](file:///home/tytso/northstar-web-browser/src/libnorthstar.c#L1601-L1604), `referrer` (`NULL`) is passed as `top_url` to `ns_engine_post_blocking` / `ns_engine_fetch_blocking`. 3. Inside [ns_fetch_sync_hop](file:///home/tytso/northstar-web-browser/src/net.c#L5010-L5248), when `top_url == NULL`: - `effective_top_url = top_url ? top_url : url` (line 5010) becomes `https://victim.example/transfer`. - `top_origin` (line 5011) becomes **`https://victim.example`**. - On a `POST` request, [ns_net_request_origin](file:///home/tytso/northstar-web-browser/src/net.c#L4920-L4923) returns `top_origin`, causing Northstar to send **`Origin: https://victim.example`** (spoofing the victim's own origin on a cross-site POST from `evil.example`!). - Because `top_url == NULL`, lines 5211–5212 send **`Sec-Fetch-Site: none`** instead of `Sec-Fetch-Site: cross-site`. - Because [ns_net_set_navigation_fetch](file:///home/tytso/northstar-web-browser/src/net.c#L4837-L4841) ignores `user_activated` (`(void)user_activated;`) and lines 5244–5245 unconditionally append `Sec-Fetch-User: ?1`, Northstar sends **`Sec-Fetch-User: ?1`** even when the POST was auto-submitted by script (`form.submit()`)! - Because `top_url == NULL` and `effective_top_url == url`, lines 5045–5051 select `victim.example`'s first-party cookie partition and attach all of `victim.example`'s cookies! 4. Furthermore, neither `fetch()` nor `XMLHttpRequest` ever sends a CORS preflight `OPTIONS` request before issuing cross-origin `PUT`/`DELETE`/`PATCH` or custom-header requests, sending the state-changing request directly to the server first. - **Impact:** Completely defeats `Origin` header validation, `Sec-Fetch-Site` / `Sec-Fetch-User` Fetch Metadata validation, first-party cookie partitioning, and CORS preflight protections against Cross-Site Request Forgery (CSRF). - **Remediation:** Pass `referrer` unconditionally in `ns_page_session_open`; wire `user_activated` into `ns_net_set_navigation_fetch`; and implement CORS `OPTIONS` preflight requests for non-safelisted cross-origin `fetch()` and `XMLHttpRequest` calls. --- ### VULN-06 [CRITICAL]: `northstar-unsafe-continue:` Scheme Bypasses Navigation Restrictions to Overwrite Browser Settings (`about:settings-save`) & Read Local Files (`file:`) - **Locations:** - [safebrowsing.h](file:///home/tytso/northstar-web-browser/src/safebrowsing.h#L13) (`NS_UNSAFE_CONTINUE_SCHEME`) - [libnorthstar.c](file:///home/tytso/northstar-web-browser/src/libnorthstar.c#L1194-L1214) (`browser_allows_navigation_url`, `browser_resolve_navigation`) - [libnorthstar.c](file:///home/tytso/northstar-web-browser/src/libnorthstar.c#L1545-L1579) (`browser_open_common`) - [net.c](file:///home/tytso/northstar-web-browser/src/net.c#L4382-L4421), [net.c](file:///home/tytso/northstar-web-browser/src/net.c#L4446-L4481), [net.c](file:///home/tytso/northstar-web-browser/src/net.c#L4615-L4630) - **Root Cause:** 1. [browser_allows_navigation_url](file:///home/tytso/northstar-web-browser/src/libnorthstar.c#L1194-L1202) only blocks `"about:"` and `"file:"` URLs when navigating from a web origin. It does **not** block `"northstar-unsafe-continue:"`. 2. In [browser_open_common](file:///home/tytso/northstar-web-browser/src/libnorthstar.c#L1540-L1561), Northstar consumes `g_pending_referrer` (`g_pending_referrer = NULL`), strips all `northstar-unsafe-continue:` prefixes in a `while` loop, adds the target host to `ns_safebrowsing_allow_host(host)`, and recursively calls `browser_open_common(real, ...)` **without re-checking `browser_allows_navigation_url`** and with `g_pending_referrer == NULL`! 3. In the recursive call, because `referrer` (`top_url`) is now `NULL` and `navigation` is `TRUE`, `about_request_from_chrome(NULL, TRUE)` returns `TRUE`, `ns_file_access_allowed(NULL)` returns `TRUE`, and `resolve_local_path` converts bare filesystem paths (`/etc/passwd`) into `file:///etc/passwd`. - **Impact:** Any untrusted webpage can auto-submit `<form method="POST" action="northstar-unsafe-continue:about:settings-save">` to overwrite `~/.config/northstar/northstar.conf` (hijacking `doh_url` to a malicious DNS-over-HTTPS server, changing `home_url`, or disabling `https_first`), POST to `northstar-unsafe-continue:about:settings-clear` to wipe all browser history/cookies/storage, or navigate to `northstar-unsafe-continue:file:///etc/passwd` and `northstar-unsafe-continue:about:history`. - **Remediation:** Reject `northstar-unsafe-continue:` in `browser_allows_navigation_url` unless the active document is a Safe Browsing interstitial, and require the stripped target URL to be `http://` or `https://`. --- ### VULN-07 [CRITICAL]: Heap Buffer Overflow in WOFF/SFNT Web Font Reconstruction (`ns_font_woff_to_sfnt`) - **Location:** [font.c](file:///home/tytso/northstar-web-browser/src/font.c#L215-L285) (`ns_font_woff_to_sfnt`) - **Root Cause:** When loading a `@font-face` web font on Linux, `ns_font_woff_to_sfnt` reconstructs an SFNT font buffer from a FreeType `FT_Face`: ```c for (FT_UInt i = 0; i < num; i++) { FT_ULong tag = 0, tlen = 0; if (FT_Sfnt_Table_Info(face, i, &tag, &tlen)) { bad = TRUE; break; } tabs[i].tag = tag; tabs[i].len = tlen; ... } ... buf = too_big ? NULL : g_try_malloc0(off); if (buf) { ... for (FT_UInt i = 0; i < num; i++) { FT_ULong tlen = tabs[i].len; if (FT_Load_Sfnt_Table(face, tabs[i].tag, 0, buf + tabs[i].off, &tlen)) { ``` - `FT_Sfnt_Table_Info(face, i, &tag, &tlen)` queries SFNT table entry `i` **by table index**. - `FT_Load_Sfnt_Table(face, tabs[i].tag, 0, buf + tabs[i].off, &tlen)` looks up the table **by 4-byte tag**, which in FreeType (`tt_face_load_any` / `sfnt_load_table`) always finds the **first** table entry matching `tabs[i].tag` and copies that first table's entire length into `buf + tabs[i].off` (ignoring the input `tlen` when `offset == 0`)! - If a crafted font contains two table directory entries with the **same 4-byte tag** where the first entry has length $L_1$ (e.g., 1 MB) and the last entry has length $L_2 < L_1$ (e.g., 16 bytes), `buf` is allocated with only $L_2$ bytes remaining at `buf + tabs[num - 1].off`, and `FT_Load_Sfnt_Table` writes $L_1$ bytes of attacker-controlled font data past the end of the heap buffer `buf`! - **Impact:** Deterministic **heap buffer overflow** (up to 64 MB of controlled bytes) triggered by any webpage loading a crafted `@font-face` font. - **Remediation:** Reject fonts containing duplicate SFNT table tags in the `FT_Sfnt_Table_Info` loop before allocating `buf`. --- ### VULN-08 [CRITICAL]: Heap Use-After-Free in IndexedDB (`ns_idb_backend_put`) & Multi-Threaded Race UAF on `g_blob_js_registry` - **Locations:** - [idb.c](file:///home/tytso/northstar-web-browser/src/idb.c#L49-L75), [idb.c](file:///home/tytso/northstar-web-browser/src/idb.c#L616-L640), [idb.c](file:///home/tytso/northstar-web-browser/src/idb.c#L739-L825) (`ns_idb_open_handle`, `ns_idb_insert_index_entries`, `ns_idb_backend_put`) - [js.c](file:///home/tytso/northstar-web-browser/src/js.c#L18778-L18901) (`g_blob_js_registry`, `ns_url_createObjectURL`, `ns_js_net_blob_resolver`) - **Root Cause:** 1. **IndexedDB Re-Entrant Getter UAF:** In [ns_idb_backend_put](file:///home/tytso/northstar-web-browser/src/idb.c#L747-L824), Northstar obtains an unrefcounted `ns_idb_db *h = ns_idb_open_handle(origin, db_name, FALSE)` from the 16-slot `g_idb_handles` table and calls [ns_idb_insert_index_entries](file:///home/tytso/northstar-web-browser/src/idb.c#L616-L640) at line 811. `ns_idb_insert_index_entries` calls `JS_GetPropertyUint32` / `JS_GetPropertyStr` / `JS_ToCString` on user-supplied `entries`. A JS getter on `entries` that calls `indexedDB.deleteDatabase(db_name)` (or opens 16 other databases) evicts and frees `h->db` and `h->path` while `ns_idb_insert_index_entries` and `ns_idb_backend_put` continue executing SQLite operations on the freed `h->db` and reading freed `h->path`! 2. **Multi-Threaded `g_blob_js_registry` UAF:** `g_blob_js_registry` ([js.c](file:///home/tytso/northstar-web-browser/src/js.c#L18778)) and per-instance `owner->blob_urls` are mutated by main-thread pages and Web Worker threads (`URL.createObjectURL` / `revokeObjectURL` / `ns_js_free`) and read concurrently by async network threads (`ns_js_net_blob_resolver`) **with no mutex** (and no origin check in `ns_js_net_blob_resolver`). - **Remediation:** Extract all JS values from `entries` into C structs before calling `ns_idb_open_handle`; protect `g_blob_js_registry` and `blob_urls` with a mutex and enforce same-origin checks in `ns_js_net_blob_resolver`. --- ### VULN-09 [HIGH]: Cross-Origin CSS & Quirks-Mode Arbitrary Response Read via `window.__ns_linked_css` - **Locations:** - [js.c](file:///home/tytso/northstar-web-browser/src/js.c#L15628-L15640) (`ns_linked_css_text`), [js.c](file:///home/tytso/northstar-web-browser/src/js.c#L49048-L49050) (`__ns_linked_css`) - [engine.c](file:///home/tytso/northstar-web-browser/src/engine.c#L187-L249) (`g_linked_css`, `engine_remember_linked_css`, `ns_engine_linked_css_text`, `fetch_css_bytes`) - [polyfills.js](file:///home/tytso/northstar-web-browser/data/js/polyfills.js#L7162-L7169) (`sheetFor`) - **Root Cause:** Whenever `<link rel="stylesheet" href="...">` is fetched ([engine.c](file:///home/tytso/northstar-web-browser/src/engine.c#L740-L745)), the raw response bytes are stored in a process-global hash table `g_linked_css` keyed by URL ([engine.c](file:///home/tytso/northstar-web-browser/src/engine.c#L190-L200)). [js.c](file:///home/tytso/northstar-web-browser/src/js.c#L49048) exposes `__ns_linked_css(url)` on the page's `globalThis` ([ns_linked_css_text](file:///home/tytso/northstar-web-browser/src/js.c#L15628-L15640)), which returns the full raw text for any URL in `g_linked_css` **with zero origin or CORS checks**. Furthermore, in quirks mode (a document without `<!DOCTYPE html>`, where `strict_css_mime` is `FALSE` at [engine.c](file:///home/tytso/northstar-web-browser/src/engine.c#L782)), [fetch_css_bytes](file:///home/tytso/northstar-web-browser/src/engine.c#L235-L241) accepts **any** response MIME type (`text/html`, `application/json`, `text/plain`) unless the server sends `X-Content-Type-Options: nosniff`. - **Impact:** Any quirks-mode webpage can embed `<link rel="stylesheet" href="https://victim.example/account">` and call `window.__ns_linked_css("https://victim.example/account")` to read the **raw cross-origin HTML/JSON response body verbatim**, as well as read stylesheets cached in `g_linked_css` from previously visited sites. - **Remediation:** Remove `__ns_linked_css` from untrusted page globals, partition stylesheet caches by top-level site, enforce `text/css` MIME requirement for all cross-origin stylesheets regardless of quirks mode, and require same-origin or CORS before exposing `sheet.cssRules`. --- ### VULN-10 [HIGH]: Privileged `about:` and `view-source:` Access Bypass from `about:blank` / `about:srcdoc` and `<a download>` - **Locations:** - [net.c](file:///home/tytso/northstar-web-browser/src/net.c#L4446-L4481) (`about_request_from_chrome`, `ns_about_url_is_public`) - [net.c](file:///home/tytso/northstar-web-browser/src/net.c#L4760-L4810) (`synthesize_view_source_response`) - [libnorthstar.c](file:///home/tytso/northstar-web-browser/src/libnorthstar.c#L1225-L1234) (`browser_js_download`) - [procwindow.c](file:///home/tytso/northstar-web-browser/src/gtk/procwindow.c#L779-L797) (`download_worker`) - **Root Cause:** 1. **`about:blank` / `about:srcdoc` Privilege Confusion:** In [net.c](file:///home/tytso/northstar-web-browser/src/net.c#L4446-L4451), `about_request_from_chrome` checks `g_str_has_prefix(top_url, "about:")`, and [synthesize_view_source_response](file:///home/tytso/northstar-web-browser/src/net.c#L4766-L4767) checks `!g_str_has_prefix(top_url, "about:")`. Because `g_str_has_prefix(top_url, "about:")` matches **unprivileged** `about:blank`, `about:srcdoc`, and `about:start`, any script running in a context whose `top_url` is `about:blank` or `about:srcdoc` passes the chrome check and can `fetch("about:history")`, `fetch("about:settings-data")`, `fetch("about:bookmarks")`, or `fetch("view-source:file:///etc/passwd")`! 2. **`browser_js_download` Fallback Bypass:** In [browser_js_download](file:///home/tytso/northstar-web-browser/src/libnorthstar.c#L1225-L1234): ```c char *abs = browser_resolve_navigation(b, url); g_free(b->pending_download); b->pending_download = g_strdup_printf("%s\t%s", abs ? abs : url, filename ? filename : ""); ``` When a page triggers `<a href="file:///home/user/.ssh/id_rsa" download="key.txt">` or `<a href="about:settings-data" download="cfg.json">`, `browser_resolve_navigation` returns `NULL` (blocked), but `abs ? abs : url` **falls back to the blocked `url`**! Then [download_worker](file:///home/tytso/northstar-web-browser/src/gtk/procwindow.c#L784) calls `ns_net_fetch_blocking(d->url, NULL, &err)` with `top_url = NULL`, copying arbitrary local files or privileged `about:` pages directly into `~/Downloads/<filename>`. - **Remediation:** In `about_request_from_chrome` and `synthesize_view_source_response`, explicitly exclude `about:blank` and `about:srcdoc`. In `browser_js_download`, return immediately if `abs == NULL`. --- ### VULN-11 [HIGH]: WebExtension Content-Script Main-World Compromise, Symlink Traversal, CSS Injection & Wildcard ReDoS - **Locations:** - [ext.c](file:///home/tytso/northstar-web-browser/src/ext.c#L71-L93) (`ns_ext_wildcard`), [ext.c](file:///home/tytso/northstar-web-browser/src/ext.c#L1220-L1242) (`ns_dnr_match_here`) - [ext.c](file:///home/tytso/northstar-web-browser/src/ext.c#L369-L403) (`content_shim`), [ext.c](file:///home/tytso/northstar-web-browser/src/ext.c#L1003-L1158) (`ns_ext_content_scripts_for_url`) - [ext.c](file:///home/tytso/northstar-web-browser/src/ext.c#L437-L450) (`ns_ext_safe_path`) - [ext.c](file:///home/tytso/northstar-web-browser/src/ext.c#L832) (`ns_abp_parse_cosmetic`) - [js.c](file:///home/tytso/northstar-web-browser/src/js.c#L57483-L57492) - **Root Cause:** 1. **Setter Trap on `globalThis.__nd_ext_*` for `document_end` / `document_idle` Scripts:** In [js.c](file:///home/tytso/northstar-web-browser/src/js.c#L57483-L57492), `ns_ext_content_scripts_for_url(..., FALSE)` runs **after** all page scripts have executed. When it runs, [ext.c](file:///home/tytso/northstar-web-browser/src/ext.c#L1109-L1126) attaches the raw C functions `__nd_ext_sread`, `__nd_ext_swrite`, `__nd_ext_manifest`, and `__nd_ext_url` to the page's `globalThis` using `JS_SetPropertyStr`. A page script that defines a setter (`Object.defineProperty(window, '__nd_ext_sread', { set(fn) { ... } })`) intercepts the raw C functions! Because `__nd_ext_sread(ext_id, area)` and `__nd_ext_swrite(ext_id, area, json)` accept any `ext_id` string as their first argument, the webpage gains full read/write access to **every installed extension's storage**. 2. **Global Intrinsics Poisoning Even for `document_start` Scripts:** Even when `at_start == TRUE`, [content_shim](file:///home/tytso/northstar-web-browser/src/ext.c#L377-L401) looks up `JSON.parse`, `JSON.stringify`, `Object.keys`, `Array.isArray`, and `Promise.resolve` dynamically from the shared page `globalThis` whenever `chrome.storage.local.get/set` is called later. 3. **Symlink Traversal in `ns_ext_safe_path` ([ext.c](file:///home/tytso/northstar-web-browser/src/ext.c#L437-L450)):** Uses lexical `g_canonicalize_filename` instead of `realpath()`, allowing symlinks inside an extension directory to read arbitrary host files via `northstar-extension://`. 4. **Cosmetic Filter CSS Injection ([ext.c](file:///home/tytso/northstar-web-browser/src/ext.c#L832)) & Exponential Wildcard ReDoS ([ext.c](file:///home/tytso/northstar-web-browser/src/ext.c#L71-L93)):** `ns_abp_parse_cosmetic` checks `!strchr(sel, '{')` but does not reject `}`, allowing CSS rule injection; `ns_ext_wildcard` and `ns_dnr_match_here` use $O(2^N)$ recursive `*` backtracking. - **Remediation:** Run extension content scripts in a separate QuickJS `JSContext` (isolated world), bind `ext_id` in C closure data, use `realpath()` in `ns_ext_safe_path`, reject `}` in `ns_abp_parse_cosmetic`, and replace recursive `*` matching with a linear two-pointer matcher. --- ### VULN-12 [HIGH]: Unpartitioned Bytecode Cache Leaks Cross-Origin Script URLs & Touches Disk in Private Mode - **Location:** [bytecode_cache.c](file:///home/tytso/northstar-web-browser/src/bytecode_cache.c#L95-L101), [bytecode_cache.c](file:///home/tytso/northstar-web-browser/src/bytecode_cache.c#L130-L136), [bytecode_cache.c](file:///home/tytso/northstar-web-browser/src/bytecode_cache.c#L268-L392) - **Root Cause:** 1. **Cross-Origin URL Leak via `Error.prototype.stack`:** [key_for](file:///home/tytso/northstar-web-browser/src/bytecode_cache.c#L95-L101) keys the global in-memory (`g_mem`) and on-disk (`~/.cache/northstar/bytecode/`) QuickJS bytecode cache **solely by `SHA-256(src)`**, with no top-level site partition key and no script URL in the hash. However, [precompile_run](file:///home/tytso/northstar-web-browser/src/bytecode_cache.c#L375) compiles the script passing `job->url ? job->url : "<script>"` as the filename, which QuickJS bakes into the serialized `JSFunctionBytecode`! When any other origin loads a script with identical source bytes, `JS_ReadObject` deserializes the cached bytecode containing the **first origin's full URL (including query parameters / tokens)**, which is immediately readable by the second origin via `Error.prototype.stack`! 2. **Private Mode Reads Disk Cache (`g_utime`) and Populates `g_mem`:** In [ns_bytecode_cache_get](file:///home/tytso/northstar-web-browser/src/bytecode_cache.c#L268-L312), `private_mode` is not checked before reading disk entries: private browsing reads cached bytecode from disk, updates on-disk file `mtime` via `g_utime(path, NULL)` ([bytecode_cache.c](file:///home/tytso/northstar-web-browser/src/bytecode_cache.c#L133))—leaking visited scripts forensically—and populates `g_mem` in RAM across the session. - **Remediation:** Include both the top-level site partition key and the script's own URL in `key_for`, and completely bypass both `g_mem` and disk in `ns_bytecode_cache_get` / `ns_bytecode_cache_store` during private mode. --- ### VULN-13 [HIGH]: Multiple Content Security Policy (CSP), Worker & ServiceWorker Bypasses - **Locations:** - [fetch_policy.c](file:///home/tytso/northstar-web-browser/src/fetch_policy.c#L67-L79) (`destination_csp_kind`) - [js.c](file:///home/tytso/northstar-web-browser/src/js.c#L21181-L21235), [js.c](file:///home/tytso/northstar-web-browser/src/js.c#L21498-L21540), [js.c](file:///home/tytso/northstar-web-browser/src/js.c#L22218-L22394) (`ns_worker_script_url_allowed`, `ns_worker_import_scripts`, `ns_worker_js_new`) - [js.c](file:///home/tytso/northstar-web-browser/src/js.c#L21779-L21807), [js.c](file:///home/tytso/northstar-web-browser/src/js.c#L22877-L22955) (`ns_sw_controller_for`, `ns_sw_register`) - [js.c](file:///home/tytso/northstar-web-browser/src/js.c#L55177-L55226) (`ns_js_run_script_element`) - [eventsource.c](file:///home/tytso/northstar-web-browser/src/eventsource.c#L327-L335) (`ns_eventsource_worker`) - [js_realm.c](file:///home/tytso/northstar-web-browser/src/js_realm.c#L97-L120) (`ns_shadow_realm_evaluate`) - [csp.c](file:///home/tytso/northstar-web-browser/src/csp.c#L224-L285), [csp.c](file:///home/tytso/northstar-web-browser/src/csp.c#L385-L464) - **Root Cause:** 1. **Redirect Bypass for `<script src>`, `<link rel="stylesheet">`, `fetch()`, and `<object data>`:** [destination_csp_kind](file:///home/tytso/northstar-web-browser/src/fetch_policy.c#L67-L79) returns `NS_CSP_KIND_COUNT` (no CSP check) for `NS_FETCH_DEST_SCRIPT`, `NS_FETCH_DEST_STYLE`, and `NS_FETCH_DEST_DEFAULT`, so [ns_fetch_policy_check](file:///home/tytso/northstar-web-browser/src/fetch_policy.c#L114-L120) skips `script-src`, `style-src`, and `connect-src` during HTTP redirects ([net.c](file:///home/tytso/northstar-web-browser/src/net.c#L5732-L5745)), and [ns_js_run_script_element](file:///home/tytso/northstar-web-browser/src/js.c#L55177-L55226) never re-checks `resp->final_url`. 2. **Workers Have `js->csp == NULL` & `importScripts()` Skips CSP:** [ns_worker_js_new](file:///home/tytso/northstar-web-browser/src/js.c#L22218-L22394) never copies the parent document's `ns_csp` onto the worker's `ns_js`, and [ns_worker_import_scripts](file:///home/tytso/northstar-web-browser/src/js.c#L21498-L21540) performs no `script-src` check, so all worker `fetch()`, `XHR`, `WebSocket`, and `importScripts()` calls bypass CSP completely. 3. **ServiceWorker Registration on Plain `http://` & Arbitrary Parent Scope Hijacking:** [ns_sw_register](file:///home/tytso/northstar-web-browser/src/js.c#L22877-L22955) allows registering ServiceWorkers on insecure `http://` origins and does not verify that `scope` is beneath the script's directory path; and [ns_sw_controller_for](file:///home/tytso/northstar-web-browser/src/js.c#L21791) uses raw `strncmp` without a path-boundary `/` check (`/app` matches `/admin`). 4. **`EventSource` Redirect Bypass & `ShadowRealm.prototype.evaluate` `'unsafe-eval'` Bypass:** [ns_eventsource_worker](file:///home/tytso/northstar-web-browser/src/eventsource.c#L327-L335) enables `CURLOPT_FOLLOWLOCATION` without redirect policy checks, and [ns_shadow_realm_evaluate](file:///home/tytso/northstar-web-browser/src/js_realm.c#L97-L120) calls `JS_Eval` without checking `ns_js_eval_allowed(ctx)`. 5. **Case-Sensitive CSP Keyword Matching & Empty-Host Wildcard Bug:** [csp.c](file:///home/tytso/northstar-web-browser/src/csp.c#L224-L236) and [csp.c](file:///home/tytso/northstar-web-browser/src/csp.c#L385-L464) match `'none'`, `'self'`, `'unsafe-inline'`, `'unsafe-eval'`, `'strict-dynamic'`, `'nonce-...'`, and `'sha256-...'` using case-sensitive `strcmp` / `g_str_has_prefix`, and in [token_matches_url](file:///home/tytso/northstar-web-browser/src/csp.c#L281) an empty host token (`https://`) matches any URL with an empty hostname. --- ### VULN-14 [HIGH]: Linux Sandbox Escape Vectors & Pre-Sandbox File Truncation - **Locations:** - [appmain.c](file:///home/tytso/northstar-web-browser/src/appmain.c#L386-L396), [appmain.c](file:///home/tytso/northstar-web-browser/src/appmain.c#L508-L535) - [trace.c](file:///home/tytso/northstar-web-browser/src/trace.c#L69-L81) (`ns_trace_enable`) - [security.c](file:///home/tytso/northstar-web-browser/src/security.c#L437-L497), [security.c](file:///home/tytso/northstar-web-browser/src/security.c#L677-L678), [security.c](file:///home/tytso/northstar-web-browser/src/security.c#L873-L885) - [procwindow.c](file:///home/tytso/northstar-web-browser/src/gtk/procwindow.c#L962) (`download_worker`) - **Root Cause:** 1. **Unconfined Thread Spawned Before Landlock (`ns_thread_dump_dispatch`):** In [appmain.c](file:///home/tytso/northstar-web-browser/src/appmain.c#L508), `ns_thread_dump_install_signal()` calls `pthread_create` ([threaddump.c](file:///home/tytso/northstar-web-browser/src/threaddump.c#L189)) **before** `ns_security_sandbox_init()` runs at line 535. Because `landlock_restrict_self(rfd, 0)` only restricts the calling thread, `ns_thread_dump_dispatch` runs **completely unconfined by Landlock** for the lifetime of the process! 2. **Seccomp `PROT_EXEC` Filter Bypass via `memfd_create`:** [ns_security_deny_exec_memory](file:///home/tytso/northstar-web-browser/src/security.c#L878-L881) only blocks `mmap` when **both** `PROT_EXEC` and `MAP_ANONYMOUS` are set (`(PROT_EXEC | MAP_ANONYMOUS)`), while `memfd_create` and `memfd_secret` are allowlisted in seccomp ([security.c](file:///home/tytso/northstar-web-browser/src/security.c#L677-L678)). Writing shellcode to a `memfd` and calling `mmap(NULL, len, PROT_READ | PROT_EXEC, MAP_PRIVATE, fd, 0)` bypasses the filter! Moreover, `download_worker` ([procwindow.c](file:///home/tytso/northstar-web-browser/src/gtk/procwindow.c#L962)) never calls `ns_security_deny_exec_memory`, and `remap_file_pages` is allowlisted in seccomp ([security.c](file:///home/tytso/northstar-web-browser/src/security.c#L729)). 3. **Host Command Execution & Persistent Compromise via Landlock `fs_rw` Paths:** - [security.c](file:///home/tytso/northstar-web-browser/src/security.c#L458) grants full `fs_rw` to `g_get_user_runtime_dir()` (`/run/user/$UID`), exposing `/run/user/$UID/bus` (D-Bus user session bus) and `/run/user/$UID/systemd/private`, allowing a compromised process to ask `systemd --user` or D-Bus (`org.freedesktop.systemd1` / `g_app_info_launch_default_for_uri`) to execute arbitrary host binaries outside the sandbox. - [security.c](file:///home/tytso/northstar-web-browser/src/security.c#L491) checks `if (dl_dir && home && g_str_has_prefix(dl_dir, home))` and grants `fs_rw` to `dl_dir`. If `XDG_DOWNLOAD_DIR` is `$HOME`, `g_str_has_prefix(home, home)` is `TRUE` and Landlock grants **full read/write access to the entire `$HOME` directory**! - [security.c](file:///home/tytso/northstar-web-browser/src/security.c#L460-L469) grants `fs_rw` to `~/.local/share/northstar`, where [ext.c](file:///home/tytso/northstar-web-browser/src/ext.c#L1003-L1006) autoloads extensions from `~/.local/share/northstar/extensions/`. 4. **Pre-Sandbox Arbitrary File Truncation via `--trace=<path>`:** In [appmain.c](file:///home/tytso/northstar-web-browser/src/appmain.c#L525-L528), `ns_trace_enable(trace_path)` ([trace.c](file:///home/tytso/northstar-web-browser/src/trace.c#L69-L81)) calls `g_fopen(path, "w")` **before** `ns_security_sandbox_init()` at line 535. --- ### VULN-17 [MEDIUM]: XML DOCTYPE Parser Differential Bypassing XHTML Well-Formedness Gate (`ns_xml_well_formed` vs. `ns_xml_parse`) - **Locations:** - [html_lexbor.c](file:///home/tytso/northstar-web-browser/src/html_lexbor.c#L571-L579) (`ns_xml_well_formed`) - [xml.c](file:///home/tytso/northstar-web-browser/src/xml.c#L233-L270) (`xml_parse_internal_entities`) - [xml.c](file:///home/tytso/northstar-web-browser/src/xml.c#L321-L334) (`xml_skip_misc_and_doctype`) - **Root Cause:** [ns_xml_well_formed](file:///home/tytso/northstar-web-browser/src/html_lexbor.c#L571-L579) skips `<!DOCTYPE ...>` by stopping at the very first `>` character regardless of `[` depth; [xml_skip_misc_and_doctype](file:///home/tytso/northstar-web-browser/src/xml.c#L321-L334) counts `[` and `]` brackets without respecting quoted strings (`<!ENTITY a "]>">`); and [xml_parse_internal_entities](file:///home/tytso/northstar-web-browser/src/xml.c#L233-L270) parses `<!ENTITY` declarations inside `<!-- ... -->` XML comments. --- ### VULN-18 [MEDIUM]: Cross-Origin `BroadcastChannel` Missing Origin Check & Forbidden `Set-Cookie` / CORS Header Exposure - **Locations:** - [js.c](file:///home/tytso/northstar-web-browser/src/js.c#L11878-L11935) (`ns_broadcast_post_message`) - [js.c](file:///home/tytso/northstar-web-browser/src/js.c#L17285-L17309) (`xhr_populate_from_response`), [js.c](file:///home/tytso/northstar-web-browser/src/js.c#L17760-L17782) (`fetch_build_response`) - **Root Cause:** 1. `ns_broadcast_post_message` matches `BroadcastChannel` instances solely by channel name (`strcmp(ns, cns) == 0`) without comparing `_origin`, allowing cross-origin frames to send and receive messages on any channel name. 2. `fetch_build_response` and `xhr_populate_from_response` copy all `resp->raw_headers` into `Response.headers` and `XHR._headers` without stripping `Set-Cookie`/`Set-Cookie2` or filtering cross-origin headers by `Access-Control-Expose-Headers`. --- ### VULN-19 [MEDIUM]: Media, Canvas, WASM & Concurrency Bugs 1. **VP9 Monochrome (`I400`) Null-Pointer Dereference ([vp9.c](file:///home/tytso/northstar-web-browser/src/vp9.c#L24-L41), [yuv.c](file:///home/tytso/northstar-web-browser/src/yuv.c#L75-L79)):** `image_to_texture` hardcodes `.monochrome = FALSE` even when a VP9 frame is monochrome (`image->planes[1] == NULL`), causing `ns_yuv_to_texture` to dereference `NULL` chroma pointers. 2. **Signed Integer Overflows in `ns_audio_context_stream_push` ([audio.c](file:///home/tytso/northstar-web-browser/src/audio/audio.c#L1321)) & `c2d_setLineDash` ([js_canvas.c](file:///home/tytso/northstar-web-browser/src/js_canvas.c#L561), [js_canvas.c](file:///home/tytso/northstar-web-browser/src/js_canvas.c#L1986)):** `frames * channels * (int)sizeof(float)` in `audio.c` and `(int)total` in `c2d_setLineDash` can overflow 32-bit signed `int`. 3. **WebAssembly Shared `wasm_module_t` Import Global Mutation ([wasm.c](file:///home/tytso/northstar-web-browser/src/wasm.c#L1439), [wasm.c](file:///home/tytso/northstar-web-browser/src/wasm.c#L1472)):** `ns_wasm_bind_imports` mutates `mod->module` in-place via `wasm_runtime_link_import_global` without locking or cloning across multiple instantiations. 4. **Data Races on Unsynchronized Global Tables ([camera.c](file:///home/tytso/northstar-web-browser/src/camera.c#L13-L14), [safebrowsing.c](file:///home/tytso/northstar-web-browser/src/safebrowsing.c#L16-L18)):** `g_camera_decisions` / `g_camera_pending` and `g_blocked` / `g_allow` are accessed across threads without a mutex, and `camera.c` collapses all opaque origins (`data:`, `file:`, sandboxed iframes) into a single shared `"null"` or `"this page"` permission key. --- ### VULN-20 [LOW]: CRLF Injection in WebSocket/EventSource Headers & Config File Newline Injection - **Locations:** - [ws.c](file:///home/tytso/northstar-web-browser/src/ws.c#L454-L468) (`ns_ws_worker`) - [eventsource.c](file:///home/tytso/northstar-web-browser/src/eventsource.c#L350-L360) (`ns_eventsource_worker`) - [config.c](file:///home/tytso/northstar-web-browser/src/config.c#L406-L441) (`ns_config_save`) - **Root Cause:** - `ns_ws_worker` formats `User-Agent` directly into the raw HTTP/1.1 WebSocket upgrade request without stripping `\r`/`\n`, and `ns_eventsource_worker` appends `Last-Event-ID` to `curl_slist` without filtering `\r`/`\n`. - `ns_config_save` writes string settings (`home_url`, `user_agent`, `doh_url`, etc.) to `~/.config/northstar/northstar.conf` without stripping `\n` or `\r`, allowing any newline in a string setting to inject arbitrary `key = value` configuration directives on next launch.

