NL Protocol Specification v1.0 -- Chapter 04: Pre-Execution Defense

Status: Draft Version: 1.0.0 Date: 2026-02-08

Note: This document is a SPECIFICATION. It defines required behaviors, data formats, and protocols — not specific products or CLI commands. For implementations of this specification, see IMPLEMENTATIONS.md.

1. Introduction

This chapter defines the Pre-Execution Defense layer of the NL Protocol. Every command, tool invocation, or action initiated by an agent MUST pass through a pre-execution interceptor before it reaches any execution environment. The purpose of this layer is to intercept and block actions that would expose, exfiltrate, or compromise secrets -- before they execute.

Pre-Execution Defense is the fourth layer of the NL Protocol's defense-in-depth architecture. While Levels 1 through 3 ensure that agents have verifiable identity, request actions rather than secrets, and execute within isolated environments, Level 4 adds a proactive interception mechanism that prevents dangerous actions from reaching the execution boundary in the first place.

1.1 Scope

This chapter applies to any system that mediates agent actions, regardless of the underlying platform. The interception mechanisms defined here are designed to be implementable across:

  • AI coding assistants (Claude Code, Cursor, Copilot, Windsurf, Aider, Codex)
  • MCP (Model Context Protocol) servers
  • CI/CD pipelines (GitHub Actions, GitLab CI, Jenkins, CircleCI)
  • Cloud platforms (AWS, GCP, Azure)
  • SaaS and payment platforms (Stripe, Twilio, GitHub)
  • Custom agent orchestration frameworks

1.2 Design Philosophy

The Pre-Execution Defense layer operates on two fundamental principles:

  1. Fail closed. If the interceptor is unavailable, experiences an error, or cannot determine whether an action is safe, the action MUST be blocked. An unknown action is a dangerous action.

  2. Educate, do not merely block. When an action is blocked, the system MUST provide the agent with a structured response that explains what was blocked, why it was blocked, and what the safe alternative is. Opaque errors teach nothing; educational responses guide the agent toward NL Protocol-compliant behavior.

2. Command Interception

2.1 Interception Requirement

All agent-initiated actions MUST pass through a Pre-Execution Interceptor before reaching the execution environment. The interceptor MUST be invoked for every action, without exception. There MUST NOT exist any code path that allows an agent action to reach execution without passing through the interceptor.

2.2 Interceptor Position

The interceptor MUST be positioned between the agent's action request and the execution environment:

+-------+      +--------------+      +-------------+      +-----------+
| Agent | ---> | Interceptor  | ---> | Authorized  | ---> | Executor  |
|       |      | (Level 4)    |      | Action      |      | (Level 3) |
+-------+      +--------------+      +-------------+      +-----------+
                     |
                     | (blocked)
                     v
              +------------------+
              | Educational      |
              | Response         |
              +------------------+

The interceptor MUST evaluate the action before any secret resolution occurs. If the action references secrets via placeholders (Chapter 02), the interceptor evaluates the action template containing the placeholder references -- not the resolved secret values.

2.3 Interceptor Evaluation Order

The interceptor MUST evaluate each action against the following checks, in the order specified:

  1. Standard deny rules (Section 3): If the action matches any standard deny rule, it MUST be blocked.
  2. Custom deny rules (Section 4): If the action matches any organization-defined deny rule, it MUST be blocked.
  3. Evasion detection (Section 6): If the action contains patterns that indicate an attempt to evade deny rules, it MUST be blocked.
  4. Allowlist rules (Section 5): If an allowlist is configured and the action does not match any allowlist entry, the action SHOULD be blocked.

If the action passes all checks, it is forwarded to the execution environment.

If any check results in a block, the interceptor MUST stop evaluation immediately, record the block in the audit log (Chapter 05), and return an educational response (Section 8).

2.4 Interceptor Interface

Implementations MUST expose an interceptor that conforms to the following interface:

InterceptorResult intercept(action: AgentAction): InterceptorResult

AgentAction {
  agent:       AgentIdentity       // The agent requesting the action (Chapter 01)
  action_type: string              // "exec" | "template" | "inject_stdin" |
                                   // "inject_tempfile" | "tool_call" | "api_call"
  command:     string              // The raw command or tool invocation string
  arguments:   map<string, any>    // Structured arguments (for tool calls and APIs)
  target:      string              // Target resource or endpoint
  metadata:    map<string, string> // Additional context (platform, session, correlation_id)
}

InterceptorResult {
  decision:    "allow" | "block"
  rule_id:     string?             // ID of the deny rule that triggered the block
  category:    string?             // Deny rule category
  severity:    string?             // "critical" | "high" | "medium" | "low"
  reason:      string?             // Human-readable explanation
  alternative: SafeAlternative?    // The safe way to accomplish the goal
  reference:   string?             // URL to protocol documentation
}

3. Standard Deny Rules

3.1 Deny Rule Format

Each deny rule MUST have the following structure:

{
  "rule_id": "NL-4-DENY-001",
  "category": "direct_secret_access",
  "severity": "critical",
  "patterns": [
    "vault\\s+(get|read|show|reveal|decrypt|fetch)\\s+",
    "braincol-vault\\s+get\\s+"
  ],
  "description": "Direct retrieval of secret values via vault CLI",
  "safe_alternative": "Use action-based access with {{nl:<reference>}} placeholder syntax (NL Protocol Level 2).",
  "applies_to": ["exec", "tool_call"]
}

Fields:

Field Type Required Description
rule_id string MUST Unique identifier, prefixed with NL-4-DENY- for standard rules.
category string MUST One of the categories defined in Section 3.2.
severity string MUST One of critical, high, medium, or low.
patterns string[] MUST Regular expression patterns to match against the action. Patterns MUST be applied case-insensitively by default.
description string MUST Human-readable description of what the rule blocks.
safe_alternative string MUST Description of the correct, safe way to accomplish the same goal.
applies_to string[] SHOULD Action types this rule applies to. If omitted, the rule applies to all action types.

3.2 Deny Rule Categories

Every NL Protocol-conformant implementation MUST enforce deny rules in the following seven categories. The specific regular expression patterns within each category MAY vary by platform to accommodate platform-specific CLI tools and APIs, but every category MUST be represented with at least one active rule.

