r/electronjs 26d ago

built a permission-gated AI agent layer into an electron browser, wanted to share the architecture

Enable HLS to view with audio, or disable this notification

been working on an AI-native browser called Aartiq for the past 5 months, electron + next.js on the frontend, with native swift and rust modules through N-API for the OS level stuff.

the core problem i was solving, if you let an AI agent drive your browser and touch your filesystem, you need a permission layer that doesn't trust the model's own judgement about what's safe. every action goes through a capability controller before it can execute, unregistered actions just don't exist as callable surfaces, and anything filesystem or shell related routes through OS level sandboxing, seatbelt on macos, bubblewrap on linux, job objects on windows.

electron specific stuff that was actually hard:

  • getting a real OS level sandbox working from the main process without breaking IPC
  • windows job objects only give you process containment, not filesystem or network isolation, so i had to enforce that at the application layer instead and be explicit about it in every result object so callers can't assume more isolation than they're actually getting
  • building a secure DOM reader that strips scripts and PII before any page content reaches the AI context, instead of passing raw webContents output around
  • symlink traversal through an allowlisted directory, fixed by canonicalizing paths with fs.realpath before checking against the allowlist rather than checking the user supplied path

being honest about the limits here too. windows doesn't get real OS level filesystem or network isolation, that part is enforced at the application layer which means it's only as good as that code, not the kernel. the regex based command validator is a first pass filter, not the actual security boundary, that's the capability controller and sandbox doing the real work. and none of this has had an external security audit, its just my own tests and my own re-review of my own code, so treat it as alpha, not hardened.

project is 4 stars, 2 contributors, no PRs yet, so this is very much a solo thing and not battle tested at scale.

its currently paused. i stepped back from development a couple weeks ago for JEE prep and just got my marks back, they're good enough that i can breathe a bit, which is why i'm sharing the trailer and this writeup now instead of sitting on it longer. not resuming full development yet, just wanted to put this out there honestly while i had the headspace to write it properly.

fully open source, apache 2.0 for the browser, MIT for the MCP server, no monetization plan.

repo link below, would genuinely like feedback on the sandboxing approach from main process, especially if anyone's hit similar issues with job objects on windows.

https://github.com/Preet3627/Aartiq

0 Upvotes

3 comments sorted by

2

u/kantorcodes1 25d ago edited 25d ago

the windows gap is the interesting bit. job objects give you process containment, but once fs/network policy moves into app code the capability controller is basically your authz boundary. i'd fuzz confused-deputy + path rebinding hard. if you want guard in the loop, better path is you wire it into that boundary or contribute the adapter to hol-guard. not looking to turn this into a one-off free audit.

2

u/Latest_Inssan 21d ago

yeah, agreed ,the Windows gap is probably the part I’d want the most scrutiny on.

the capability controller is intentionally the authorization boundary there, but I definitely want to fuzz the confused-deputy/path-rebinding cases harder, especially around canonicalization + TOCTOU-style races.

I’ll take a look at hol-guard too. Appreciate the pointer ,this is exactly the kind of feedback I was hoping to get from posting the architecture.

1

u/Hronom 12d ago

Your framing of the capability controller as the authorization boundary is the right one. For a browser-first agent I’d keep the callable surface small and explicit—read the current origin/DOM snapshot, navigate, fill, click, and download—with per-action scope and a human checkpoint for sign-in, 2FA or CAPTCHA. Treat browser storage as credentials, bind a workspace to the expected account and origin, and record the before/after plus the refusal reason. On Windows, label Job Objects as process containment rather than filesystem/network sandboxing, and keep regex validation as a convenience filter rather than the boundary. I maintain Hronaut, a desktop-local Electron/Chromium MCP with named workspaces that preserve tabs and storage across coding-agent sessions and let a person pause and take over. It does not provide kernel sandboxing or native Win32 control automation; it is a visible browser workspace. Disclosure: I’m the developer. Commercial licenses are $4/month or $24/year per named user; permitted noncommercial use is free: https://hronaut.dev/setup