agentskit.js
Security

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:

BoundaryRecommended limit
User message4 000 chars
Tool description1 024 chars
Tool string arg2 048 chars (adjust per tool)
RAG chunk injected8 000 chars
System prompt16 000 chars

Explore nearby

✎ Edit this page on GitHubΒ·Found a problem? Open an issue β†’Β·How to contribute β†’

On this page

Ask the docs
Ask anything about AgentsKit. Answers come from the docs corpus and cite their sources.