diff --git a/scripts/stage-bearnet.sh b/scripts/stage-bearnet.sh index 3f75524..bbf32aa 100755 --- a/scripts/stage-bearnet.sh +++ b/scripts/stage-bearnet.sh @@ -28,7 +28,7 @@ REPO="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" # 1. The pages, loose where resource://bearstart/ resolves. bs="$GRE/browser/bearstart" mkdir -p "$bs" -for f in bearbrowser-start.html bearnet.html cockpit-waiter.html world.json dm-sans-latin.woff2 dm-sans-latin-ext.woff2; do +for f in bearbrowser-start.html bearnet.html beartrap.html cockpit-waiter.html world.json dm-sans-latin.woff2 dm-sans-latin-ext.woff2; do [ -f "$REPO/settings/start/$f" ] && cp "$REPO/settings/start/$f" "$bs/" done # Wordmark SVG referenced by bearbrowser-start.html — sits next to the HTML so diff --git a/settings/start/bearstart-autoconfig.js b/settings/start/bearstart-autoconfig.js index dc6ce11..8aa26dc 100644 --- a/settings/start/bearstart-autoconfig.js +++ b/settings/start/bearstart-autoconfig.js @@ -325,27 +325,40 @@ try { onWindowTitleChange() {}, }); - // Badge the BearNet button when BearTrap catches fingerprinting — so the - // honeypot is visible from anywhere, not just inside the panel. + // Badge the BearNet button when BearTrap catches fingerprinting OR when + // BearWall blocks a vendor host — so the honeypot + firewall are visible + // from anywhere, not just inside the panel. Total count on tooltip; the + // per-kind counts show up on the BearTrap surface page. try { - const fpOrigins = new Set(); + const fpOrigins = new Set(); // fingerprint probe origins seen + const vendorHosts = new Set(); // BearWall-blocked hosts seen + const canaryOrigins = new Set(); // canary-token exfiltration origins + const summary = () => { + const bits = []; + if (fpOrigins.size) bits.push(fpOrigins.size + " fingerprint attempt" + (fpOrigins.size === 1 ? "" : "s")); + if (vendorHosts.size) bits.push(vendorHosts.size + " vendor request" + (vendorHosts.size === 1 ? "" : "s") + " blocked"); + if (canaryOrigins.size) bits.push(canaryOrigins.size + " canary exfiltration" + (canaryOrigins.size === 1 ? "" : "s")); + return bits.length ? bits.join(", ") + " — open BearTrap" : "BearNet — see and block what this browser is talking to"; + }; + const total = () => fpOrigins.size + vendorHosts.size + canaryOrigins.size; Services.obs.addObserver( { observe(subj) { try { const d = subj && subj.wrappedJSObject; - if (d && d.kind === "fingerprint" && d.origin) fpOrigins.add(d.origin); - const n = fpOrigins.size; + if (!d) return; + if (d.kind === "fingerprint" && d.origin) fpOrigins.add(d.origin); + if (d.kind === "vendor-blocked" && (d.dest || d.host)) vendorHosts.add(d.dest || d.host); + if (d.kind === "canary" && d.origin) canaryOrigins.add(d.origin); + const n = total(); + const active = fpOrigins.size + vendorHosts.size + canaryOrigins.size > 0; const e2 = Services.wm.getEnumerator("navigator:browser"); while (e2.hasMoreElements()) { const b = e2.getNext().document.getElementById("bearnet-button"); if (b) { - b.setAttribute( - "tooltiptext", - n + " fingerprinting attempt" + (n === 1 ? "" : "s") + - " caught — open BearNet" - ); - b.setAttribute("beartrap", "1"); + b.setAttribute("tooltiptext", summary()); + b.setAttribute("beartrap", active ? "1" : "0"); + b.setAttribute("data-block-count", String(n)); } } } catch (e) {} @@ -375,8 +388,8 @@ try { if (!Services.appinfo.inSafeMode) { const ENTRIES = [ { id: "bearbrowser-appmenu-bearnet", label: "BearNet — Network Monitor", url: "resource://bearstart/bearnet.html", accessKey: "N" }, - { id: "bearbrowser-appmenu-beartrap", label: "BearTrap — Fingerprint Log", url: "resource://bearstart/bearnet.html#beartrap", accessKey: "T" }, - { id: "bearbrowser-appmenu-bearwall", label: "BearWall — Blocked Vendors", url: "resource://bearstart/bearnet.html#bearwall", accessKey: "W" }, + { id: "bearbrowser-appmenu-beartrap", label: "BearTrap — Fingerprint Log", url: "resource://bearstart/beartrap.html#beartrap", accessKey: "T" }, + { id: "bearbrowser-appmenu-bearwall", label: "BearWall — Blocked Vendors", url: "resource://bearstart/beartrap.html#bearwall", accessKey: "W" }, { id: "bearbrowser-appmenu-cockpit", label: "Cockpit", url: "resource://bearbrowser-cockpit/index.html", accessKey: "C" }, ]; const ensureAppMenuSection = (win) => { diff --git a/settings/start/beartrap.html b/settings/start/beartrap.html new file mode 100644 index 0000000..01bf6d6 --- /dev/null +++ b/settings/start/beartrap.html @@ -0,0 +1,221 @@ + + + + +BearTrap — Fingerprint & Vendor Log + + + + + +
+ +
+ +

BearTrap what the honeypot has caught this session

+ +
connecting to loopback sidecar…
+ +
+ + + +
+ +
+

Every fingerprinting probe the browser sees is caught here — Canvas, WebGL, AudioContext, font enumeration, timing, hardware-concurrency, and more. The origin that ran the probe is recorded so you can see who is trying to identify you.

+
No fingerprint probes caught yet in this session.
+
+ +
+

BearWall enforces a hard denylist of upstream telemetry / update / crash / metrics endpoints. When it blocks a request, the host + count is logged here. If the honeypot sink is enabled, blocked requests are redirected to a loopback endpoint that returns 204 — recorded here.

+
No vendor requests blocked yet in this session.
+
+ +
+

Canary tokens are per-origin sentinel strings BearTrap injects into hidden fields. If a request body contains one, a script scraped the field and is exfiltrating — the origin, destination, and matched token are recorded here.

+
No canary-token exfiltrations detected in this session.
+
+ + + + +