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.

Reply via email to