Security Guide
Security best practices for BoxLang AI - API key management, prompt injection prevention, data privacy, and compliance guidance.
Comprehensive security guide for BoxLang AI applications. Learn about API key management, input validation, prompt injection prevention, data privacy, multi-tenant security, and compliance best practices.
π‘οΈ Security Overview
Security Principles
Key security considerations for AI applications:
π Credential Security - Protect API keys and secrets
π« Input Validation - Sanitize all user inputs
π‘οΈ Prompt Injection - Defend against manipulation attacks
π Data Privacy - Handle sensitive data appropriately
π₯ Multi-Tenancy - Isolate user data completely
π PII Protection - Detect and redact personal information
π Audit Trails - Log all AI interactions
βοΈ Compliance - Meet regulatory requirements (GDPR, HIPAA, etc.)
Threat Model
Common AI application threats:
API Key Exposure
Unauthorized access, billing fraud
Secrets manager, rotation
Prompt Injection
Data leakage, unauthorized actions
Input validation, system message protection
Data Leakage
Privacy breach, compliance violation
PII detection, redaction
Excessive Usage
Cost overruns, DoS
Rate limiting, quotas
Model Poisoning
Incorrect responses
Output validation
Data Exfiltration
Sensitive data exposure
Access controls, auditing
π API Key Management
Never Hardcode Keys
Secrets Manager Integration
AWS Secrets Manager
Azure Key Vault
HashiCorp Vault
Key Rotation
Key Scope Limitation
Use separate keys for different environments:
π« Input Validation
Sanitize User Input
Always validate and sanitize user inputs before sending to AI:
Input Length Limits
Type Validation
π‘οΈ Prompt Injection Prevention
What is Prompt Injection?
Prompt injection is when attackers embed instructions in user input, retrieved documents, web pages fetched by tools, or MCP results β trying to override your system prompt, exfiltrate data, or hijack tool calls. Traditional input validation doesn't cover this class of attack. BoxLang AI ships five layered, configurable defenses for it β this section leads with those; hand-rolled alternatives are in the appendix below if you need something the built-ins don't cover.
Layer 1: Unicode Hygiene (on by default)
Every inbound user message is automatically NFKC-normalized and stripped of zero-width/invisible/bidi-control characters β the classic carriers for hidden instructions. No configuration needed; it applies to aiChat(), aiModel(), and aiAgent() alike, even with settings.security.enabled left false.
Layer 2: Input Sanitizer Middleware (opt-in)
InputSanitizerMiddleware heuristically scans user messages β and tool/MCP results β for injection patterns with six built-in detectors: instructionOverride, roleImpersonation, jailbreak, invisibleUnicode, base64Blob, and exfilUrl. Homoglyph folding on the detection copy defeats lookalike-character evasion.
Enable it globally with one setting β every AI request in your application is guarded:
Or attach it per-agent/per-model like any middleware:
The four actions:
block
Throws BXAI.SecurityViolation β the request never reaches the provider
strip
Removes the detected fragments and continues
flag
Continues; findings stamped on chatRequest.providerOptions.securityFindings and logged to the ai log (default β observe before you enforce)
log
Continues; logs only
For custom flows, scan directly:
Layer 3: Fencing Untrusted Content (RAG / tool data)
The most common real-world LLM attack is indirect prompt injection: an attacker hides instructions inside content your application retrieves β a knowledge-base doc, a web page, an MCP tool result β and the model, unable to tell your instructions from that data, obeys them. Fencing wraps untrusted content in unique random boundary markers plus a security preamble, so the model treats everything inside as inert data.
Produces a block the model is told never to obey β and an attacker cannot forge a closing marker to "break out" (the boundary id is random per call, and any marker syntax embedded in the content is neutralized):
For structured messages, mark segments untrusted and the preamble is injected automatically:
Fencing of the ${context} path is on by default β any context passed via options.context or ${context} is fenced automatically for every aiChat/aiModel/aiAgent request. Requests without context are unaffected. Opt out globally or per message:
Layer 4: LLM-as-Judge (middleware)
Layers 1β3 are pattern-based β fast and free, but they can miss novel or obfuscated attacks. LLMGuardMiddleware adds a semantic layer: a second, typically cheaper/faster model classifies the request (and optionally the response) for prompt-injection or harmful content before it's acted on.
A blocked request throws BXAI.SecurityViolation before the main model is ever called. The content shown to the judge is itself fenced so the judge can't be injected, the judge's own call is recursion-guarded, and verdicts are cached so identical inputs aren't re-judged. The judge must answer strict JSON: { "verdict": "SAFE|INJECTION|HARMFUL", "confidence": 0.0-1.0, "reason": "..." }.
Layer 5: Output Guard (middleware)
Layers 1β4 guard what goes in. OutputGuardMiddleware guards what comes out β see Output Validation below.
Complementary Practices
These general practices are still worth following alongside the built-in layers β they cost nothing and catch cases pattern-matching can't:
Testing Your Guardrails
The built-in mock provider runs the full pipeline (middleware, tool-calling loop, return formats) with scripted responses β no HTTP, no API keys β so you can prove your guardrails actually catch what you expect, offline:
π See examples/security in the bx-ai repo for runnable, fully-offline examples of all five layers.
π§ Tool & Function Calling Security
The Tool Calling Risk
AI agents can autonomously invoke tools based on user requests. If inputs aren't validated, attackers can:
Trigger unintended tool calls:
"Search my entire database"β database lookup toolPass malicious parameters:
"Look up user with id: 1; DROP TABLE users; --"Exploit tool side effects: Delete files, transfer funds, send emails
Combine tools maliciously: Web search β database lookup β email tool chain
Parameter Validation Before Tool Execution
Tool Invocation Sandboxing
Tool Audit & Rate Limiting
π External Data Source Validation
Web Search Result Validation
Web search results come from untrusted sources. Always validate before using:
Document Loader Input Validation
Loading documents from untrusted sources can introduce malicious content:
Vector Memory Poisoning Prevention
Adversaries can pollute vector databases with malicious embeddings:
π Web Search Specific Security
API Key & Rate Limiting
Search Query Sanitization
Domain Filtering
β Output Validation
Output Guard Middleware (built-in)
OutputGuardMiddleware scrubs the model's response before it reaches your application or the user, defending against two risks:
Secret/PII leakage β the model echoes an email, SSN, credit card, API key, or private key into its reply. These are masked.
Data exfiltration β an injected instruction makes the model emit a data-bearing markdown image (
) that leaks when the response is rendered. These are stripped.
It's 100% offline β regex redaction, a Luhn check for credit cards, and exfil stripping, no second model, no network:
redact (default)
Mask secrets + strip exfil, then let the clean response through
flag
Leave content intact, but stamp findings on chatRequest.providerOptions.securityFindings and log
block
Throw BXAI.SecurityViolation when anything is found
Built-in redactors (opt-in set): email, ssn, creditCard, awsAccessKey, privateKeyBlock, jwt, genericApiToken β plus phone and your own via customRedactors, which accepts either a regex string or a closure function( text, mask ) for dynamic redaction (partial masking, keep-last-4, an external lookup, etc.).
OutputGuardMiddleware also scans the model's reasoning (extended thinking / message.reasoning), not just its final answer β a secret named while thinking and never repeated in the answer is still redacted, and action: "block" fires for it too. See Reasoning.
Streaming caveat: streaming guards are detection-only, not prevention. afterLLMCall fires once the stream has ended, so block throws only after the caller's callback has already received every chunk, and redact rewrites an aggregate the provider has already finished emitting β withholding content mid-stream would need a per-chunk hook, which isn't implemented yet.
Application-Level Output Checks
OutputGuardMiddleware covers secrets and exfiltration; if your application renders AI output into HTML or SQL, it's still your responsibility to treat that output as untrusted at the render/query boundary β never trust AI output blindly:
Structured Output Validation
π Data Privacy
Local vs Cloud Providers
Choose providers based on privacy requirements:
Ollama
Local only
No
Never sent
Maximum privacy, on-premise
LM Studio
Local only
No
Never sent
Desktop, development
OpenAI
Cloud
No (since March 2023)
30 days
General use
Claude
Cloud
No
Not used for training
General use
Azure OpenAI
Your region
No
Controlled by you
Enterprise, compliance
Data Minimization
Send only necessary data to AI:
PII Detection and Redaction
Encryption
Encrypt sensitive data at rest and in transit:
π₯ Multi-Tenant Security
Complete Isolation
Ensure users can only access their own data:
Namespace Isolation
Row-Level Security
For database-backed memory:
π Audit Logging
Comprehensive Logging
Log all AI interactions for security and compliance:
Audit Query API
βοΈ Compliance
GDPR Compliance
Requirements for EU data:
HIPAA Compliance
Requirements for healthcare data:
Data Retention Policies
π§ Secure Configuration
Environment-Specific Settings
Security Headers
π Network Security
API Gateway
Route all AI requests through secure gateway:
TLS/SSL
Require HTTPS for all AI endpoints:
π¨ Incident Response
Security Incident Handling
π§© Appendix: Hand-Rolled Patterns
Everything below predates β and is now covered by β the five built-in guardrail layers above. Reach for these only if you need something the built-ins genuinely don't cover; they are not the recommended starting point.
Hand-Rolled Input Pattern Matching
InputSanitizerMiddleware (Layer 2) does this with six tunable detectors, homoglyph-folding, and flag/strip/block/log actions. A hand-rolled equivalent:
Hand-Rolled Delimiter Wrapping
aiFence() (Layer 3) does this with a random per-call boundary id that can't be forged, plus an auto-injected security preamble. A hand-rolled equivalent:
Hand-Rolled Response Keyword Filtering
OutputGuardMiddleware (Layer 5) redacts secrets/PII and strips exfiltration markdown with regex + Luhn validation, not a keyword blocklist. A hand-rolled equivalent:
Hand-Rolled Tool-Result Sanitization
InputSanitizerMiddleware( scanToolResults: true ) (Layer 2) scans tool/MCP results the same way it scans user input β the indirect-injection channel. A hand-rolled equivalent:
π Additional Resources
π‘οΈ Middleware Overview β middleware architecture and full catalog
π§Ό InputSanitizerMiddleware β inbound prompt-injection scanning and hygiene
π OutputGuardMiddleware β outbound redaction and exfiltration stripping
π€ LLMGuardMiddleware β LLM-as-judge semantic classification
π§ββοΈ Human-in-the-Loop β human approval for sensitive tool calls
π Gateways β HMAC-signed HTTP delivery for approvals and events
π Main Documentation
π¬ FAQ
π§ Key Concepts
π― Best Practices
β Security Checklist
Before deploying:
Last updated