Input validation
Opt-in JSON Schema validation of tool inputs plus user-message limits, prompt-injection checks, and allowlists.
Every agent boundary is an attack surface. Validate tool arguments and user messages before they enter the agent loop.
#Validate model-proposed tool arguments
Tool schemas are optional in the core contract, and core does not bundle a runtime validator. For production tool boundaries, attach a JSON Schema and opt in to the Ajv-backed validator published through @agentskit/tools/validation:
import type { ToolDefinition } from '@agentskit/core'
import { createChatController } from '@agentskit/core'
import { createAjvValidator } from '@agentskit/tools/validation'
const fetchUrl: ToolDefinition = {
name: 'fetch_url',
description: 'Fetch the content of a URL.',
schema: {
type: 'object',
properties: {
url: {
type: 'string',
format: 'uri',
maxLength: 2048,
pattern: '^https://', // allowlist: HTTPS only
},
},
required: ['url'],
additionalProperties: false,
},
execute: async (args) => { /* ... */ },
}
const chat = createChatController({
adapter,
tools: [fetchUrl],
validateArgs: createAjvValidator(),
})With validateArgs configured, a mismatch is rejected as AK_TOOL_INVALID_INPUT before execute. Without it, behavior remains passthrough. A tool without schema is also skipped by the validator.
JSON Schema is the canonical tool contract. Do not maintain a second schema solely for runtime validation; that invites drift between the model-visible schema and the executable boundary.
#Strict additional properties
const validateArgs = createAjvValidator({
rejectAdditionalProperties: true,
})This recursively adds additionalProperties: false to ordinary object boundaries that omit a policy, without mutating the source schema. Explicit additionalProperties policies are preserved. Draft-07 composition and applicator boundaries (allOf, anyOf, oneOf, conditionals, and schema dependencies) cannot safely infer one combined property set, so they stay as authored; declare additionalProperties: false explicitly on the appropriate composed boundary.
coerceTypes is off by default. Enabling it can mutate the argument object. If you pass a pre-configured Ajv instance, that instance owns coercion, formats, keywords, and strictness.
Schemas are trusted application configuration and compile lazily. An invalid schema throws on its first validation attempt; invalid model arguments return structured paths without including argument values.
#User message validation
Validate user input before passing it to chat.send:
const MAX_MESSAGE_LENGTH = 4_000 // tokens β chars / 4
function validateUserMessage(text: string): string {
if (text.length > MAX_MESSAGE_LENGTH) {
throw new RangeError(`Message too long (${text.length} chars, max ${MAX_MESSAGE_LENGTH})`)
}
// Strip null bytes and non-printable control characters
return text.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, '')
}
chat.send(validateUserMessage(rawUserInput))#Escape sequences and null bytes
Models and logging pipelines are sensitive to escape sequences injected by user input:
function sanitizeForLogging(s: string): string {
// Remove ANSI escape codes
return s.replace(/\x1B\[[0-9;]*[A-Za-z]/g, '')
}#Prompt injection mitigation
Use createInjectionDetector from @agentskit/core/security as a preprocess step:
import { createInjectionDetector } from '@agentskit/core/security'
const detector = createInjectionDetector()
async function sendSafe(text: string) {
const verdict = await detector.check(text)
if (verdict.blocked) {
throw new Error(`Input rejected: ${verdict.reason}`)
}
return chat.send(text)
}The heuristic layer catches "ignore previous instructions", role-swap attempts, and fenced payloads synchronously at zero cost. See Prompt injection for the full API.
#Allowlist patterns
Prefer allowlists over denylists for structured values:
const ALLOWED_TOOLS = new Set(['web_search', 'calculator', 'read_file'])
function assertAllowedTool(name: string): void {
if (!ALLOWED_TOOLS.has(name)) {
throw new Error(`Tool not permitted: ${name}`)
}
}Apply the same pattern to file paths (canonical path prefix check), URLs (origin allowlist), and model names.
#Max-length limits
Set maxLength on every string property in JSON Schema and enforce at runtime:
| Boundary | Recommended limit |
|---|---|
| User message | 4 000 chars |
Tool description | 1 024 chars |
| Tool string arg | 2 048 chars (adjust per tool) |
| RAG chunk injected | 8 000 chars |
| System prompt | 16 000 chars |
#Related
- Prompt injection β heuristic + model classifier for injection detection
- Mandatory sandbox β allow/deny/require across tool calls
- Rate limiting β token-bucket limits by user / IP / key
Explore nearby
- PeerSecurity
Six primitives for production agents: PII redaction, injection detection, rate limiting, audit log, sandbox enforcement, and HITL approvals.
- PeerPII redaction
Strip emails, phones, SSNs, and API keys from messages before they reach the model or get written to logs.
- PeerPrompt injection
Detect instruction-hijacking patterns in user input, tool results, and RAG chunks before they reach the model.