Browser safety (@codecai/web-safety)
Optional client-side safety layer. Catches secrets, PII, jailbreak templates, dangerous commands, and host-blocked patterns before the prompt hits the wire, which keeps doomed inputs out of the inference budget. New in v0.4.
Frameworks
'@codecai/web-safety' is the optional client-side safety layer that ships with Codec v0.4. It's a sibling of '@codecai/web'. Install it alongside when you want to prevent doomed prompts from consuming wire, server inference budget, or classifier-tier compute.
The package is framework-free. Host apps ('leet', 'codec-website', future clients) render their own UI on top of the framework-agnostic 'SafetyGate' state machine.
Install
code (bash):
npm install @codecai/web-safety @codecai/web
Optional peer dependencies, only installed if you opt into the corresponding classifier:
code (bash):
npm install @huggingface/transformers # for the default Prompt Guard 86M classifier
npm install @mlc-ai/web-llm # for the opt-in Llama Guard 3 1B (WebGPU) tier
Two layers
Layer 1 Prefilter (always-on, no network, no model load)
Catches obviously-doomed inputs via regex + Shannon-entropy detection. Pure JavaScript, runs in browsers, Node, edge runtimes. Five categories:
ββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ¬βββββββββββ
β Category β Rules β Examples β
ββββββββββββββββββββββΌβββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββΌβββββββββββ€
β 'secrets' β AWS / GitHub / OpenAI / Anthropic / Google / Slack / Stripe β 'AKIAβ¦', β
β β keys, SSH key headers, JWTs β 'ghp_β¦', β
β β β 'sk-ant- β
β β β β¦' β
β 'pii' β Email, US phone, SSN, Luhn-valid credit-card candidates β n/a β
β 'high_entropy' β base64/hex runs β₯ 24 chars with Shannon β₯ 4.0 bits β Unknown- β
β β β vendor β
β β β API keys β
β 'dangerous_action' β Jailbreak templates, malware/exploit authoring asks, β 'ignore β
β β destructive command literals β previous β
β β β instruct β
β β β ions', β
β β β 'write β
β β β working β
β β β ransomwa β
β β β re', 'rm β
β β β -rf /', β
β β β 'dd β
β β β if=/dev/ β
β β β zero β
β β β of=/dev/ β
β β β sda' β
β 'blocked_action' β Host-supplied patterns, empty by default β Internal β
β β β hostname β
β β β s, β
β β β '--privi β
β β β leged', β
β β β "no β
β β β 'DROP β
β β β TABLE β
β β β prod_*'" β
ββββββββββββββββββββββ΄βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ΄βββββββββββ
code (ts):
import { SafetyGate } from "@codecai/web-safety";
const gate = new SafetyGate({
// Optional: telemetry sink that sees categories + rule IDs only,
// never the matched values.
audit: (e) => {
if (e.kind === "blocked") console.info(`prefilter: ${e.categories}`);
},
});
const decision = gate.check(promptText);
if (decision.kind === "blocked") {
// Host renders a redact / send-anyway / cancel dialog using
// decision.matches; user picks; gate.apply() returns the final
// text or a cancel signal.
const action = await showHostModal(decision);
const result = gate.apply(decision, action);
if (result.kind === "cancel") return;
promptText = result.text; // possibly redacted with [REDACTED:<rule>]
}
// ... tokenize and send via @codecai/web as usual
Layer 3 Browser-side classifier registry (opt-in)
When regex doesn't catch the nuance, fall through to a semantic classifier. The registry mirrors the codec-supervisor server registry exactly so policy decisions stay symmetric across hosts.
Two shipped classifiers:
β’ Prompt Guard 86M (default tier), Transformers.js, β80 MB ONNX, CPU/WASM. Best for always-on inbound-prompt classification.
β’ Llama Guard 3 1B (opt-in tier), codec-web-llm, β1 GB WebGPU quant. Same 14-category Llama Guard taxonomy as the server-side classifier so policy decisions are symmetric across mesh peers.
code (ts):
import { registerPromptGuard86m } from "@codecai/web-safety/classifiers/prompt-guard-86m";
import { registerLlamaGuard31B } from "@codecai/web-safety/classifiers/llama-guard-3-1b";
import { resolveClassifier } from "@codecai/web-safety";
registerPromptGuard86m();
registerLlamaGuard31B(); // opt-in
const { classifier, downgraded } = await resolveClassifier("Llama-Guard-3-1B");
// downgraded === true β registry fell back to Prompt Guard because
// the device couldn't load Llama Guard (no WebGPU, insufficient memory).
// Surface a "downgraded enforcement" badge in your UI.
const result = await classifier.score({ form: "text", payload: userMessage });
if (result.scores.jailbreak >= 0.5) {
// host policy decides: stop, redact, regenerate, flag
}
Host-supplied blocked patterns
Deployments often need patterns the generic rules can't anticipate (internal hostnames, "no 'rm -rf /prod'", regulator-mandated refusals). Inject them via 'PrefilterOptions.blockedActionPatterns':
code (ts):
import { scanText } from "@codecai/web-safety";
const matches = scanText(promptText, {
blockedActionPatterns: [
{ rule: "no_prod_db", pattern: /\b(?:db|database)-prod-\w+\b/g },
{ rule: "no_privileged_run", pattern: /docker\s+run\s+[^\n]*--privileged/g },
{ rule: "no_drop_table_prod", pattern: /\bDROP\s+TABLE\s+prod_\w+/gi },
],
});
These patterns are decided by the host application and don't ship in the npm package. They never cross the wire either. The prefilter runs locally before any encode + send.
Public-by-design vs. server-side private
The client-side prefilter rules are public by design. They ship in the npm package source, visible via 'npm view @codecai/web-safety' or by reading 'src/prefilter.ts' in the Codec repo (https://github.com/wdunn001/Codec/tree/main/packages/web-safety). The vendor-anchored secret patterns are public anyway (AWS publishes the 'AKIA' prefix; GitHub publishes the 'ghp_' prefix); the jailbreak templates are public (well-documented in adversarial-prompt literature); the destructive-command literals are common-knowledge unix.
This is the opposite boundary from the server-side policy disclosure contract introduced in Codec v0.4 (https://github.com/wdunn001/Codec/blob/main/spec/versions/v0.4.md#safety-policy-negotiation):
β’ Server-side, private: operator-internal banned-token-ID lists, regex patterns, classifier thresholds, multi-token patterns. Live in 'codec-supervisor/policies_dir/'. Never serialised to the wire.
β’ Server-side, public: the sanitized descriptor at '.well-known/codec/policies/<id>.json', categories + actions + classifier family + summary counts. Listed publicly so clients can verify what shape of enforcement applies, without leaking what's enforced.
β’ Client-side, public (this package): regex rules that run in the browser before transmission. The output of the prefilter (gate-redacted text, or "user cancelled") reaches the wire, never the rule list.
The two halves are complementary, not duplicating. A host that runs both gets defense-in-depth: cheap regex catches the obvious cases on the client, server-side enforcement catches the subtle cases the model would have otherwise complied with.
See also
β’ '@codecai/web', the base tokenizer + detokenizer this package pairs with.
β’ Codec v0.4 safety-policy negotiation (https://github.com/wdunn001/Codec/blob/main/spec/versions/v0.4.md#safety-policy-negotiation), the wire-level contract.
β’ 'codec-supervisor' (https://github.com/wdunn001/codec-supervisor), the server-side companion shipping the policy admin REST + the matching 'SafetyClassifier' Python registry.
β’ Source on GitHub (https://github.com/wdunn001/Codec/tree/main/packages/web-safety)