3.2.1 Category 1: Direct Secret Access (NL-4-DENY-001 through NL-4-DENY-009)

Actions that directly retrieve, display, or return the plaintext value of a secret MUST be blocked.

Rule ID Pattern Description
NL-4-DENY-001 vault\s+(get|read|show|reveal|decrypt|fetch)\s+ Generic vault CLI retrieval commands
NL-4-DENY-002 cat\s+\.env Reading .env files containing secrets
NL-4-DENY-003 cat\s+.*\.(key|pem|p12|pfx|jks|keystore|crt) Reading key and certificate files directly
NL-4-DENY-004 op\s+(read|get|item\s+get)\s+ 1Password CLI retrieval
NL-4-DENY-005 aws\s+secretsmanager\s+get-secret-value AWS Secrets Manager retrieval
NL-4-DENY-006 gcloud\s+secrets\s+versions\s+access GCP Secret Manager retrieval
NL-4-DENY-007 az\s+keyvault\s+secret\s+show Azure Key Vault retrieval
NL-4-DENY-008 doppler\s+secrets\s+(get|download) Doppler CLI retrieval
NL-4-DENY-009 stripe\s+(config|listen)\s+--api-key Stripe CLI with inline API key exposure

Safe alternative: Use action-based access (Chapter 02) with {{nl:<reference>}} placeholder syntax. The secret is resolved inside the isolated execution environment (Chapter 03) and never enters the agent's context.

Example -- blocked vs. safe:

BLOCKED:  vault get API_KEY
          -> The secret value "sk-live-abc123..." enters the agent context

SAFE:     An NL-compliant implementation executes:
          curl -H "Authorization: Bearer {{nl:API_KEY}}" https://api.stripe.com/v1/charges
          -> The agent never sees the secret; it is injected at execution time

3.2.2 Category 2: Bulk Export (NL-4-DENY-010 through NL-4-DENY-019)

Actions that export, dump, or enumerate multiple secret values at once MUST be blocked.

Rule ID Pattern Description
NL-4-DENY-010 vault\s+export Vault bulk export
NL-4-DENY-011 ^env$|^env\s Shell environment variable dump
NL-4-DENY-012 ^printenv$|^printenv\s Print all environment variables
NL-4-DENY-013 ^set$|^set\s Shell variable dump (includes env vars)
NL-4-DENY-014 doppler\s+secrets(\s+|$) Doppler full secrets listing
NL-4-DENY-015 aws\s+secretsmanager\s+batch-get-secret-value AWS batch secret retrieval
NL-4-DENY-016 terraform\s+output\s+-json Terraform output dump (may contain secrets)
NL-4-DENY-017 kubectl\s+get\s+secret.*-o\s+(json|yaml|jsonpath) Kubernetes secret value extraction
NL-4-DENY-018 docker\s+inspect.*--format.*\.Env Docker container environment extraction
NL-4-DENY-019 heroku\s+config(\s+|$) Heroku config vars dump

Safe alternative: Use the implementation's secret listing capability to enumerate secret names without their values. Then reference specific secrets via the {{nl:<reference>}} placeholder syntax.

Example -- blocked vs. safe:

BLOCKED:  env
          -> Dumps ALL environment variables, including any injected secrets

SAFE:     An NL-compliant implementation lists secrets by name:
          API_KEY, DB_PASSWORD, STRIPE_KEY (values never shown)

3.2.3 Category 3: Internal File Access (NL-4-DENY-020 through NL-4-DENY-029)

Actions that read the internal storage files of a vault, encrypted key stores, or secret manager data directories MUST be blocked.

