π Overview Dashboard
Real-time extension behavior analysis toolkit
Run a comprehensive scan to detect the Blocksi extension, probe its service worker, and enumerate its filtering behavior.
π Extension Detection
INFO Fingerprint the Blocksi extension using multiple detection vectors
Attempt to load known extension resources to confirm installation.
Check for chrome.runtime APIs and message channels.
Detect injected content scripts by scanning for known DOM mutations and event listeners.
π₯ Service Worker Stress Test
CRITICAL Overwhelm the service worker with concurrent requests to test resource exhaustion
π URL Manipulation Tests
HIGH Test URL parsing edge cases and authority masking vectors
Test the @ symbol trick and other URL obfuscation methods.
Test multi-hop redirect chains to see if intermediate hops bypass filtering.
πͺ Iframe Nesting Tests
CRITICAL Test deep iframe nesting and content script injection boundaries
Create deeply nested iframe chains to test content script injection limits.
π Category System Explorer
INFO Complete Blocksi v4.3.38 category taxonomy (extracted from source)
β±οΈ Timing Analysis
HIGH Measure extension response times to identify race condition windows
Measure the time between navigation and extension interception.
The extension uses a ping/pong mechanism with a 5-second timeout. Measure the actual response latency.
π Protocol & Scheme Tests
MEDIUM Test various URI schemes and protocol handlers for filter bypass
Test which URI schemes are intercepted by webRequestBlocking.
Test if data: and blob: URIs bypass content filtering.
π Network Intelligence
HIGH Extracted server endpoints, WebSocket targets, and API credentials
| Service | Endpoint | Protocol | Purpose |
|---|---|---|---|
| C2 Socket | wss://k8s-ws-lb.blocksi.net | WebSocket | Real-time command & control |
| LiveKit | wss://livekit.prod.blocksi.net | WebSocket | Screen share / conference |
| TURN Server | turn:webrtc.blocksi.net:3478 | TURN (UDP/TCP) | WebRTC relay |
| Custom Logos | storage.googleapis.com/custom_extension_pages_files/ | HTTPS | School branding assets |
| Type | Value | Source File |
|---|---|---|
| Datadog Client Token | pub9615fc31c443ecb83a61b0a33e432aa2 | offscreen.js |
| TURN Username | blocksi | offscreen.js |
| TURN Credential | blocksi | offscreen.js |
| Datadog Service Name | blocksi_extension | offscreen.js |
π Bypass Lab
Active exploit tests targeting confirmed weaknesses in Blocksi's filtering pipeline
How: Open about:blank in a new window, then use document.write() to inject content.
Why it works: webRequestBlocking never fires for about:blank (no HTTP request). The iframeObserver sees about:blank as top URL but only blocks iframes inside it, NOT the content written directly to the page body.
Content script injection: <all_urls> does NOT match about: scheme - content scripts won't inject.
How: Create a full browsing interface as a data:text/html URI.
Why it works: webRequestBlocking cannot intercept data: scheme. Content scripts don't match data:. The page contains a URL bar and uses fetch to proxy content.
Limitation: CORS blocks most cross-origin fetches, but some APIs and pages with permissive CORS will work.
How: Create a blob: URL containing a full page with navigation interface.
Why it works: blob: URLs are session-scoped, opaque, and not interceptable by webRequest. Each blob URL is unique and unpredictable.
How: Use Google Translate's web proxy to load blocked pages through translate.google.com.
Why it works: Google Translate is typically whitelisted for education. It proxies the entire page content through Google's servers, so the actual domain never appears in webRequest.
Key: Content scripts ARE excluded for docs.google.com per manifest exclude_matches. Google Translate may or may not be excluded.
How: Flood the service worker until it can't respond to its own ping within 5s, triggering chrome.runtime.reload().
Why it works: During SW reload, ALL filtering (webRequest handlers) are temporarily deregistered. The filtering gap lasts 1-3 seconds.
Enhanced: Uses blockPage.html?source=contentScript which contains its own SW ping+reload mechanism, amplifying the attack.
How: Create an iframe with sandbox="allow-scripts" but WITHOUT allow-same-origin.
Why it works: Without same-origin, the frame is treated as a unique opaque origin. Content scripts cannot inject into it. However, webRequest may still block the network request.
How: Content scripts are EXCLUDED from certain domains (see manifest). Navigate through whitelisted domains.
Excluded domains: *.sharepoint.com, *.office.com, *.officeapps.live.com, *.office365.com, docs.google.com
Key insight: These domains have a separate content script config with all_frames: true but different behavior.
How: The iframeObserver delays 100ms on popstate/hashchange before re-checking. Rapidly mutate iframe src to exploit the gap.
Code: window.addEventListener("hashchange", () => setTimeout(() => P(), 100))
Key: The function P() is async and awaits chrome.runtime.sendMessage - there's a gap between the hash change and the filtering response arriving.
π₯ Fragment Injection (CONFIRMED)
CRITICAL Unescaped # in redirect URL causes blockPage query parameter truncation
Root Cause: background.js does NOT encodeURIComponent() the blocked URL before injecting it into the redirect to blockPage.html?url=....
Impact: If a blocked URL contains # (e.g. discord.com/#/...), the browser treats everything after # as the block page's own fragment - all subsequent query parameters (filter, type) are lost.
Code Path: blockPage.js -> new URL(window.location.href).searchParams -> only sees params before #
Confirmed: β
You verified this - block page for discord.com/#/... is missing "Access Denied By: Url Filter" because filter param is truncated.
Generate URLs with fragment payloads to test the block page parameter truncation.
Shows how the block page sees the URL with vs without fragment injection.
π Intelligence Dump
INFO Complete reverse-engineered message protocol and system architecture
All chrome.runtime message types extracted from the extension source.
| ID | Role | File |
|---|---|---|
| contentScript | Content injection & DOM monitoring | contentScript.js |
| serviceWorker | Central hub, filtering, policy | background.js |
| offscreen | Socket I/O, NSFW check, WebRTC | offscreen.js |
| blockPage | Block page UI & access requests | blockPage.js |
| warningPage | Warning page with consent | warningPage.js |
| lockdownPage | Full lockdown overlay | lockdownPage.js |
| headsupPage | "Heads Up" attention page | headsupPage.js |
| assessmentPage | Assessment/exam mode | assessmentPage.js |
| hallPassActivePage | Hall pass timer | hallPassActivePage.js |
| castPage | Teacher screen broadcast | castPage.js |
| conferencePage | LiveKit video conference | conferencePage.js |
| chatPage | Student-teacher chat | chatPage.js |
| classJoinPage | Class enrollment | classJoinPage.js |
| enforcePage | Whitelist-only mode | enforcePage.js |
| bedtimePage | Bedtime lockout | bedtimePage.js |
| Vector | Severity | Description |
|---|---|---|
| π₯ Fragment Injection | CRITICAL | Unescaped # in redirect URL truncates blockPage query params (filter, type). Confirmed: background.js does NOT encode # before building blockPage.html?url= |
| π₯ Block Page Param Loss | CRITICAL | blockPage.js uses new URL(location.href).searchParams - params after unescaped # are lost. 'filter' and 'type' vanish, breaking display logic |
| SW Ping Timeout | CRITICAL | 5s timeout -> chrome.runtime.reload() if SW unresponsive |
| Iframe Observer Race | CRITICAL | MutationObserver + async GET_FILTERING_RESULT has timing gap |
| Warning Page Consent | HIGH | ADD_TO_BW_LIST_FROM_STUDENT -> SW whitelist. warningPage 'Yes' click sends consentUrl from query param, then navigates to it |
| Offscreen Document | HIGH | Single offscreen doc handles socket + NSFW + WebRTC - DoS target |
| Hardcoded TURN Creds | HIGH | Username/password "blocksi"/"blocksi" in cleartext |
| Datadog Token Leak | MEDIUM | pub9615fc31c443ecb83a61b0a33e432aa2 exposed client-side |
| GCS Logo URL | MEDIUM | Predictable storage path for school branding |
| Click Tracking | INFO | Every click on ext pages fires EXT_PAGE_CLICK to SW |