jso-protector/runtime/third-party-inventory is the browser sensor. jso-protector/runtime/managed-integrity is the policy and incident control plane. The account dashboard now persists and versions policies at /dashboard/web-integrity.aspx, while the public ETag-enabled policy endpoint lets the browser sensor enforce them without exposing account credentials. Apply App_Data/CreateWebIntegrityTables.sql before enabling it.
Block unknown dynamic scripts
const inventory = require("jso-protector/runtime/third-party-inventory");
inventory.attach(window, {
originAllowlist: ["https://js.stripe.com", "https://cdn.example.com"],
inlineContentAllowlist: ["e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"],
enforcementMode: "block",
beaconUrl: "/v1/runtime/beacon.ashx",
onBlocked(decision) { lockCheckout(decision); }
});
Block mode neutralizes a dynamically-created script before its src is assigned when the origin is unknown or the script is injected after page load. Pre-existing parser-inserted scripts still require CSP and SRI for deterministic pre-execution blocking.
The dashboard can publish durable versioned policies. Load one directly with attachFromPolicy(window, { policyUrl: "/v1/runtime/integrity-policy.ashx?id=..." }); public responses use an ETag and five-minute cache window while containing no account credentials or secrets.
Inline allowlist values use the sensor's native digest format: exactly 64 hexadecimal SHA-256 characters, without a sha256- prefix. Policy creation is bounded to 25 policies per account and 100 origins plus 100 inline hashes per policy.
Fence protected data at browser egress
const dataGuard = require("jso-protector/runtime/data-exfiltration-guard");
dataGuard.attach(window, {
id: "checkout-egress", version: "1", mode: "block",
allowedOrigins: [location.origin, "https://api.stripe.com"],
protectedFieldNames: ["accountNumber"]
});
The guard watches fetch, XHR, sendBeacon, WebSocket sends, and programmatic form submission. Built-in selectors cover password and payment autocomplete fields; add application-specific selectors or field names explicitly. It blocks only when protected data is sent to an unapproved destination. Incident snapshots retain destination origin, field names, counts, transport, and action, but never field values or request bodies.
This is a defense-in-depth browser control, not a substitute for CSP, SRI, server-side tokenization, or a managed SOC. It cannot reliably identify the originating script for every JavaScript call, and already-encoded or encrypted payloads may evade value matching. Start in monitor mode, review destinations, then enable block.
Version and operate policy
const managed = require("jso-protector/runtime/managed-integrity");
const policy = managed.createManagedIntegrityPolicy({
id: "checkout", version: "2026-07-13.1", mode: "block",
allowedOrigins: ["https://js.stripe.com"],
expectedContentBySrc: approvedHashes
});
const decision = managed.evaluateSnapshot(policy, inventorySnapshot);
const operations = managed.createIntegrityOperations();
operations.ingest(decision);
The operations layer fingerprints repeated violations, increments occurrence counts, supports open/reviewing/resolved/ignored transitions, records assignee and resolution data, and exports portable JSON for retention or SIEM handoff.
Operational boundary
The hosted product stores policies and receives runtime incidents; customers can also run the package control plane in their own worker or collector. A managed monitoring contract, 24/7 analyst response, regulatory attestation, and incident-response ownership remain service and organizational commitments rather than properties software can create.
Frequently asked questions
What is the difference between the sensor and the control plane?
One watches, the other decides. The third-party inventory module is the browser sensor: it observes script origins, inline content hashes, content swaps and late injection on the page. The managed integrity module is the policy and incident side, where a versioned policy is published, incidents are deduplicated, and each one is assigned and worked through a status. You can run the sensor alone and collect signal, and the control plane is what turns that signal into something a team operates.
What can block mode actually stop, and what can it not?
It neutralises a dynamically created script before its source is assigned, when the origin is unknown or the script is being injected after page load. That covers the injection pattern behind most third-party incidents. What it does not cover is a script the parser already knew about when the page was delivered, because by then the decision point has passed. For those you still want a content security policy and subresource integrity, which block deterministically before execution. The two mechanisms are complementary rather than alternatives.
What format do inline allowlist entries take?
The sensor's native digest format: exactly sixty-four hexadecimal characters, with no algorithm prefix. This is a common source of a policy that silently matches nothing, because the prefixed form used in content security policy headers looks similar and is not accepted here. If an inline script you expected to allow keeps producing incidents, check the entry format before looking anywhere else.
Does the public policy endpoint expose our account?
No. It is designed so the browser can fetch a policy without carrying credentials, and the public response contains no account identifiers or secrets. It is served with an entity tag and a short cache window so repeated page loads do not turn into repeated full fetches. That separation is what lets the sensor enforce a centrally managed policy from an untrusted context.
Are there limits on how many policies and entries we can publish?
Yes, and they are worth knowing before you design your rollout. Policy creation is bounded per account, and each policy is bounded in how many origins and inline hashes it can carry. The practical consequence is that a policy per page template does not scale, whereas a small number of policies covering meaningfully different surfaces does. Group by risk surface rather than by route.
What should we do before switching enforcement on?
Apply the integrity table migration, then run in monitoring mode long enough to see a full traffic cycle. The inventory you collect is the real input to your allowlist, because the set of origins a production page loads is almost always larger than the set anyone expects. Move to blocking once the incident stream is quiet and you understand every entry, and keep a route back to monitoring for the release where something unexpected appears.