Guard Jsonpath

JSONPath content-safety guard — refuses user-supplied JSONPath query strings that exhibit dynamic-code-execution shapes BEFORE they reach a JSONPath evaluator. Many JSONPath implementations (the original Stefan Goessner reference and several JS forks) route filter / script expressions through eval-class dispatch, turning a query path into an RCE primitive; this primitive screens the path so a hostile query can't escape into code execution. KIND=identifier; the gate consumes ctx.identifier (or ctx.jsonpath) and refuses on hostile shapes. Targets the RFC 9535 compliant subset — filter / script expressions with code-execution semantics are rejected at every profile.

Threat catalog: filter expression ?(...) (dynamic-code- execution class in legacy implementations — refused universally); script expression shape (@.x) (RFC 9535 undefined but several implementations alias it to filter); JS-source hints (the path contains substrings that only appear in a code-injection attempt — dynamic-code-exec keyword, constructor invocation keyword, function-declaration keyword, arrow-function arrow, or statement-separator semicolon); recursive-descent depth bomb (..[*] repeated past maxRecursiveDescents); 3+ consecutive [ parser-DoS shape; per-pattern byte cap; BIDI override / zero-width / C0 control / null-byte universal refuse.

Profiles: strict / balanced / permissive. Compliance postures: hipaa / pci-dss / gdpr / soc2. Operators select via { profile: "strict" } or { compliancePosture: "hipaa" }; postures overlay on top of the profile baseline. Filter / script / dynamic-hint refusal holds at every profile — the RCE class is never an operator opt-in.

JSONPath strings can't be repaired safely — sanitize either passes through clean input or throws GuardJsonpathError; the gate returns serve / audit-only / refuse (no sanitize action). The source file's hint catalog is composed from substring fragments so the file itself stays free of the literal keywords (the codebase-patterns gate flags them otherwise).

b.guardJsonpath.validate(input, opts) #

stable0.7.13hipaapci-dssgdprsoc2
{
  profile:                "strict"|"balanced"|"permissive",
  compliancePosture: "hipaa"|"pci-dss"|"gdpr"|"soc2",
  bidiPolicy:             "reject"|"audit"|"allow",
  controlPolicy:          "reject"|"audit"|"allow",
  nullBytePolicy:         "reject"|"audit"|"allow",
  zeroWidthPolicy:        "reject"|"strip"|"audit"|"allow",
  filterExprPolicy:       "reject"|"audit"|"allow",
  scriptExprPolicy:       "reject"|"audit"|"allow",
  dynamicHintPolicy:      "reject"|"audit"|"allow",
  bracketNestingPolicy:   "reject"|"audit"|"allow",
  recursiveDescentPolicy: "reject"|"audit"|"allow",
  maxRecursiveDescents:   number,
  maxPatternBytes:        number,
  maxBytes:               number,
  maxRuntimeMs:           number,
}

Inspect a user-supplied JSONPath string and return an aggregated issue list. Pure inspection — never throws on hostile paths; caller decides what to do with the issues. The ok flag is true only when zero critical / high issues fire. Throws GuardJsonpathError("jsonpath.bad-opt") when a numeric opt is non-finite / negative (config-time mistake by the operator).

var clean = b.guardJsonpath.validate("$.users[*].name", { profile: "strict" });
clean.ok;                                          // → true

var hostile = b.guardJsonpath.validate("$..[?(@.x)]", { profile: "strict" });
hostile.ok;                                        // → false
hostile.issues.some(function (i) { return i.kind === "filter-expression"; });  // → true

b.guardJsonpath.sanitize(input, opts) #

stable0.7.13hipaapci-dssgdprsoc2
{
  profile:                "strict"|"balanced"|"permissive",
  compliancePosture: "hipaa"|"pci-dss"|"gdpr"|"soc2",
  filterExprPolicy:       "reject"|"audit"|"allow",
  scriptExprPolicy:       "reject"|"audit"|"allow",
  dynamicHintPolicy:      "reject"|"audit"|"allow",
  bracketNestingPolicy:   "reject"|"audit"|"allow",
  recursiveDescentPolicy: "reject"|"audit"|"allow",
  maxRecursiveDescents:   number,
  maxPatternBytes:        number,
}

Pass-through-or-throw. JSONPath expressions cannot be safely repaired (stripping a ?( from a filter silently changes query semantics); this primitive returns the input unchanged when no critical or high issue fires, otherwise throws GuardJsonpathError with the offending rule id (e.g. jsonpath.filter-expression, jsonpath.dynamic-hint, jsonpath.script-expression). Operators that need a "best- effort cleanup" semantic should reject the path at the boundary instead.

var safe = b.guardJsonpath.sanitize("$.users[*].name", { profile: "strict" });
safe;                                              // → "$.users[*].name"

try {
  b.guardJsonpath.sanitize("$..[?(@.x)]", { profile: "strict" });
} catch (e) {
  e.code;                                          // → "jsonpath.filter-expression"
}

b.guardJsonpath.compliancePosture(name) #

stable0.7.13hipaapci-dssgdprsoc2

Look up a compliance-posture overlay by name (one of "hipaa" / "pci-dss" / "gdpr" / "soc2"). Returns a fresh clone of the posture overlay so the caller may mutate it freely without disturbing the shared table. Throws GuardJsonpathError with code "jsonpath.bad-posture" when the name is not one this guard maps. Wired by gateContract.defineGuard through gateContract.lookupCompliancePosture, so the clone semantics and error code are identical across every guard in the family.

var posture = b.guardJsonpath.compliancePosture("hipaa");
posture;                                             // → overlay clone (mutable)

try {
  b.guardJsonpath.compliancePosture("not-a-regime");
} catch (e) {
  e.code;                                            // → "jsonpath.bad-posture"
}

b.guardJsonpath.buildProfile(opts) #

stable0.7.13
{
  extends:   string|string[],   // base profile name(s) to compose
  ...:       any guard key,      // inline override of resolved keys
}

Compose a derived profile from one or more named bases plus inline overrides, resolving names through this guard's own PROFILES table. opts.extends is a base profile name ("strict" / "balanced" / "permissive") or an array of names — later entries shadow earlier ones, and inline opts keys win last. Wired by gateContract.defineGuard through gateContract.makeProfileBuilder, so operator-defined profiles stay traceable to a baseline instead of a hand-typed dictionary.

var custom = b.guardJsonpath.buildProfile({ extends: "strict" });
custom;                                              // → composed profile object

b.guardJsonpath.loadRulePack(pack) #

stable0.7.13

Register an operator-supplied rule pack with this guard's rule-pack registry. The pack is identified by pack.id (a non-empty string) and stored for later dispatch by gates that opt in via opts.rulePackId. Returns the pack unchanged on success; throws GuardJsonpathError with code "jsonpath.bad-opt" when pack is missing or pack.id is not a non-empty string. Wired by gateContract.defineGuard through gateContract.makeRulePackLoader, so storage shape and validation are identical across the family.

var pack = b.guardJsonpath.loadRulePack({ id: "tenant-policy", rules: [] });
pack.id;                                             // → "tenant-policy"

b.guardJsonpath.gate(opts?) #

stable0.7.13
{
  profile:           string,    // one of PROFILES; default this guard's default
  compliancePosture: string,    // overlay one of hipaa/pci-dss/gdpr/soc2
  mode:              string,    // one of gateContract MODES; default "enforce"
}

Build the guard's request-boundary gate — a contract-shaped object exposing check(ctx) that host primitives call at their byte moment. This is the factory default chain: serve when no issue, audit-only for info / warn issues, and refuse for any high / critical issue, dispatched to the right ctx field by the guard's KIND. Wired by gateContract.defineGuard through gateContract.buildGuardGate; a guard whose gate diverges (a bespoke sanitize-and-reserialize chain, for example) ships its own gate block instead of this template.

var gate = b.guardJsonpath.gate({ profile: "strict" });
var decision = await gate.check({ bytes: Buffer.from("...") });
decision.action;                                     // → "serve" | "refuse" | …

b.guardJsonpath.resolveOpts(opts?) #

stable0.7.13
{
  profile:           string,    // one of PROFILES; default this guard's default
  compliancePosture: string,    // overlay one of hipaa/pci-dss/gdpr/soc2
}

Resolve caller opts against this guard's PROFILES + compliance-posture overlays into the fully-defaulted option set the guard runs on — the same resolution validate / sanitize / gate apply internally. Wired by gateContract.defineGuard from the guard's binding config (profiles / postures / defaults / error class), so a guard's bespoke gate calls resolveOpts instead of re-declaring the per-guard resolver wrapper. Throws GuardJsonpathError with code "jsonpath.bad-opt" / "jsonpath.bad-posture" on an unknown profile or posture name.

var resolved = b.guardJsonpath.resolveOpts({ profile: "strict" });
resolved.profile;                                    // → "strict"

Last updated 2026-08-08T16:39:49.652Z by seeder.