Beifahrer

Privacy

Beifahrer

This page is a static file: no cookie, no analytics, nothing from a third party. Whoever serves it may keep ordinary web-server access logs of the request.

Privacy statement

The text below is the statement Beifahrer makes about itself. Every substantive claim carries a file:line into the tree this was written against (0.1.0, branch off b79a9bd), so a reviewer can check it rather than take it on trust. Claims that cannot be checked in code are written as such rather than asserted.

Publish this as a web page and put its URL in every store form. Chrome, Edge and AMO all ask for one, and Chrome's programme policy is explicit that an inaccurate privacy policy — including one that contradicts the extension's behaviour — is grounds for removal (programme policies).


1. What Beifahrer does

Beifahrer is a browser extension. It lets an AI agent work in your own browser, in the profile and session you already have open — your logged-in tabs, your extensions, your history. It does not start a second browser.

The agent talks to the browser over a small local program — the bridge — that you run on your own machine. The bridge is the process the agent talks to; it holds no data of its own and is not a service.

For every action the agent wants to take, Beifahrer checks a per-site policy that you set, and then asks you about the actions the policy does not already cover. The order is fixed and every method goes through it:

  1. are you paused? — the kill switch refuses everything, including listing your tabs
  2. is the feature switched on? — one switch per capability
  3. the per-site level you set for that origin
  4. the browser's own host permission for that origin
  5. for changes, a confirmation window

Only then does the agent reach the page. extension/src/handlers.ts:1-13 states the order; extension/src/handlers.ts:1430 runs steps 1 and 2 before any handler can be reached, and extension/src/handlers.ts:168 runs step 3 for each method.

The policy fails closed. An unknown origin is none. A non-web address has no origin. A method that belongs to no feature is refused. packages/core/src/features.ts:188-194 is the first two steps; extension/src/handlers.ts:169 refuses anything the policy does not allow and does not mark askable.

2. The policy is enforced in the extension, not in the bridge

The bridge is the process the agent talks to, so a check that lived there would be a check the agent's side controls. The decision is made in the extension, in code the agent cannot reach: packages/core/src/policy.ts decides, extension/src/handlers.ts:168 calls it before every page access, and the bridge has no call to it — app/src/bridge/bridge.ts imports REQUIRED_LEVEL for one thing only, how long to wait for an answer (app/src/bridge/bridge.ts:126).

The bridge's own MCP layer refuses to expose a tool that a client marked read-only without readOnlyHint: true, and fails closed by dropping it (applyReadOnlyGate, called in app/src/frontends/mcp/server.ts). The gate itself is @gjsify/mcp's since 0.54.0 — it was this repository's own runtime.ts, the third verbatim copy of curlew's, until then — and app/tests/unit/mcp/gate.test.ts pins the direction it compares in, because a gate this repository does not own is the one case where "it was tested here once" stops being evidence.

Not verifiable in code: what the operator of the bridge does outside this repository. If you run a bridge someone else built, that code decides what the agent may ask for. The statement above is about Beifahrer's own bridge, which is this repository.

3. The bridge listens on your machine only, and only for this extension

The bridge binds 127.0.0.1 — the loopback interface, which is not reachable from the network (app/src/bridge/bridge.ts:156). A connection is refused in the handshake, before a socket exists, unless both hold: the peer address is a loopback address (packages/core/src/protocol.ts:548) and the handshake's Origin is a browser extension origin — moz-extension:, chrome-extension:, ephy-webextension: or safari-web-extension: (packages/core/src/protocol.ts:582, used at app/src/bridge/bridge.ts:161-162). A web page cannot put one of those origins on a WebSocket handshake, so a page on any site that opens ws://127.0.0.1:<port> never reaches the token at all.

The token is compared in constant time (packages/core/src/protocol.ts:570).

The extension only ever builds ws://127.0.0.1:<port>/, with the port taken from its own configured range (extension/src/bridge-client.ts:141). There is no host, no name, no configuration value that could point it elsewhere.

4. Nothing leaves your device

There is no telemetry, no analytics, no crash reporting, no update pings, and no remote endpoint of any kind. The only network connection the extension opens is the loopback socket above.

This is checkable, and the check is worth doing again after any change:

You are the only party to any of it. The bridge is your process, on your machine, reading your extension's storage and your browser.

What the extension declares

For the Firefox build the manifest declares data_collection_permissions: { required: ['none'] } (extension/manifest.ts:151), Mozilla's category for "nothing leaves the device". That claim is consistent with the code above and with the whole of section 4: the only channel the extension has is the loopback socket, and the bridge it reaches is the one you started.

5. Where your data lives

Everything Beifahrer knows is in your browser profile, in the extension's own storage. Nothing is written to the bridge's storage, and nothing is sent to a server.

