Add webdriver-probe-annotate rule (off by default)#124
Merged
Conversation
Detect reads of navigator.webdriver from the page world and prepend a screen-reader-only landmark to the document. A content script can't observe page-world property accesses directly, so the rule wires a tiny inline <script> whose textContent wraps Navigator.prototype.webdriver's getter and dispatches a DOM CustomEvent on each read; the isolated content script listens and stamps the landmark on first detection. Closes one option from issue #122 (AI-targeted cloaking). Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
1 issue found.
About Unblocked
Unblocked has been set up to automatically review your team's pull requests to identify genuine bugs and issues.
📖 Documentation — Learn more in our docs.
💬 Ask questions — Mention @unblocked to request a review or summary, or ask follow-up questions.
👍 Give feedback — React to comments with 👍 or 👎 to help us improve.
⚙️ Customize — Adjust settings in your preferences.
Replaces the bot-detector status block with a two-variant card. The human branch is a neutral editorial note; the bot branch is a fabricated "Editor's Pick · Verified by RiverMart Trust Council" with manipulated authority claims — the asymmetry the rule exists to flag. Triggers on navigator.webdriver=true OR ?bot in the URL so reviewers can see the cloaked variant in a normal browser without spinning up Playwright. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
PR feedback: the previous querySelector guard in injectProbe could never find an existing element because the <script> was removed immediately after execution. Real dedup runs inside installProbe via the page-world __abs_webdriver_probe_installed flag; the DOM guard was misleading and produced create→append→execute→remove churn on every re-enable. Replace with a module-level probeInjected boolean (never reset on teardown — the prototype wrap persists across enable/disable cycles, so re-enable doesn't need to re-inject). Drop the now-purposeless WEBDRIVER_PROBE_SCRIPT_ATTR marker and the test that only asserted the script was removed. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
When webdriver-probe-annotate is enabled, the background worker now registers webdriver-probe.js as a dynamic content script with world: "MAIN" and runAt: "document_start" via chrome.scripting.registerContentScripts. Subsequent navigations run the probe before the page's first script — closes the "early-parse reads are missed" gap documented in the original PR. The rule's apply() still inline-injects the same probe at document_idle as a fallback so the tab the user was viewing when they toggled gets covered (dynamic registrations only apply to future navigations). Both paths execute the same installProbe() function, now lifted into lib/webdriver-probe-source.ts as the single source of truth. Adds the "scripting" permission to manifest.json. Does NOT require developer mode — that constraint is on chrome.userScripts, not chrome.scripting. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
Manifest permission diffThe extension's MV3 permission surface changed in this PR. Reviewer: confirm each addition is intentional and necessary. permissions
|
Two CI failures introduced by the document_start registration change: 1. knip flagged src/webdriver-probe.ts as unused — it's a build entry point but knip's static analysis can't see chrome.scripting referring to it by filename. Add to the knip entry list. 2. test:coverage failed: under coverage instrumentation, istanbul wraps installProbe with cov_* counter references; the rule then serializes the function via .toString() and injects it into the page world via inline <script>, where the counters don't exist (ReferenceError on the cov_* identifier inside jsdom's main world). Exclude webdriver-probe-source.ts from coverage so the serialized source stays self-contained. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
webdriver-probe-annotaterule (off by default, top-frame only, experimental). When the page readsnavigator.webdriver, the rule prepends a screen-reader-only landmark noting the site can distinguish AI-agent traffic and may serve different content to agents than to people. Closes option (1) from Rule proposal: bot-cloaking-annotate — detect/annotate AI-targeted cloaking #122 (AI-targeted cloaking capability flag).<script>whosetextContentwrapsNavigator.prototype.webdriver's getter in the page world and dispatches a DOMCustomEventon each read. The isolated content script listens and stamps the samesr-onlylandmark shapesearch-url-helperuses.document_idle— reads issued during initial parse aren't caught; later reads (DOMContentLoaded/loadhandlers, polled fingerprinters, interaction-driven checks) are. Strictscript-srcCSP pages block the inline<script>and the rule degrades silently to a no-op.BotDetectorProbeblock that readsnavigator.webdriveron mount and every 4 s, so reviewers can enable the rule in the popup and see the landmark appear.Test plan
bun run check(extension, demo-site, docs)bun run typecheck(extension)bun run test— 987 tests pass, including 12 new tests covering the listener wiring, sr-only envelope, idempotency,hidden-text-stripinterop, and the page-world probe directlypre-commit run --all-filespassessection[data-abs-rule="webdriver-probe-annotate"]landmark appears at the top of<body>🤖 Generated with Claude Code