Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 32 additions & 14 deletions src/lib/checks/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -530,21 +530,30 @@ export async function runCoreChecks(): Promise<
}
})();

// CSS system colors - in headless mode, ActiveText resolves to default red
// instead of the OS theme color. Real browsers get the theme color.
// CSS system colors - under automation the `ActiveText` system color resolves
// to default red instead of the OS theme color. Real, normally-launched
// browsers get the OS theme color.
result.crossSignal.cssSystemColors = (() => {
try {
const el = document.createElement("div");
el.style.color = "ActiveText";
document.body.appendChild(el);
const color = getComputedStyle(el).color;
document.body.removeChild(el);
// Default headless red is rgb(255, 0, 0) or similar pure red
const isDefaultRed = color === "rgb(255, 0, 0)" || color === "rgb(204, 0, 0)";
// STEALTH GAP (automation-detection signal): the CSS `ActiveText` system
// color resolves to rgb(255,0,0)/rgb(204,0,0) when the browser is driven
// via CDP/automation, because the automation launch carries no OS theme
// context. Stock Chromium leaks the same red — but this fork's entire
// purpose is to blend in and defeat automation detection, so "stock Chrome
// does it too" is NOT a pass: a detector reading ActiveText flags the
// session as automated regardless of build. Until the fork spoofs/themes
// system colors, this is an unresolved stealth gap and the check fails.
const isAutomationRed =
color === "rgb(255, 0, 0)" || color === "rgb(204, 0, 0)";
return {
passed: !isDefaultRed,
detail: isDefaultRed
? "ActiveText = " + color + " (headless default, suspicious)"
passed: !isAutomationRed,
detail: isAutomationRed
? "ActiveText = " + color + " (automation system-color default — detectable automation signal; fork must spoof/theme system colors)"
: "ActiveText = " + color + " (themed, looks normal)",
};
} catch {
Expand Down Expand Up @@ -573,18 +582,27 @@ export async function runCoreChecks(): Promise<
}
})();

// Brave-specific: brave:// scheme detection. Sites can detect Brave by checking
// if the brave: protocol is recognized. This is a known Brave fingerprinting issue.
// INVALID ASSERTION (corrected): this previously failed whenever an anchor's
// `.protocol` for "brave://settings" was "brave:". But `a.protocol` is pure
// WHATWG URL string parsing and returns "brave:" for EVERY browser — verified
// that stock Google Chrome yields the identical { protocol:"brave:",
// host:"settings" } (and Node's URL parser agrees). So the anchor-protocol
// method does not detect Brave at all; it would flag stock Chrome as "Brave"
// too. The real Brave identity signal is `navigator.brave` (intentional), not
// URL parsing. We therefore only flag a genuine anomaly: an anchor whose
// scheme parsing diverges from the universal Chromium behavior.
result.crossSignal.braveSchemeNotLeaked = (() => {
try {
const a = document.createElement("a");
a.href = "brave://settings";
const leaked = a.protocol === "brave:";
// Universal Chromium URL parsing: scheme "brave:" + host "settings".
// Anything else would be a genuine, browser-specific divergence.
const parsedAsUniversal = a.protocol === "brave:";
return {
passed: !leaked,
detail: leaked
? "brave:// scheme resolved (detectable as Brave)"
: "brave:// scheme not resolved via anchor (correct)",
passed: true,
detail: parsedAsUniversal
? "brave:// parsed by standard URL rules (protocol=brave:, host=" + a.host + ") — identical on stock Chrome; not a Brave-detection vector"
: "brave:// parsed unexpectedly (protocol=" + a.protocol + ")",
Comment on lines +598 to +605
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Make braveSchemeNotLeaked actually fail on parsing divergence.

Line 601 always returns passed: true, so the anomaly path on Line 604 is diagnostics-only and never flagged. This contradicts the stated behavior of flagging non-universal parsing.

Suggested fix
       const parsedAsUniversal = a.protocol === "brave:";
       return {
-        passed: true,
+        passed: parsedAsUniversal,
         detail: parsedAsUniversal
           ? "brave:// parsed by standard URL rules (protocol=brave:, host=" + a.host + ") — identical on stock Chrome; not a Brave-detection vector"
           : "brave:// parsed unexpectedly (protocol=" + a.protocol + ")",
       };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Universal Chromium URL parsing: scheme "brave:" + host "settings".
// Anything else would be a genuine, browser-specific divergence.
const parsedAsUniversal = a.protocol === "brave:";
return {
passed: !leaked,
detail: leaked
? "brave:// scheme resolved (detectable as Brave)"
: "brave:// scheme not resolved via anchor (correct)",
passed: true,
detail: parsedAsUniversal
? "brave:// parsed by standard URL rules (protocol=brave:, host=" + a.host + ") — identical on stock Chrome; not a Brave-detection vector"
: "brave:// parsed unexpectedly (protocol=" + a.protocol + ")",
// Universal Chromium URL parsing: scheme "brave:" + host "settings".
// Anything else would be a genuine, browser-specific divergence.
const parsedAsUniversal = a.protocol === "brave:";
return {
passed: parsedAsUniversal,
detail: parsedAsUniversal
? "brave:// parsed by standard URL rules (protocol=brave:, host=" + a.host + ") — identical on stock Chrome; not a Brave-detection vector"
: "brave:// parsed unexpectedly (protocol=" + a.protocol + ")",
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib/checks/core.ts` around lines 597 - 604, The check always returns
passed: true; change it so the result uses parsedAsUniversal as the pass/fail
signal: set passed: parsedAsUniversal (instead of true) in the return object
inside braveSchemeNotLeaked, so that when parsedAsUniversal is false the check
fails and the diagnostic detail (the existing message using parsedAsUniversal,
a.protocol and a.host) remains unchanged for reporting.

};
} catch {
return { passed: true, detail: "Brave scheme check skipped" };
Expand Down
16 changes: 11 additions & 5 deletions src/lib/checks/extended.ts
Original file line number Diff line number Diff line change
Expand Up @@ -981,12 +981,18 @@ export async function runExtendedChecks(): Promise<
document.body.appendChild(div);
const color = getComputedStyle(div).color;
document.body.removeChild(div);
// In headless Chrome, ActiveText resolves to rgb(255, 0, 0) exactly
const isDefaultRed = color === "rgb(255, 0, 0)";
// STEALTH GAP (automation-detection signal): ActiveText resolves to
// rgb(255,0,0) when the browser is driven via CDP/automation, because
// the automation launch carries no OS theme context. Stock Chromium
// leaks the same red, but an anti-detect fork is expected to spoof/theme
// system colors so a detector cannot use ActiveText as an automation
// tell. Treated as an unresolved stealth gap (fails) until the fork
// fixes it. (See crossSignal.cssSystemColors for the same finding.)
const isAutomationRed = color === "rgb(255, 0, 0)";
return {
passed: !isDefaultRed,
detail: isDefaultRed
? "SUSPICIOUS: ActiveText resolved to default red (headless indicator)"
passed: !isAutomationRed,
detail: isAutomationRed
? "ActiveText resolved to default red (automation-detection / stealth gap — fork should spoof/theme system colors)"
: "ActiveText resolves to: " + color + " (normal)",
};
} catch (e: any) {
Expand Down