BEX Tracer v1
Objective
Identify which browser extensions are active in a Chrome session from page-context JavaScript. The challenge loads a secret subset of a published extension pool, opens a static bait page, performs fixed interactions, and compares the miner's boolean predictions with the hidden subset.
The miner must detect extension behavior. Chrome Web Store IDs are not exposed by the task and are not stable at runtime.
Current defaults
| Setting | Value |
|---|---|
| Extension pool | 89 names |
| Groups | 8 |
| Enabled per round | 12, fixed |
Rounds per POST /score |
6 |
| Round execution | Sequential, fresh browser profile each round |
| Page settle | 6 seconds |
| Post-interaction settle | 1.5 seconds |
| Detector budget | 10 seconds |
| Maximum file size | 750 lines and 262,144 bytes |
| Browser | Chrome for Testing 152.0.7977.54 |
These values describe the current deployment defaults. The deployed task and OpenAPI schema take precedence if the challenge is reconfigured.
Task contract
GET /task publishes:
random_val, a cache-busting value used by the subnet protocol;extension_names, the complete pool by display name;groups, a map from each group name to the extension names it owns.
Example, shortened for readability:
{
"random_val": "a1b2c3d4e5f6g7h8",
"extension_names": [
"uBlock Origin Lite",
"AdGuard AdBlocker"
],
"groups": {
"ad_blockers": [
"uBlock Origin Lite",
"AdGuard AdBlocker"
]
}
}
Never hardcode the group list. Generate the required files from
miner_input.groups because pool organization can change.
Submission contract
Return exactly one commit file per group:
{
"commit_files": [
{
"file_name": "ad_blockers.js",
"content": "window.detect_ad_blockers = async function () { return {}; };"
}
]
}
The example contains one group only to show the shape. A real response must include every group returned by the task, with no missing, duplicate, or unexpected file names.
Each <group>.js file must define window.detect_<group>:
window.detect_ad_blockers = async function () {
return {
"uBlock Origin Lite": true,
"AdGuard AdBlocker": false,
};
};
Rules:
- Return booleans keyed by exact extension display names.
- Answer only for names owned by that file's group.
- Missing names count as
false. - Names outside the published pool are discarded.
- A detector may be synchronous or asynchronous.
- One group throwing, hanging, or returning invalid data makes only that
group's labels
false; other groups still contribute. - Every file is limited to 750 lines and 262,144 UTF-8 bytes.
Browser environment
Every round uses a fresh Chrome profile and a fresh secret scratch path. The
challenge copies only the 12 selected unpacked extensions into that path.
Because their manifests contain no fixed key, Chrome derives different
extension IDs every round.
The bait page is served at https://baitpage.test:10443/_web through a
loopback mapping. It contains stable detection surfaces including:
- ad-shaped elements and tracker-like resources;
- email, password, textarea, and contenteditable fields;
- cookie controls, links, images, canvas, and common browser APIs;
- six deterministic clicks, keystrokes, and scroll actions.
Useful signals include modified browser APIs and values, wrapped native functions, injected DOM or styles, request blocking, post-interaction UI, and timing. Some extensions may not expose a useful signal on the bait page.
The challenge's Compose file does not restrict network egress. Do not depend on external services: deployment networking can differ and detectors should remain deterministic.
Scoring
Each round compares all 89 labels, including the 77 extensions that are not enabled. It calculates the Matthews correlation coefficient (MCC), clamps negative results to zero, then averages scored rounds:
MCC = (TP × TN - FP × FN)
/ sqrt((TP + FP)(TP + FN)(TN + FP)(TN + FN))
round_score = max(0, MCC)
run_score = mean(round_score)
All-true and all-false predictions score zero because the MCC denominator
vanishes. False positives therefore matter; return true only when a signal
supports it.
Miner-caused failures remain in the average as zero. Browser infrastructure failures are excluded, but the score request fails if more than 20% of rounds lose the browser.
Detection guidance
- Read names and groups from every task.
- Build independent detectors so one weak category does not break the others.
- Prefer multiple specific behavioral signals over a single fragile timing threshold.
- Test both positive and negative cases; MCC rewards true negatives.
- Avoid static store-ID probes because runtime IDs rotate.
- Avoid network dependencies and persistent state between rounds.
API discovery
The deployed challenge exposes Swagger UI at /docs, ReDoc at /redoc,
and its OpenAPI schema at /openapi.json. Use those endpoints to confirm the
current request envelope and authentication requirements.