JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 44
  • Score
    100M100P100Q98121F
  • License MIT

Zero-dependency TypeScript security filter for LLM streams — redact secrets, enforce tool policy, byte and event modes.

Package Exports

  • llm-stream-guard

Readme

llm-stream-guard

core node runtime deps tests ci status

Security filter for LLM streams — redact secrets and PII, enforce tool-call policy, sanitize errors. Works on raw bytes (TransformStream) and parsed event streams. Declarative JSON/YAML policies and a CLI for offline scans.

A standalone, zero-dependency TypeScript security filter for LLM proxy and agent pipelines. Byte mode: chunk-safe secret redaction on raw SSE. Event mode: tool allow/deny, arg blocking, PII & error sanitization on parsed streams. Policy files + llm-stream-guard scan for CI prep.

Status: Stable 0.5.0 — static manifest audit, GitHub Action, CI dogfood workflow, and audit CLI subcommands. Integration cookbook and examples from 0.4.0 unchanged. Review CHANGELOG.md before upgrades.


Contents


Why stream guard?

When proxying or running agents, unsafe content leaks downstream in predictable ways:

  1. Secrets in text deltas — API keys, bearer tokens, JWTs echoed in model output.
  2. Dangerous tool args — shell injection, exfil URLs, oversized JSON before execution.
  3. Unauthorized tool names — models invoke tools outside your allowlist.
  4. Raw provider errors — internal URLs and stack traces forwarded to browsers.

Many filters scan raw bytes only and miss precise policy on assembled tool_call.done JSON. This library targets both byte and event modes with zero runtime dependencies.

Chunk redaction: secrets split across TCP reads

  • Mid-chunk splits — secrets split across TCP reads use a rolling buffer + prefix holdback (LSG-C).
  • Tool policy timing — evaluate names early; validate args on done when JSON is complete (LSG-T).
  • Violation modesblock, warn, or audit with onViolation for SIEM-friendly logs.

Two modes

Mode API When
Byte createByteGuard() Proxy forwards provider-shaped SSE without parsing
Event guardEvents() Parsed stream — assemble, AI SDK, or custom mapper

Byte mode vs event mode


Architecture

Raw upstream content enters through byte guard or event guard; composable rules redact or block before your proxy, UI, or tool executor sees output.

End-to-end pipeline

Optional pairing with llm-stream-assemble (parse → guard) — cookbook only, no npm coupling:

Ecosystem: optional assemble + guard

Lifecycle and concurrency

Create one GuardContext per stream — never share across concurrent requests. Stateless helpers (pipeGuard, internal transform pipeline) compose into stateful entry points.

GuardContext lifecycle

Diagram sources: docs/img/ (Mermaid .mmd + committed SVG). Regenerate with pnpm diagrams:build.


GuardEvent model

Independent event union — not StreamEvent, not provider types:

GuardEvent mindmap

Type Shape
text { type, phase: delta | done, text }
tool_call { type, phase, id?, name?, args?, argsText? }
reasoning { type, phase, text }
error { type, message, code? }
finish { type, reason? }

Full spec: docs/proposal.MD.


Violation modes

block / warn / audit

Mode Secrets / PII Tool policy
block Always redact Safe substitute + policy_violation finish
warn Always redact Block tool + onViolation
audit Always redact + onViolation on match Pass tool through + onViolation

Install

pnpm add llm-stream-guard
# or npm install llm-stream-guard

Requirements: Node.js 18+ · Bun / Deno / Workers (Web Streams)

Maintainers: run pnpm release:prep before tagging and npm publish. GitHub Release notes from CHANGELOG.md.


First success in 30 seconds

git clone git@github.com:01laky/llm-stream-guard.git
cd llm-stream-guard
pnpm install
./scripts/setup-githooks.sh
pnpm verify

Then pipe bytes through the byte guard:

import { createByteGuard } from "llm-stream-guard";

const guarded = sourceStream.pipeThrough(createByteGuard({ redactSecrets: true, mode: "warn" }));

Quickstart

Proxy (byte mode)

import { createByteGuard } from "llm-stream-guard";

return new Response(
    upstream.body!.pipeThrough(
        createByteGuard({ redactSecrets: true, sanitizeErrors: true, mode: "warn" }),
    ),
    { headers: { "Content-Type": "text/event-stream" } },
);

redactSecrets and sanitizeErrors are active on createByteGuard() options.

Agent (event mode)

import {
    allowTools,
    blockToolArgs,
    guardEvents,
    redactSecrets,
    sanitizeErrors,
} from "llm-stream-guard";

