Expand description
JavaScript integrity trap canary probes.
§What is a “JavaScript integrity trap”?
Modern anti-bot vendors (Cloudflare, DataDome, PerimeterX,
Akamai Bot Manager, Kasada) ship detection scripts that look for
artefacts left by patched browser surfaces — places where a
stealth framework rewrote a native prototype, getter, or accessor
and the patch is detectable from the JavaScript side. Classic
examples:
Object.getOwnPropertyDescriptor(Navigator.prototype, "webdriver")returning a data property instead of a native accessor.Function.prototype.toStringshowing patch source code (e.g."function webdriver() { [native code] }") when applied to a patched prototype method.Performance.nowreturning suspiciously round / quantized values that betray deterministic jitter injection.
The traps come in two shapes:
- Suspected — the surface shape is unusual but the signal is
ambiguous (e.g. a non-
native codetoStringon a polyfill that the user’s browser already shipped). - Confirmed — the surface shape is only achievable via a
stealth framework patch on a real browser (e.g.
webdriveris a data property onNavigator.prototype).
§What this module provides
- A stable
IntegrityProbecatalogue with weighted risk contributions and per-probe mitigation hints (seeprobes::all_probes). - A pure-Rust scoring pipeline (
report::IntegrityRiskScore) that turns a set ofprobes::ProbeFindingrecords into an aggregate score and a documented Suspected vs Confirmed classification. - A trend-detection seam (
trend::CanaryTrendObservation) that future canary infrastructure (T84) can subscribe to without modifying the probe set.
§Probe catalogue
The default probe set (see probes::all_probes) covers eight
surfaces:
| Probe | Default weight | What it checks |
|---|---|---|
probes::IntegrityProbeId::WebDriverDescriptorNative | 0.20 | Navigator.prototype.webdriver accessor shape |
probes::IntegrityProbeId::FunctionToStringNative | 0.18 | Function.prototype.toString reports [native code] for patched natives |
probes::IntegrityProbeId::ErrorToStringNative | 0.08 | (function(){}).toString() reports [native code] |
probes::IntegrityProbeId::IntlDateTimeFormatNative | 0.10 | Intl.DateTimeFormat.prototype.format is native |
probes::IntegrityProbeId::RegExpTestNative | 0.08 | RegExp.prototype.test is native |
probes::IntegrityProbeId::CanvasGetImageDataNative | 0.10 | CanvasRenderingContext2D.prototype.getImageData is native |
probes::IntegrityProbeId::PerformanceNowResolution | 0.14 | performance.now() resolution is plausible (not quantized) |
probes::IntegrityProbeId::ProxyTrapObservable | 0.12 | Proxy traps on patched natives do not leak surface state |
§Feature flag
This module is default-on and is always compiled as part of
the stygian-browser crate. The probe set and scoring pipeline
are pure Rust with no I/O so they are safely callable in
deterministic tests without booting Chrome.
§Integration with the existing diagnostic payload
The canary report attaches additively to
crate::diagnostic::DiagnosticReport via
crate::diagnostic::DiagnosticReport::with_integrity_canary
(added in this task) so downstream automation can consume the
finding set without breaking the legacy schema.
§Reuse of the canary trend pipeline (T84)
T84 will add a stealth canary hard-gate. This module exposes
trend::CanaryTrendObservation as the stable seam that
future canary infrastructure can consume without changing probe
definitions: each observation carries the normalized risk score
and a deterministic signature string so two reports with the
same findings produce byte-identical trend entries.
§Example
use stygian_browser::integrity_canary::{
IntegrityCanaryReport, IntegrityProbe, IntegrityRiskClassification,
};
// Simulate a probe set where two probes fired with confirmed traps.
let finding_a = IntegrityProbe::confirmed_finding(
"webdriver_descriptor_native",
0.20,
"Navigator.prototype.webdriver is a data property (should be an accessor)",
);
let finding_b = IntegrityProbe::confirmed_finding(
"performance_now_resolution",
0.14,
"performance.now() values are quantized to 0.1 ms (timing-noise injection)",
);
let report = IntegrityCanaryReport::from_findings(vec![finding_a, finding_b]);
assert!(report.score.value() > 0.0);
assert!(matches!(
report.score.classification(),
IntegrityRiskClassification::Confirmed | IntegrityRiskClassification::Suspected
));
assert_eq!(report.findings.len(), 2);Structs§
- Canary
Trend Observation - Deterministic, JSON-stable trend observation built from an
IntegrityCanaryReport. - Integrity
Canary Policy - Configurable thresholds for the canary risk bands.
- Integrity
Canary Report - Aggregate integrity canary report.
- Integrity
Probe - Single integrity probe definition: stable id, weight, JS evaluation script, description, and mitigation hint.
- Integrity
Risk Score - Aggregate integrity risk score in
[0.0, 1.0]. - Probe
Finding - Captured result of a single integrity probe evaluation.
Enums§
- Integrity
Probe Id - Stable identifier for a built-in integrity probe.
- Integrity
Probe Outcome - Severity outcome of an integrity probe.
- Integrity
Risk Classification - Aggregate risk classification.
- Trend
Severity - Coarse trend severity band.
Constants§
- RISK_
CONFIRMED_ THRESHOLD_ DEFAULT - Default lower bound of the Confirmed risk band.
- RISK_
SUSPECTED_ THRESHOLD_ DEFAULT - Default lower bound of the Suspected risk band.
Functions§
- all_
probes - Return the full built-in integrity probe catalogue.
- probe_
by_ id - Look up a probe by its stable identifier.