# Complete specification for egress JSON path filter
## When this applies
Use this when implementing or auditing a filter that screens outgoing structured payloads for identifying filesystem path strings before transmission. This skill provides a complete specification checklist addressing the architectural requirements and common gaps that enable bypass.
## The failure it prevents
Incomplete specifications create exploitable ambiguity. An adversarial review of a filter design that already included decoded-value validation, normalization, and resource limits still found seven critical undefined behaviors that enable bypass: budget exhaustion mid-validation, normalization fixpoint failure, operation ordering, relative path coverage, UNC path handling, resource limit enforcement timing, and per-string size bounds. Each gap allows either direct path leakage or creates a contradiction that breaks another guarantee.
A subsequent adversarial review of resource exhaustion defenses found four additional bypass vectors: undefined work budget operation costs enabling asymmetric exploitation, byte budget measuring serialized size while memory exhaustion depends on parsed representation, independent budgets creating multiplicative attack surface, and nested encoded payloads evading validation.
## Complete specification requirements
### 1. Parse and validate decoded values
**Requirement**: Strict parse incoming JSON into a dedicated tree structure. Validate decoded string values, not serialized bytes.
**Why**: Regex patterns written for readable text fail against escaped serialized forms. A backslash becomes a doubled pair in JSON strings, defeating separator-based patterns.
**Specification**: The validated value must be the exact decoded representation later emitted. Validation happens after decode, before serialization.
### 2. Resource limits enforced during parse with defined measurement
**Requirement**: Enforce byte limit, depth limit, and per-string length cap during streaming parse, before tree construction completes.
**Why**: Checking post-parse means parsing itself can exhaust memory or crash on pathological depth before limits apply. Measuring the wrong representation creates a gap between limit and actual resource consumption.
**Concrete values and measurement semantics**:
- **Byte limit**: 1MB maximum, measured as estimated in-memory size not serialized wire size. Account for object overhead, pointer storage, and string buffer allocation. Conservative estimation: multiply serialized size by 10 for initial check, track actual allocations during parse.
- **Depth limit**: 32 maximum nesting levels, counted during streaming parse with early abort.
- **String length cap**: 10KB maximum per individual string value after decoding.
**Specification**: Parser must abort immediately when any limit is exceeded during the streaming parse phase. Exceeding any limit triggers DENY verdict. Memory accounting must track parsed representation size, not wire format size, to prevent expansion attacks.
### 3. Normalization to fixpoint with defined failure behavior
**Requirement**: Apply normalization transformations in this exact order, iterating until output equals input or iteration limit is reached:
1. Decode unicode escape sequences to their character equivalents
2. Fold separator variations to canonical form
3. Strip invisible characters
**Iteration limit**: 10 rounds maximum.
**Critical specification**: If fixpoint is not reached within iteration limit, immediately trigger DENY verdict. Never proceed with non-canonical partially-normalized output.
**Why**: Cyclic encodings like nested unicode escapes encoding separators never stabilize. Proceeding with partial normalization enables bypass. Operation order matters because strip-then-decode versus decode-then-strip produce different intermediate states that affect structural detection.
### 4. Path detection on normalized values
**Requirement**: Apply all of these structural signals to the canonicalized value:
- **Absolute path indicators**: Leading separator, drive letter pattern
- **UNC path pattern**: Explicit check for double-backslash prefix
- **Relative path indicators**: Consecutive separator pairs, separator density threshold
- **Separator density**: Reject if separator count divided by string length exceeds 0.15
**Why**: Missing relative path or UNC detection enables direct bypass. Unquantified thresholds create implementation ambiguity.
**Specification**: A string matching any structural signal triggers path detection. No field-specific variance unless field classification rules are explicitly defined with their classification mechanism.
### 5. Shared work budget with defined operation costs
**Requirement**: Track cumulative operations across parse, traversal, normalization, and validation under a single shared budget with explicit per-operation costs.
**Budget value**: 1,000,000 operation units.
**Operation cost definitions**:
- Tree node allocation or traversal: 1 unit per node
- String examination for pattern matching: 10 units per string plus 1 unit per byte examined
- Normalization transformation: 5 units per string plus 1 unit per byte processed
- Regex pattern application: 10 units base plus 1 unit per character matched, enforced via linear-time automaton not backtracking engine
**Critical specification**: When budget is exhausted, immediately stop all processing and return DENY verdict. Never allow partial validation to succeed. The budget accounts for combined costs across all operations, preventing front-loading of expensive benign data to exhaust budget before later fields are validated.
**Why**: Undefined operation costs enable asymmetric attacks where many tiny strings versus one large string with identical total bytes have different operation counts. Attacker selects low-cost operations to bypass the limit. Budget must capture actual computational cost, not just operation count.
### 6. Nested and encoded payload handling
**Requirement**: Detect and recursively validate base64-encoded JSON, escaped JSON strings inside values, and other nested encoding layers.
**Specification**:
- Heuristically detect base64 blobs and encoded JSON patterns
- Decode one level and recursively validate
- Each recursive layer counts against depth budget and work budget
- Maximum recursion depth: 3 levels
- Exceeding recursion limit triggers DENY verdict
**Why**: Base64 wrapped JSON or escaped JSON strings inside values bypass validation unless recursively decoded. Without this requirement, attacker hides paths in encoded form.
### 7. Multiplicative budget interaction
**Requirement**: Budget limits must be multiplicatively conservative to prevent combined resource exhaustion.
**Specification**: When an implementation uses independent depth, byte, and work budgets, recognize that resource consumption multiplies across dimensions. A payload with maximum depth, maximum bytes, and maximum complexity strings may pass each individual limit while still exhausting combined resources. Either:
- Set limits multiplicatively conservative such that maximum depth times maximum bytes times maximum complexity operations stays within total resource bounds, OR
- Use unified work budget that accounts for combined costs including depth-dependent traversal overhead
**Why**: Independent budgets create multiplicative attack surface. Maximum nesting times maximum size times maximum string complexity exceeds what individual limits suggest.
### 8. Timeout with process isolation
**Requirement**: Execute validation in isolated worker process with wall-clock timeout enforced by supervisor.
**Timeout value**: 5 seconds maximum.
**Specification**:
- Supervisor sends payload to isolated worker
- Supervisor enforces timeout deadline
- On timeout or worker crash, supervisor immediately returns DENY verdict
- Worker returns only fixed-size framed verdict, never payload content
- Primary application task continues regardless of validation outcome
**Why**: Pathological regex backtracking can hang indefinitely even with work budget. Isolation ensures filter failure cannot crash primary application.
### 9. Fail-closed verdict framing
**Requirement**: Worker returns verdict as single-byte enum: 0 for ALLOW, 1 for DENY, optionally followed by single-byte category code.
**Category codes**:
- DEPTH_EXCEEDED
- SIZE_LIMIT
- BUDGET_EXHAUSTED
- TIMEOUT
- VALIDATION_FAILED
- NESTED_LIMIT
**Critical specification**: Supervisor defaults to DENY on any of: worker crash, timeout, malformed verdict, verdict parse error, or any unexpected worker output.
**Why**: If verdict channel is unbounded or unframed, corrupted worker can return arbitrary content. Truncation of complex verdict structure creates parse ambiguity.
### 10. Content-free rejection diagnostics
**Requirement**: Log only these elements on rejection, never the rejected value:
- Field path from schema
- Rule identifier that triggered rejection
- Coarse length bucket: 0-10, 10-50, 50-100, 100-500, 500+ characters
- Character class summary: alphanumeric, with-separators, with-special, mixed
- Keyed hash under rotating secret
**Why**: Logging rejected content is itself a leak channel. Dynamic length counts leak information. Plain hashes of short strings are brute-forceable. Reporting which budget type failed reveals structural characteristics amplified by timing side channels.
### 11. Primary task continuation guarantee
**Requirement**: Filter denial must never crash, block indefinitely, or propagate exceptions to primary application task.
**Specification**: On any validation error, timeout, or resource exhaustion, filter returns DENY verdict as a normal return value. Application sees sharing-unavailable status and continues its core logic.
**Why**: Validation failure should not disrupt primary application function.
## Testing without exposing values
Since tests must not print candidate path values:
1. Use property-based testing with generators that produce known-shape strings without logging them
2. Assert verdicts and category codes, not the input values
3. Test encodings through transformation verification: apply normalization, check fixpoint reached, verify structural signals detected, all without printing intermediate values
4. Record test results as verdict tuples: input-shape-description, expected-verdict, actual-verdict
## Evidence basis
This specification is derived from reasoned analysis through two rounds of adversarial review, not executed tests. The first review identified seven critical undefined behaviors in a design with decoded validation, normalization and resource limits. The second review of a three-budget resource defense found four additional bypass vectors: undefined operation costs, wrong size measurement, multiplicative budget interaction, and missing nested payload handling. Each undefined behavior demonstrates concrete bypass scenarios showing that specification gaps enable exploitation even when the core architecture is sound.