for await (const event of guardEvents(
    parsedEvents,
    { mode: "block", onViolation: (v) => console.warn(v.rule, v.message) },
    redactSecrets(),
    allowTools(["search", "read_file"]),
    blockToolArgs(/rm\s+-rf/),
    sanitizeErrors(),
)) {
    if (event.type === "tool_call" && event.phase === "done") {
        await executeTool(event);
    }
}

Transform ordering

Recommended pipeline:

redactSecrets() → redactPII()? → allowTools/denyTools → blockToolArgs → maxToolArgsBytes → sanitizeErrors()

Reversing order is explicit — see docs/integration-cookbook.md.


Policy files & CLI

Policy compile pipeline

Declarative policies map to the same rule factories as manual stacks. Built-in profiles: proxy-strict, agent-gate, audit-only.

Policy file (policies/agent-gate.json)

{
    "version": "1",
    "policyVersion": "team-alpha-v3",
    "mode": "block",
    "rules": [
        { "allowTools": { "names": ["search", "read_file", "grep"] } },
        { "maxToolArgsBytes": { "max": 65536 } },
        { "sanitizeErrors": {} }
    ]
}

Programmatic (loadPolicy / createGuardFromPolicy)

import { createGuardFromPolicy, loadPolicy } from "llm-stream-guard";

const guard = createGuardFromPolicy(loadPolicy("./policies/agent-gate.json"));
for await (const event of guard.guard(parsedEvents)) {
    await handle(event);
}
const byteGuard = guard.createByteGuard();

CLI

npx llm-stream-guard validate policies/agent-gate.json
npx llm-stream-guard resolve policies/examples/extends-agent.json
npx llm-stream-guard scan --policy policies/agent-gate.json test/fixtures/events/
cat capture.log | npx llm-stream-guard scan --policy policies/proxy-strict.json -
npx llm-stream-guard diff policies/v1.json policies/v2.json --check
npx llm-stream-guard profiles list
Env variable Effect
GUARD_MODE Override policy mode (block / warn / audit)
GUARD_POLICY_PATH Default --policy path for CLI scan

Schema reference: schemas/policy-v1.json. Example policies: policies/.

Policy pitfalls: overlapping allow/deny lists (POLICY_E009); empty allowlist with mode: block (POLICY_E010 / POLICY_E008).


Mode decision guide

Pick byte vs event mode in ~30 seconds:

Use the modes diagram above, or:

  • Raw SSE to browser, no parsercreateByteGuard()
  • Tool gate before executeguardEvents() + rule factories
  • Parse with assemble / AI SDK first → map to GuardEvent, then guardEvents()

Documentation

CI & static audit (0.5.0)

Policy drift detection, static tool manifest scanning, and a composite GitHub Action for PR gates:

Integration cookbook (0.4.0)

End-to-end recipes for byte proxies (Hono, Express, Workers), agent tool gates, policy-driven setup, assemble/AI SDK mappers, dual-stream audit, MCP mapping, LiteLLM hooks, CI scans, and migration from regex middleware:

Reference

Related: llm-stream-assemble — stream parsing and assembly (separate package).


How this compares

llm-stream-guard Enterprise middleware llm-stream-assemble
Scope Stream security filter Broad platform Stream parsing
Byte + event Both first-class Often bytes-only Events (after parse)
Tool policy First-class Varies Assembly only
Dependencies Zero runtime Varies Zero runtime

Full matrix: docs/comparison.md.


Non-goals

  • No HTTP client, auth, or agent loop
  • No tool execution or UI components
  • No LLM-as-judge classifier
  • No hard dependency on assemble, AI SDK, or LangChain
  • No provider adapters (use assemble or your parser)

See docs/proposal.MD.


Development

pnpm install
./scripts/setup-githooks.sh
pnpm verify
Command Description
pnpm verify format + typecheck + build + test + fixtures + smoke
pnpm verify:deps fail if runtime dependencies are added
pnpm release:prep pre-tag checks (version, CHANGELOG, dist, npm pack)
pnpm diagrams:build regenerate README SVGs from Mermaid sources
pnpm fixtures:check-policies validate example + profile policies
pnpm fixtures:audit-policy-registry policy fixture REGISTRY parity
pnpm test Vitest (LSG-S/B/E/C/R/T/P/POL/CBK, LSG-REL)
pnpm examples:typecheck Typecheck cookbook examples against dist/
pnpm examples:smoke minimal-node install smoke after build
pnpm cookbook:check-examples examples README registry parity
pnpm bench:smoke local byte/event timing (informational)
pnpm build tsup → ESM + CJS + declarations

Author

Ladislav Kostolny01laky@gmail.com · GitHub @01laky

License

MIT — see LICENSE. Copyright (c) 2026 Ladislav Kostolny.