Rule ID Pattern Description
NL-4-DENY-020 cat\s+.*vault\.(age|enc|gpg|sealed|db) Reading encrypted vault files
NL-4-DENY-021 strings\s+.*\.(key|age|enc|pem|db) Extracting strings from encrypted files
NL-4-DENY-022 xxd\s+.*\.(key|age|enc|pem) Hex dump of key material
NL-4-DENY-023 sqlite3\s+.*vault Direct SQLite access to vault databases
NL-4-DENY-024 cat\s+.*\.vault/ Reading vault internal directory structure
NL-4-DENY-025 find\s+.*-name\s+["']?\*?\.(key|pem|p12|age) Searching for key files on disk
NL-4-DENY-026 ls\s+(-la?\s+)?.*\.vault/ Listing vault internal directory contents
NL-4-DENY-027 cp\s+.*\.(key|pem|age|enc) Copying key or encrypted files
NL-4-DENY-028 tar\s+.*\.(key|pem|age|enc|vault) Archiving key material or vault files
NL-4-DENY-029 scp\s+.*\.(key|pem|age|enc)\s+ Remote copying of key material

Safe alternative: Interact with the vault exclusively through its CLI, API, or MCP tools. Never access vault storage files directly.

3.2.4 Category 4: Encoding Evasion (NL-4-DENY-030 through NL-4-DENY-039)

Actions that encode, decode, or transform blocked commands to evade pattern matching MUST be blocked.

Rule ID Pattern Description
NL-4-DENY-030 base64\s+(-d|--decode).*|\s*(sh|bash|zsh|dash) Base64 decode piped to shell
NL-4-DENY-031 echo\s+.*|\s*base64\s+(-d|--decode)\s*|\s*(sh|bash) Echo encoded payload to decode to shell
NL-4-DENY-032 python[23]?\s+-c\s+.*exec\(.*decode Python exec with base64/hex decode
NL-4-DENY-033 node\s+-e\s+.*Buffer\.from\(.*base64 Node.js base64 decode and execute
NL-4-DENY-034 printf\s+.*\\\\x[0-9a-fA-F].*|\s*(sh|bash) Hex-encoded command piped to shell
NL-4-DENY-035 xxd\s+-r.*|\s*(sh|bash) Hex reversal piped to shell
NL-4-DENY-036 perl\s+-e\s+.*pack\s*\( Perl pack/unpack evasion
NL-4-DENY-037 ruby\s+-e\s+.*\.unpack Ruby unpack evasion
NL-4-DENY-038 openssl\s+(enc|base64)\s+-d.*|\s*(sh|bash) OpenSSL decode piped to shell
NL-4-DENY-039 gzip\s+-d.*|\s*(sh|bash) Compressed payload decompressed to shell

Safe alternative: All commands MUST be submitted in plaintext. The interceptor requires commands to be human-readable and inspectable. Encoded or obfuscated commands will always be blocked.

Example -- blocked vs. safe:

BLOCKED:  echo 'dmF1bHQgZ2V0IEFQSV9LRVk=' | base64 -d | sh
          -> Decodes to "vault get API_KEY" and executes it, bypassing deny rules

SAFE:     An NL-compliant implementation executes:
          curl -H "Authorization: Bearer {{nl:API_KEY}}" https://api.example.com
          -> Command is plaintext, inspectable, and uses placeholder syntax

3.2.5 Category 5: Shell Expansion (NL-4-DENY-040 through NL-4-DENY-049)

Actions that use shell expansion mechanisms to capture or interpolate secret values into the agent's context MUST be blocked.

Rule ID Pattern Description
NL-4-DENY-040 \$\(\s*vault\s+(get|read|show|reveal)\s+ Command substitution with vault get
NL-4-DENY-041 `\s*vault\s+(get|read|show|reveal)\s+ Backtick substitution with vault get
NL-4-DENY-042 \$\(\s*op\s+(read|get)\s+ Command substitution with 1Password CLI
NL-4-DENY-043 \$\(\s*aws\s+secretsmanager\s+get-secret-value Command substitution with AWS Secrets Manager
NL-4-DENY-044 \$\(\s*gcloud\s+secrets\s+versions\s+access Command substitution with GCP Secret Manager
NL-4-DENY-045 eval\s+.*vault Eval wrapping vault commands
NL-4-DENY-046 source\s+<\(.*vault Process substitution with vault commands
NL-4-DENY-047 xargs.*vault\s+(get|read) xargs piping to vault retrieval
NL-4-DENY-048 \$\(\s*kubectl\s+get\s+secret Command substitution with kubectl secrets
NL-4-DENY-049 \$\(\s*az\s+keyvault\s+secret\s+show Command substitution with Azure Key Vault

Safe alternative: Use the {{nl:<reference>}} placeholder syntax. The NL Protocol runtime resolves placeholders inside an isolated execution environment (Chapter 03) without any shell expansion in the agent's context.

Example -- blocked vs. safe:

BLOCKED:  curl -H "Authorization: Bearer $(vault get API_KEY)" https://api.example.com
          -> Shell substitution causes the secret value to enter the agent's shell context

SAFE:     An NL-compliant implementation executes:
          curl -H "Authorization: Bearer {{nl:API_KEY}}" https://api.example.com
          -> Placeholder is resolved inside the isolated subprocess; value never enters agent context

3.2.6 Category 6: Environment Dumps (NL-4-DENY-050 through NL-4-DENY-059)

Actions that read process environments -- which may contain secrets injected into execution subprocesses -- MUST be blocked.

Rule ID Pattern Description
NL-4-DENY-050 cat\s+/proc/.*/environ Linux process environment file
NL-4-DENY-051 ps\s+.*eww Process listing with full environment
NL-4-DENY-052 tr\s+.*\\\\0.*</proc/.*/environ Null-byte-delimited environ parsing
NL-4-DENY-053 cat\s+/proc/self/environ Self process environment
NL-4-DENY-054 xargs\s+.*-0.*</proc/.*/environ Environ parsing via xargs null delimiter
NL-4-DENY-055 strings\s+/proc/.*/environ Extracting strings from process environment
NL-4-DENY-056 python[23]?\s+-c\s+.*os\.environ Python os.environ access
NL-4-DENY-057 node\s+-e\s+.*process\.env Node.js process.env access
NL-4-DENY-058 ruby\s+-e\s+.*ENV Ruby ENV hash access
NL-4-DENY-059 php\s+-r\s+.*getenv\(\) PHP environment access

Safe alternative: Secrets are available only within the isolated execution environment (Chapter 03). The agent's own process environment MUST NOT contain secret values. To use secrets, reference them with {{nl:<reference>}} placeholder syntax.

3.2.7 Category 7: Indirect Execution (NL-4-DENY-060 through NL-4-DENY-069)

Actions that use indirection mechanisms to circumvent the interceptor or construct blocked commands dynamically MUST be blocked.

Rule ID Pattern Description
NL-4-DENY-060 eval\s+.*\$ Eval with variable expansion
NL-4-DENY-061 bash\s+-c\s+.*vault\s+(get|read|export) Subshell wrapping vault retrieval
NL-4-DENY-062 sh\s+-c\s+.*vault\s+(get|read|export) Subshell wrapping vault retrieval
NL-4-DENY-063 source\s+.*\.env Sourcing .env files into shell context
NL-4-DENY-064 \.\s+.*\.env Dot-sourcing .env files
NL-4-DENY-065 crontab\s+ Scheduling commands (may persist secret access)
NL-4-DENY-066 at\s+ Scheduling one-time commands
NL-4-DENY-067 nohup\s+.*vault Background execution of vault commands
NL-4-DENY-068 screen\s+-dmS\s+.*vault Detached screen with vault commands
NL-4-DENY-069 tmux\s+.*send-keys.*vault tmux send-keys with vault commands

Note on false positives: Rules NL-4-DENY-060, NL-4-DENY-065, and NL-4-DENY-066 have elevated false positive rates in development contexts. Implementations SHOULD apply these rules contextually: block when the indirect execution wraps a command that would itself be blocked, but allow when the indirect execution is unrelated to secret access. Implementations MAY require these specific rules to be explicitly enabled via configuration.

Safe alternative: Submit all commands directly. Wrapping commands in eval, bash -c, or other indirection layers to avoid the interceptor is a violation of NL Protocol Level 4.

4. Custom Deny Rules

4.1 Requirement

Organizations MUST be able to define additional deny rules beyond the standard set defined in Section 3. Custom rules allow organizations to protect platform-specific secrets, internal tools, proprietary systems, and organization-specific workflows.

4.2 Custom Rule Format

Custom deny rules MUST follow the same format as standard deny rules (Section 3.1) with the following additional fields:

{
  "rule_id": "CUSTOM-ORG-001",
  "category": "custom",
  "severity": "high",
  "patterns": ["internal-tool\\s+export-credentials"],
  "description": "Blocks credential export from organization-specific internal tool",
  "safe_alternative": "Use internal-tool inject-credentials with placeholder syntax.",
  "applies_to": ["exec"],
  "organization_id": "org_example",
  "created_by": "human:admin@example.com",
  "created_at": "2026-02-08T10:00:00Z",
  "expires_at": "2027-02-08T10:00:00Z"
}
Field Type Required Description
organization_id string MUST Identifier of the organization that created the rule.
created_by string MUST Identity of the administrator who created the rule. MUST be a human identity, not an agent.
created_at string MUST ISO 8601 timestamp of rule creation.
expires_at string MAY ISO 8601 timestamp after which the rule is no longer enforced.

4.3 Custom Rule Precedence

Standard deny rules MUST be evaluated before custom deny rules. If both a standard rule and a custom rule match the same action, the standard rule takes precedence for reporting purposes. The action is blocked regardless of which rule matched first.

4.4 Custom Rule Management

Implementations MUST provide mechanisms for authorized administrators to:

  1. Create custom deny rules.
  2. List all active deny rules (standard and custom).
  3. Update custom deny rules. Standard rules MUST NOT be modifiable.
  4. Delete custom deny rules. Standard rules MUST NOT be deletable.
  5. Test a custom rule against sample commands without enforcing it (dry-run mode).

Agents MUST NOT be able to create, update, or delete deny rules. Rule management MUST require human administrator privileges.

All custom rule changes (creation, update, deletion) MUST be recorded in the audit log (Chapter 05).

5. Allowlist Mode

5.1 Allowlist as Complementary Control

In addition to deny rules, implementations SHOULD support an allowlist mode. When allowlist mode is enabled, only actions that match an allowlist entry are permitted. All other actions are blocked by default. Allowlist mode provides the strongest security posture because it follows a default-deny approach.

5.2 Allowlist Entry Format

{
  "entry_id": "ALLOW-001",
  "patterns": ["curl\\s+-H.*\\{\\{nl:.*\\}\\}\\s+https://"],
  "description": "Allow curl commands with NL Protocol placeholders targeting HTTPS endpoints",
  "applies_to": ["exec"],
  "max_secrets": 3,
  "allowed_secret_refs": ["api/*", "tokens/*"]
}
Field Type Required Description
entry_id string MUST Unique identifier for the allowlist entry.
patterns string[] MUST Regex patterns that the action must match.
description string MUST Human-readable description.
applies_to string[] SHOULD Action types this entry applies to.
max_secrets integer MAY Maximum number of secret placeholders allowed in a single action.
allowed_secret_refs string[] MAY Glob patterns for which secret references are permitted.

5.3 Interaction with Deny Rules

Deny rules MUST always take precedence over allowlist entries. An action that matches both a deny rule and an allowlist entry MUST be blocked. The evaluation order is:

  1. Standard deny rules.
  2. Custom deny rules.
  3. Evasion detection.
  4. Allowlist check (if allowlist mode is enabled).

An action MUST pass all four checks to be allowed.

6. Evasion Detection

6.1 Requirement

The interceptor MUST detect and block attempts to evade deny rules through obfuscation, encoding, or indirection. Evasion detection goes beyond static pattern matching by analyzing the structure and intent of commands.

6.2 Evasion Techniques and Countermeasures

6.2.1 Unicode Normalization

Agents MAY attempt to substitute visually similar Unicode characters for ASCII characters to bypass pattern matching (e.g., fullwidth characters vault instead of vault, or Cyrillic characters that resemble Latin letters).

Countermeasure: The interceptor MUST normalize all input to NFC (Unicode Normalization Form C) and strip or replace non-ASCII characters that are visually confusable with ASCII equivalents before applying deny rules. Implementations SHOULD use a confusable character mapping table (such as Unicode Confusables from UTS #39) for this purpose.

6.2.2 Whitespace Manipulation

Agents MAY insert extra whitespace, tabs, newlines, or zero-width characters to break pattern matches (e.g., vault get SECRET).

Countermeasure: The interceptor MUST collapse consecutive whitespace characters into a single space and remove zero-width characters before applying deny rules. Leading and trailing whitespace MUST be trimmed.

6.2.3 Case Variation

Agents MAY use mixed case to bypass case-sensitive patterns (e.g., VaUlT GeT SECRET).

Countermeasure: Deny rule patterns MUST be applied case-insensitively unless the rule explicitly specifies case-sensitive matching.

6.2.4 String Concatenation and Variable Construction

Agents MAY construct blocked commands by concatenating shell variables, using string slicing, or building command names character by character (e.g., cmd="vault"; $cmd get SECRET).

Countermeasure: The interceptor SHOULD perform static analysis of variable assignments and substitutions within the same command context. When variable expansion is detected that could construct a blocked command, the interceptor SHOULD block the action. When variable expansion analysis is not feasible, the interceptor SHOULD block commands that assign variables and immediately use them in command position.

6.2.5 Multi-Stage Payloads (Write-Then-Execute)

Agents MAY write a script containing blocked commands to a file and then execute that file in a separate action (e.g., action 1: echo "vault get SECRET" > /tmp/x.sh; action 2: bash /tmp/x.sh).

Countermeasure: The interceptor MUST track file write operations and correlate them with subsequent execution requests within the same agent session. When a write-then-execute pattern is detected, the content of the written file SHOULD be subject to the same deny rules as direct commands. Implementations SHOULD maintain a session-scoped watchlist of files written by the agent and intercept execution of those files.

6.2.6 Alias and Function Definition

Agents MAY define shell aliases or functions that wrap blocked commands (e.g., alias v=vault; v get SECRET or function g() { vault get "$1"; }; g SECRET).

Countermeasure: The interceptor SHOULD detect alias and function definitions that reference blocked command patterns. When detected, both the definition and any subsequent invocations of the alias or function MUST be blocked.

6.3 Evasion Scoring

Each detected evasion attempt MUST be recorded in the audit log (Chapter 05) with category evasion_attempt. Evasion attempts SHOULD increment the agent's threat score (Chapter 06) by at least +10. Repeated evasion attempts from the same agent SHOULD trigger enhanced monitoring or automatic suspension depending on the implementation's threat response policy.

7. Fail-Closed Design

7.1 Requirement

If the interceptor fails, becomes unavailable, or encounters any error during evaluation, the action MUST be blocked. The system MUST NOT fall back to allowing unfiltered actions under any failure condition.

7.2 Failure Modes

The following failure modes MUST result in the action being blocked:

Failure Mode Required Behavior
Interceptor process crash Block all pending and new actions; restart interceptor before resuming.
Deny rule file parsing error Block all actions; alert administrator. Use last-known-good rules if available.
Pattern matching timeout Block the action that caused the timeout; log the event.
Network error (if rules are loaded remotely) Block all actions; use last-known-good cached rules if available and cache has not expired.
Resource exhaustion (memory, CPU) Block all actions; alert administrator; shed load.
Unknown or unrecognized action type Block the action; log the unknown type for investigation.
Configuration corruption Block all actions; alert administrator.

7.3 Health Monitoring

Implementations SHOULD expose a health check endpoint or signal for the interceptor. Monitoring systems SHOULD query this health check at a regular interval (RECOMMENDED: every 10 seconds). If the interceptor becomes unhealthy, all agent actions MUST be queued or rejected until the interceptor recovers.

The health check MUST verify:

  1. The interceptor process is running.
  2. Deny rules are loaded and parseable.
  3. The last successful interception occurred within a configurable recency window (RECOMMENDED: 60 seconds).

7.4 Graceful Degradation with Cached Rules

When the interceptor uses cached deny rules during a network failure:

  1. The implementation MUST log that cached rules are in use with a warning severity.
  2. A maximum cache duration MUST be enforced (RECOMMENDED: 1 hour).
  3. If the cache expires without successful reconnection to the rule source, ALL actions MUST be blocked until connectivity is restored.

8. Educational Response

8.1 Response Requirement

When an action is blocked, the interceptor MUST return an Educational Response. The response MUST provide the agent with sufficient information to understand the block and correct its behavior. Responses MUST NOT be opaque error codes, generic failure messages, or empty rejections.

The educational response serves a dual purpose: it trains the AI agent to use safe patterns, and it provides a human-readable audit trail of why an action was blocked.

8.2 Educational Response Schema

{
  "status": "BLOCKED",
  "rule_id": "NL-4-DENY-001",
  "category": "direct_secret_access",
  "severity": "critical",
  "blocked_action": "vault get API_KEY",
  "reason": "Direct secret retrieval would expose the secret value in the agent's LLM context window. Once in context, the secret can be memorized, replicated, or exfiltrated through the model.",
  "risk": "The secret value would become part of the agent's conversation history and could appear in logs, model outputs, or be sent to unintended recipients.",
  "safe_alternative": {
    "description": "Use action-based access (NL Protocol Level 2) with placeholder syntax to reference the secret without retrieving its value.",
    "example": "Submit an Action Request with command: curl -H \"Authorization: Bearer {{nl:API_KEY}}\" https://api.example.com",
    "documentation": "https://nlprotocol.org/spec/v1.0/02-action-based-access"
  },
  "protocol_reference": "https://nlprotocol.org/spec/v1.0/04-pre-execution-defense#direct-secret-access",
  "agent_guidance": "You do not need the secret's value to use it. Reference it with {{nl:API_KEY}} and the NL Protocol runtime will inject it into your command at execution time."
}

8.3 Required Fields

Field Type Required Description
status string MUST Always "BLOCKED".
rule_id string MUST The ID of the deny rule that triggered the block.
category string MUST The deny rule category.
severity string MUST The severity level: critical, high, medium, or low.
blocked_action string MUST The action that was blocked. Secret values MUST NOT appear here; only references or command templates.
reason string MUST A clear, specific explanation of why the action is dangerous in the context of AI agent security.
risk string SHOULD A description of the concrete risk if the action were allowed to execute.
safe_alternative object MUST An object containing description (string, MUST), example (string, MUST), and documentation (string, SHOULD).
protocol_reference string SHOULD URL to the relevant section of the NL Protocol specification.
agent_guidance string SHOULD A concise, agent-friendly instruction on how to proceed correctly.

8.4 Additional Examples

8.4.1 Blocked Bulk Export

{
  "status": "BLOCKED",
  "rule_id": "NL-4-DENY-011",
  "category": "bulk_export",
  "severity": "critical",
  "blocked_action": "env",
  "reason": "The 'env' command dumps all environment variables to stdout. In execution environments where secrets are injected as environment variables, this would expose all secret values simultaneously.",
  "risk": "Every secret currently in the environment would enter the agent's context at once, maximizing the blast radius of any subsequent exfiltration.",
  "safe_alternative": {
    "description": "Use the implementation's secret listing capability to enumerate secret names without values, or reference specific secrets via placeholder syntax.",
    "example": "Use the list_secrets tool or equivalent to enumerate available secret names without values.",
    "documentation": "https://nlprotocol.org/spec/v1.0/02-action-based-access#placeholder-syntax"
  },
  "agent_guidance": "To see which secrets are available, use the secret listing capability. To use a specific secret, reference it with {{nl:SECRET_NAME}} in your command."
}

8.4.2 Blocked Encoding Evasion

{
  "status": "BLOCKED",
  "rule_id": "NL-4-DENY-030",
  "category": "encoding_evasion",
  "severity": "critical",
  "blocked_action": "echo 'dmF1bHQgZ2V0IEFQSV9LRVk=' | base64 -d | sh",
  "reason": "Base64-encoded commands piped to a shell are a known evasion technique. The decoded content matches a blocked pattern. Encoded commands bypass pattern matching and cannot be inspected by the interceptor.",
  "risk": "The decoded command would execute without interception, potentially exposing secret values to the agent's context.",
  "safe_alternative": {
    "description": "Submit all commands in plaintext. The interceptor requires commands to be human-readable.",
    "example": "Submit an Action Request with command: curl -H \"Authorization: Bearer {{nl:API_KEY}}\" https://api.example.com",
    "documentation": "https://nlprotocol.org/spec/v1.0/04-pre-execution-defense#encoding-evasion"
  },
  "agent_guidance": "Do not encode commands. Use {{nl:SECRET_NAME}} placeholder syntax to reference secrets safely and submit commands in plaintext."
}

8.4.3 Blocked Kubernetes Secret Extraction

{
  "status": "BLOCKED",
  "rule_id": "NL-4-DENY-017",
  "category": "bulk_export",
  "severity": "critical",
  "blocked_action": "kubectl get secret my-secret -o json",
  "reason": "Extracting Kubernetes secrets with JSON output returns base64-encoded secret values in the 'data' field. These values can be trivially decoded and would enter the agent's context.",
  "risk": "All key-value pairs in the Kubernetes secret would be exposed in base64 format, which is equivalent to plaintext.",
  "safe_alternative": {
    "description": "Use the NL Protocol Kubernetes integration to inject secrets directly into pod specifications without retrieving their values.",
    "example": "Submit an Action Request with command: kubectl apply -f deployment.yaml (where deployment.yaml uses {{nl:db/password}} placeholders)",
    "documentation": "https://nlprotocol.org/spec/v1.0/04-pre-execution-defense#bulk-export"
  },
  "agent_guidance": "Do not extract Kubernetes secret values. Reference them with {{nl:k8s/SECRET_NAME}} in your manifests."
}

9. Opaque Proxy Pattern for MCP and API Servers

9.1 Purpose

When agents interact with secret managers through MCP (Model Context Protocol) servers, REST APIs, or GraphQL endpoints, the server itself becomes a critical trust boundary. A poorly designed MCP server can expose secret values through its tool names, input schemas, or return types -- even if the agent did not explicitly request those values. This section defines the Opaque Proxy Pattern to prevent such exposure at the API design level.

9.2 Tool Naming Constraints

MCP servers and API endpoints that manage secrets MUST NOT expose tools or endpoints whose names suggest that they return secret values. The following name patterns MUST NOT be used:

Prohibited Pattern Reason
get_value, getValue Implies returning a secret's value
reveal, reveal_secret Implies making a secret visible
decrypt, decrypt_secret Implies returning decrypted plaintext
raw, raw_value, get_raw Implies unprocessed secret data
fetch_secret, read_secret Implies reading the secret's content
export, dump, dump_secrets Implies bulk data extraction
plaintext, cleartext Implies unencrypted content
show_secret, display_secret Implies visual display of the value

Tools that manage secrets SHOULD use action-oriented names:

Recommended Pattern Purpose
inject_secret Inject a secret into an execution context
list_secrets List secret names and metadata (not values)
search_secrets Search for secrets by name, category, or tag
create_secret Create a new secret
rotate_secret Rotate a secret's value
delete_secret Delete a secret
verify_access Check whether the agent has access to a specific secret

9.3 Return Type Constraints

The return type schema of any tool or endpoint related to secrets MUST NOT include fields that could contain secret values. Implementations MUST validate return schemas at server startup and at tool registration time.

Non-compliant return schema (MUST NOT be used):

{
  "name": "get_secret",
  "returns": {
    "type": "object",
    "properties": {
      "name": { "type": "string" },
      "value": { "type": "string" },
      "category": { "type": "string" }
    }
  }
}

Compliant return schema:

{
  "name": "inject_secret",
  "returns": {
    "type": "object",
    "properties": {
      "status": { "type": "string", "enum": ["success", "error", "blocked"] },
      "stdout": { "type": "string", "description": "Sanitized command output" },
      "stderr": { "type": "string", "description": "Sanitized error output" },
      "exit_code": { "type": "integer" }
    }
  }
}

9.4 Pre-Authentication Resources

MCP servers SHOULD expose documentation resources that do not require authentication. These resources educate agents about the NL Protocol's constraints and safe usage patterns before any authenticated interaction occurs. Exposing documentation before authentication reduces the rate of blocked actions because the agent understands the rules before it starts working.

Pre-authentication resources SHOULD include:

  1. Protocol overview: What the NL Protocol is and its core security model ("use secrets without seeing them").
  2. Usage guide: How to use the {{nl:<reference>}} placeholder syntax and action-based access.
  3. Available tools: What authenticated tools are available and what they do (without exposing any data).
  4. Deny rules summary: What actions are blocked, why, and what the safe alternatives are.

Example MCP resource URIs:

nl-provider://docs/overview              -> NL Protocol overview
nl-provider://docs/usage                 -> Placeholder syntax and injection guide
nl-provider://docs/tools                 -> Available MCP tools reference
nl-provider://docs/never-leak-protocol   -> Security rules and deny patterns
nl-provider://docs/api-reference         -> API reference

9.5 API Endpoint Constraints

REST APIs, GraphQL endpoints, and other programmatic interfaces that manage secrets MUST follow the same constraints as MCP tools:

  1. No endpoint MUST return secret values in response bodies.
  2. Endpoint paths MUST NOT suggest value retrieval (e.g., /secrets/{id}/value is prohibited; /secrets/{id}/metadata is acceptable).
  3. Response schemas MUST be validated to ensure no field contains or could contain a secret value.
  4. API documentation MUST clearly indicate that all endpoints return masked data only.
  5. List endpoints MUST return secret names, categories, and metadata -- never values.

10. Platform Integration Points

10.1 Purpose

The NL Protocol is designed to be implementable across any platform that mediates agent actions. This section defines how the Pre-Execution Defense layer integrates with specific platform categories. Each integration point specifies where interception occurs, how deny rules are loaded, and how bypass prevention is achieved.

10.2 Universal Integration Requirements

Regardless of platform, every integration MUST satisfy:

  1. Interception point: Define where in the platform's action pipeline the interceptor is invoked.
  2. Deny rule loading: Define how standard and custom deny rules are loaded and updated.
  3. Response delivery: Define how educational responses are delivered back to the agent.
  4. Bypass prevention: Ensure no code path from agent to execution bypasses the interceptor.
  5. Audit integration: Every interception decision MUST be loggable per Chapter 05.

10.3 AI Coding Assistants

10.3.1 Claude Code

  • Interception point: PreToolUse hooks defined in .claude/hooks.json.
  • Deny rule loading: The hook script loads deny rules from a configuration file or evaluates them inline.
  • Response delivery: The hook script outputs the educational response to stdout. Exit code 2 signals a block; exit code 0 signals allow.
  • Bypass prevention: The .claude/settings.local.json file MUST include deny patterns in the blockedCommands array as a secondary enforcement layer.

Example hook configuration:

{
  "hooks": {
    "PreToolUse": [
      {
        "type": "command",
        "command": "vault-guard.sh \"$NL_TOOL_NAME\" \"$NL_TOOL_INPUT\"",
        "blocking": true
      }
    ]
  }
}

10.3.2 Cursor

  • Interception point: .cursorrules file with deny patterns as agent instructions, plus .cursor/mcp.json for MCP-level enforcement.
  • Deny rule loading: Deny patterns are embedded as natural language instructions in the .cursorrules file; MCP server enforces programmatically.
  • Response delivery: The .cursorrules instructions tell the agent to use safe alternatives; the MCP server returns structured error responses.
  • Bypass prevention: MCP server-side enforcement provides the programmatic enforcement layer.

10.3.3 Generic MCP Clients

  • Interception point: MCP server-side tool validation at request processing time.
  • Deny rule loading: The MCP server enforces deny rules internally before executing any tool.
  • Response delivery: The tool returns an error result containing the educational response as structured JSON.
  • Bypass prevention: The MCP server is the sole execution path; the agent has no direct access to the underlying system.

10.4 CI/CD Pipelines

10.4.1 GitHub Actions

  • Interception point: A composite action or reusable workflow step that validates commands before execution.
  • Deny rule loading: Rules loaded from a configuration file in the repository or from a shared organization-level configuration.
  • Response delivery: The action fails with an annotation containing the educational response.
  • Bypass prevention: The validation step MUST be enforced via required workflows or branch protection rules that cannot be overridden by repository contributors.

Example workflow step:

- name: NL Protocol Pre-Execution Check
  uses: nlprotocol/guard-action@v1
  with:
    command: ${{ steps.agent.outputs.command }}
    deny_rules: standard+custom
    fail_on_block: true

10.4.2 GitLab CI

  • Interception point: A before_script block or CI/CD component.
  • Deny rule loading: Rules loaded from CI/CD variables or an external configuration endpoint.
  • Response delivery: Pipeline fails with a descriptive error in the job log.
  • Bypass prevention: The before_script MUST be defined in a shared CI template (using include) that project-level .gitlab-ci.yml files cannot override.

10.4.3 Jenkins

  • Interception point: A shared library step invoked before each agent-generated command.
  • Deny rule loading: Rules loaded from Jenkins credentials store or a configuration management system.
  • Response delivery: The shared library step fails the build with a descriptive error message.
  • Bypass prevention: The shared library MUST be configured as a globally trusted library.

10.5 Cloud Platforms

10.5.1 AWS

  • Interception point: Lambda authorizer on API Gateway, IAM policy conditions, or AWS Config rules.
  • Deny rule loading: Rules stored in AWS Systems Manager Parameter Store or S3.
  • Response delivery: API Gateway returns the educational response as a structured JSON error body.
  • Bypass prevention: IAM policies MUST deny direct secretsmanager:GetSecretValue and ssm:GetParameter (for SecureString) to agent IAM roles. Agents MUST access secrets only through an NL Protocol-compliant intermediary Lambda or service.

10.5.2 GCP

  • Interception point: Cloud Functions or Cloud Run service acting as a proxy before Secret Manager.
  • Deny rule loading: Rules stored in non-secret configuration in Firestore, Cloud Storage, or environment configuration.
  • Response delivery: The proxy returns the educational response as a structured JSON error.
  • Bypass prevention: IAM bindings MUST deny secretmanager.versions.access to agent service accounts. Agents access secrets only through the proxy.

10.5.3 Azure

  • Interception point: Azure API Management policy, Azure Functions proxy, or Managed Identity configuration.
  • Deny rule loading: Rules stored in Azure App Configuration or Blob Storage.
  • Response delivery: The proxy returns the educational response as a structured JSON error.
  • Bypass prevention: Azure RBAC MUST deny Key Vault get operations to agent managed identities directly. Agents MUST use the NL Protocol proxy.

10.6 SaaS Platforms

10.6.1 Stripe

  • Interception point: A proxy service that mediates all agent interactions with the Stripe API.
  • Deny rule loading: Rules embedded in the proxy configuration.
  • Response delivery: The proxy returns the educational response when a blocked pattern is detected.
  • Bypass prevention: Restricted API keys with minimal scope MUST be used. Agents MUST NOT have access to unrestricted Stripe secret keys. The proxy is the only component with API key access.

10.6.2 GitHub (as a Platform)

  • Interception point: GitHub App permissions, fine-grained PAT scope limits, and webhook-based validation.
  • Deny rule loading: Rules stored in the GitHub App's server-side configuration.
  • Response delivery: Check run annotations or commit status descriptions with the educational response.
  • Bypass prevention: Fine-grained personal access tokens or GitHub App installation tokens with minimal scopes. Agents MUST NOT have access to classic PATs with broad scope.

10.7 Custom Platforms (Webhook-Based Interception)

10.7.1 Webhook Pattern

For platforms not covered in Sections 10.3 through 10.6, implementations MUST support a webhook-based interception pattern:

  1. The agent's execution environment sends a pre-execution webhook request to an NL Protocol interceptor service.
  2. The interceptor evaluates the action against standard and custom deny rules.
  3. The interceptor responds with allow or block, including the educational response if blocked.
  4. The execution environment proceeds or halts based on the interceptor's response.

Webhook request format:

{
  "webhook_version": "1.0",
  "agent": {
    "agent_id": "nl://example.com/deploy-bot/1.0.0",
    "organization_id": "org_example",
    "session_id": "session_abc123"
  },
  "action": {
    "type": "exec",
    "command": "vault get API_KEY",
    "timestamp": "2026-02-08T10:30:00.000Z"
  },
  "platform": "custom-orchestrator",
  "request_id": "req-7f3a2b1c",
  "nonce": "nonce-unique-value"
}

Webhook response format:

{
  "decision": "block",
  "request_id": "req-7f3a2b1c",
  "response": {
    "status": "BLOCKED",
    "rule_id": "NL-4-DENY-001",
    "category": "direct_secret_access",
    "reason": "Direct secret retrieval is not permitted under NL Protocol Level 4.",
    "safe_alternative": {
      "description": "Use action-based access with {{nl:API_KEY}} placeholder syntax.",
      "example": "Submit an Action Request with command: curl -H \"Auth: Bearer {{nl:API_KEY}}\" https://api.example.com"
    }
  }
}

10.7.2 Webhook Security Requirements

Webhook-based interception MUST use the following security measures:

  1. TLS: All webhook communication MUST use HTTPS with TLS 1.2 or higher.
  2. Authentication: Webhook requests MUST be authenticated using HMAC-SHA256 signatures, mutual TLS, or OAuth 2.0 bearer tokens.
  3. Timeout: Webhook responses MUST be received within a configurable timeout (RECOMMENDED: 5 seconds). If the timeout is exceeded, the action MUST be blocked (fail-closed per Section 7).
  4. Replay prevention: Webhook requests MUST include a timestamp and nonce. The interceptor MUST reject requests with timestamps older than 5 minutes or with previously seen nonces.
  5. Idempotency: The interceptor MUST return the same decision for the same request_id if the request is retried.

11. Defense Bypass Prevention

11.1 Requirement

The interceptor MUST be implemented such that no agent-accessible mechanism can bypass, disable, or circumvent it. Bypass prevention is a fundamental architectural requirement, not an optional feature.

11.2 Bypass Vectors and Mitigations

Bypass Vector Required Mitigation
Agent modifies interceptor configuration files Configuration files MUST be read-only to the agent's process. File integrity monitoring SHOULD detect and alert on changes.
Agent terminates the interceptor process The interceptor MUST run as a separate, privileged process that the agent cannot signal or terminate. Alternatively, the interceptor MUST be embedded in the execution pipeline such that its absence blocks all actions (fail-closed).
Agent uses an alternative execution path All execution paths MUST route through the interceptor. Implementations MUST audit their architecture to confirm no alternative paths exist.
Agent writes a script and executes it later File write operations followed by execution MUST be correlated and analyzed (Section 6.2.5). Scheduled task creation (cron, at) MUST be blocked by default.
Agent requests another agent to execute a blocked command Cross-agent action requests MUST also pass through the receiving agent's interceptor (Chapter 07). There is no "trusted agent" exemption.
Agent modifies deny rules at runtime Deny rule creation, modification, and deletion MUST require human administrator privileges. These privileges MUST NOT be delegatable to agents.
Agent manipulates the interceptor's input before evaluation The interceptor MUST receive the raw, unmodified action as submitted by the agent. No intermediate layer MUST be able to sanitize or transform the action before interception evaluation.

11.3 Architectural Guarantee

Implementations MUST ensure that the interceptor is in the mandatory execution path:

  1. The interceptor MUST NOT be an optional middleware that can be configured off.
  2. The interceptor MUST NOT be bypassable by calling underlying system functions directly.
  3. The interceptor MUST be initialized and healthy before any agent action is processed.
  4. If the interceptor is not initialized, has failed, or has been tampered with, zero agent actions MUST be processed.

12. Security Considerations

  • Performance. The interceptor adds latency to every agent action. Implementations SHOULD optimize pattern matching using compiled regular expressions, trie-based matchers, or Aho-Corasick multi-pattern matching to minimize overhead. The RECOMMENDED maximum latency added by the interceptor is 10 milliseconds per action.

  • False positives. Some deny rules -- particularly in the indirect execution category (Section 3.2.7) -- may block legitimate actions. Implementations SHOULD provide mechanisms for administrators to review blocked actions and adjust custom rules. Agents MUST NOT be given the ability to override or dismiss blocks.

  • Rule updates. When deny rules are updated (standard rules via protocol version update, custom rules via administrator action), the interceptor MUST reload rules without requiring a process restart. Rule reloading MUST be atomic: the old rule set is enforced until the new rule set is fully loaded and validated.

  • Logging. Every interception decision MUST be logged for audit purposes (Chapter 05). Block decisions MUST always be logged. Allow decisions SHOULD be logged at a configurable verbosity level.

  • Denial of service. An agent could flood the interceptor with rapid requests to degrade its performance or cause it to fail (triggering fail-closed blocking of all actions). Implementations SHOULD apply per-agent rate limiting independently of the interceptor to mitigate this vector.

  • Rule completeness. The standard deny rules defined in this chapter represent a baseline. No deny rule set is exhaustive. Organizations SHOULD continuously evaluate their custom rule sets based on observed blocked actions, security incidents, and new attack techniques.

13. Conformance Requirements

An implementation conforms to NL Protocol Level 4 if it satisfies all MUST-level requirements. Full conformance includes satisfying all MUST and SHOULD requirements.

Requirement ID Description Level
NL-4.1 All agent actions pass through a pre-execution interceptor (Section 2.1) MUST
NL-4.2 Standard deny rules are enforced across all seven categories (Section 3.2) MUST
NL-4.3 Organizations can define, manage, and enforce custom deny rules (Section 4) MUST
NL-4.4 Encoding and evasion attempts are detected and blocked (Section 6) MUST
NL-4.5 Fail-closed behavior on any interceptor failure (Section 7) MUST
NL-4.6 Educational responses returned for every blocked action (Section 8) MUST
NL-4.7 No bypass path exists from agent to execution without interception (Section 11) MUST
NL-4.8 MCP/API servers follow the Opaque Proxy Pattern (Section 9) MUST
NL-4.9 Allowlist mode is supported (Section 5) SHOULD
NL-4.10 Pre-authentication documentation resources are exposed (Section 9.4) SHOULD
NL-4.11 At least one platform integration is implemented (Section 10) SHOULD
NL-4.12 Webhook-based interception is supported for custom platforms (Section 10.7) SHOULD
NL-4.13 Interceptor health monitoring is implemented (Section 7.3) SHOULD
NL-4.14 Variable expansion analysis is performed for evasion detection (Section 6.2.4) MAY
NL-4.15 Write-then-execute pattern detection is implemented (Section 6.2.5) MAY

14. References