Security
A browser's attack surface splits in two: the engine we did not write, and the shell we did. The two behave very differently, so we describe them separately. The known gaps in this release are at the end of the page.
The engine: Chromium, V8, Skia
Through 2026, dozens of memory-safety flaws were fixed in Chrome, six of them zero-days exploited in the wild. We do not write this code and we cannot fix it; the only defence here is keeping the engine current.
That is why our rule is blunt: Girginos Browser is not released on an end-of-life Electron version. Electron supports only its last three major versions, and the version pin is checked before every release. We currently ship Electron 44.2.0 with Chromium 152.0.7977.76.
The shell: the code we wrote
These are the architectural decisions on the shell side:
- Every tab is a separate WebContentsView. Page content runs with sandbox: true, contextIsolation: true and nodeIntegration: false, and gets no preload.
- The interface window is sandboxed as well and shares a session with the tabs, so the interface's own requests also pass through the blocker and carry the DNT headers.
- IPC channels are accepted only from the main frame of the interface window. Settings writes go through key and type validation.
- Downloads are addressed by identifier; a raw file path coming from the interface is never opened.
- Page-initiated navigation is limited to http(s) and view-source:http(s). file: and chrome: open only when the user types them into the address bar.
- Handing off to an external application is limited to a narrow scheme list: mailto:, tel:, sms:, magnet:, ftp(s):, webcal:. Only one confirmation dialog can be open at a time.
- Opaque origins — those whose origin is null, such as data: and about: — are always denied on permission requests.
- Spellchecking is disabled, because Chromium downloads its dictionary files from a Google server.
- Data is written atomically, via a temporary file and a rename.
Attack vectors and countermeasures
| Class | Example | Countermeasure |
|---|---|---|
| Address bar spoofing | RLO/bidi, CR-LF, NUL, bank.com@evil.com, whitespace padding, IDN homographs | Invisible characters and spaces stay percent-encoded, credentials are hidden, punycode is shown |
| Domain obfuscation | accounts.google.com.giris.evil.com | The registrable domain is drawn in full colour, the rest is dimmed |
| Internal page impersonation | newtab.html, a downloaded copy | The full address must match; no substring search is done |
| Full-screen interface spoofing | a page goes full screen and paints a fake toolbar | The page view is never expanded over the shell |
| Scheme escape | file:, chrome:, blob:, view-source:file: | Page-initiated navigation is http(s) only |
| External application invocation | ms-msdt:, search-ms:, ms-appinstaller: | A narrow allowlist and a single confirmation dialog |
| Download name tricks | evil.exe / evil.exe., trailing dot or space, extension hidden with RLO | Normalisation before the extension check; the decision follows the real name on disk |
| Blocker evasion | izleyici.com., trailing dot | Host normalisation |
The signed update chain
The threat model assumes the update server may already be compromised. The sequence runs like this:
- The signed manifest and the signature file next to it are fetched.
- The signature is verified over the manifest's raw bytes with the Ed25519 public key embedded in the application. If it does not verify, not a single field is read.
- Version gates are applied: downgrades are refused; a manifest past its own expiry date is refused — this defends against an attacker serving an old manifest forever to freeze updates; an intermediate version is required where necessary; and the download address must be https.
- The version and package digest found by the downloader must match the signed manifest exactly.
- Once the download finishes, the package's sha512 digest is compared against the signed digest in constant time.
- Installation only starts once the user approves it.
If any step fails, no update happens. The private key is never kept on the server; even if the server were taken over, an attacker could not produce a valid manifest.
Tests
118 unit tests, 73 attack-vector regressions and 46 update-verification tests run against the code, and the IPC and DOM contract between the interface and the main process is tested separately. Alongside those, end-to-end verification scripts run before and after each release against real output and the live server.
Known gaps
The following are missing in 0.1.0. Hiding them would make the product look safer than it is, so we are stating them plainly.
- No Mark-of-the-Web
- No Zone.Identifier is written to downloaded files, so Windows SmartScreen does not engage for them. The browser shows its own warning, but the operating-system layer is absent.
- No code signing certificate
- The installer's code signature cannot be verified. The signed manifest closes this for updates, but the first installation remains exposed.
- No Public Suffix List
- On hosting domains such as github.io, site exceptions and address-bar highlighting cover more than they should.
- Certificate errors use the Chromium default
- No custom "proceed anyway" screen was written; on a bad certificate the page simply does not open.
- Blocking is domain-level only
- Trackers hidden behind CNAME records and ads served from the first party are not caught, and no cosmetic filtering is applied.