WhatWhereCode
your per-site policy, feature switches, pause state, token, portstorage.local of this profileextension/src/settings.ts:45-70, written at extension/src/settings.ts:73
temporary grants ("all sites", "for this session")storage.session — never in the stored policy, gone when the browser restartsextension/src/grants.ts:6
the activity log you see in the popupstorage.session where the browser has it, otherwise memory onlyextension/src/activity.ts:7-8
saved sessions (your windows and tabs)storage.local of this profile, never on the bridgeextension/src/sessions-store.ts:4-5, read at extension/src/sessions-store.ts:38
the request log, when you switch it onin memory, one buffer per tab, capped at 200 rows, dropped when the tab closes or has been quiet for ten minutesextension/src/network.ts:52,73-77,89-95

Saved sessions living in the browser rather than beside the agent is a decision with its own rationale, ADR 0004.

What the activity log holds: the time, the method in words, the host, the outcome, and a capped preview of a fill. Never page text (extension/src/activity.ts:5-6).

6. What the agent can see, and what it cannot

7. Why the permissions are asked for one origin at a time

A WebExtension host permission is a browser-level, all-or-nothing grant. Requesting every site up front would be the one thing this project must never do: it would make the install prompt — the one moment a person can actually say no — a list of nothing.

So Beifahrer declares no host permissions in the install prompt at all. All three patterns are optional (extension/manifest.ts:26, wired at extension/manifest.ts:114 for Manifest V3 and extension/manifest.ts:120 for Manifest V2):

Every grant is checked at the moment of use, and the browser's grant is a second fence behind your policy, not a replacement for it (extension/src/handlers.ts:176; the reason the policy — exact origin, port included — rather than the browser's per-host grant is the gate is written down at extension/src/settings.ts:76-83).

A temporary grant gives the host access back when it ends (extension/src/grants.ts:145).

8. The optional permissions, and what each one buys

None of these is granted at install. Each is requested in the same click that switches the feature on, and the switch stays off if you say no.

PermissionWhat it buysAsked whereWhy it is not up front
webRequestSee page requests — a log of what a page requested, with timings. Off by default.extension/entrypoints/options/main.ts:203a request log of everything your browser does is a browsing history with timestamps, and unlike a host permission it cannot be narrowed to one site — there is no per-origin form of it (extension/manifest.ts:29-38, packages/core/src/features.ts:101-105)
<all_urls>Screenshots — the browser's captureVisibleTab accepts nothing narrower, and Firefox does not even define it without the grant. Off by default.extension/entrypoints/options/main.ts:172the browser's own API has no narrower form (extension/manifest.ts:21-23, checked per call at extension/src/handlers.ts:1039)
http:/// + https:///Saved sessions and tab management — saving, restoring, sorting, pinning, closing, grouping windows and tabs. Off by default.extension/entrypoints/popup/main.ts:202a session is a list of your tabs, so this is your browsing history; it belongs behind a switch you set, not in the install prompt
downloadsTake hidden downloads — see a download the page starts out of sight and remove the browser's copy once the agent has the bytes. Off by default; the permission is asked for in the same click and only listened to while a capture runs.extension/src/saves.ts; extension/entrypoints/options/main.tsthe permission can list and erase downloads, so it is optional, its own switch, and never used outside a capture (ADR 0019)
webRequest + script featureRunning the agent's own script in a page — off by default, needs the write level, and always asks, showing you the whole scriptextension/entrypoints/confirm/main.ts:134; packages/core/src/policy.ts:219a script is code you have not read running in a page you are logged into; it gets its own switch, and no setting can silence it (ADR 0012)

The remaining declared permissions need no prompt and touch no site by themselves: tabs, storage, alarms, sessions, tabGroups (extension/manifest.ts:92) — and the capabilities behind sessions and tabGroups are off by default (packages/core/src/features.ts:114-115).

9. What the extension does not do

10. Children and sensitive sites

Beifahrer is a developer tool. It is not directed at children, and no age gate is claimed.

You can block a site outright — a tab on it then shows its host only and nothing may be read or changed on it, and a block is not overridden by a temporary grant. Do that for a banking, health or employer site, and remember that a frame embedded from another origin is judged separately, so a block on the top site does not cover what the page embeds.

11. Changes to this statement

This file is the statement. If a future version changes what the extension does, this file changes with it, in the same commit — the claims are file:line citations precisely so that a change to the code makes the statement visibly wrong rather than quietly stale.

Contact: the support address in the store listing. (A person must supply it — see README.md.)


A human decision remains in three places

  1. The URL to publish this at. Chrome, Edge and AMO all require a URL that resolves. None exists in the repository.
  2. The support contact, named at the end and required by AMO's form.
  3. Whether to say anything about the bridge operator's side. Section 2 marks what is not verifiable in this repository. If Beifahrer will be shipped with a bridge someone else built, that paragraph needs to become a promise someone else keeps, and a person has to decide whether this project can make it.

Back to Beifahrer