How Shannon Validates YAML Configuration Files Using JSON Schema and AJV

Shannon performs a defense-in-depth validation by combining strict YAML parsing with js-yaml's FAILSAFE_SCHEMA, AJV JSON Schema validation against a Draft-07 schema, and custom security checks for dangerous patterns before distributing sanitized configuration to agents.

The KeygraphHQ/shannon repository implements a robust configuration validation pipeline that ensures user-supplied YAML files meet strict security and structural requirements before execution. This article examines how the framework validates YAML configuration files using JSON Schema and AJV within the src/config-parser.ts module, combining schema-based validation with additional security scans to prevent code injection and misconfiguration.

Loading the Canonical JSON Schema

Shannon validates all configurations against a strict Draft-07 JSON Schema defined in configs/config-schema.json. This schema defines the exact shape, required fields, formats, enumerations, and length limits for every configuration section including authentication and rules.

The schema is loaded and compiled once during initialization:

// src/config-parser.ts – lines 30-38
const schemaPath = new URL('../configs/config-schema.json', import.meta.url);
const schemaContent = await fs.readFile(schemaPath, 'utf8');
configSchema = JSON.parse(schemaContent) as object;
validateSchema = ajv.compile(configSchema);

This compilation step creates a reusable validation function that enforces constraints such as URI formats for login_url, enumerated values for login_type, and minimum/maximum string lengths throughout the configuration structure.

Safe YAML Parsing with js-yaml

Before schema validation begins, Shannon parses YAML content using the js-yaml library with security-hardened options. The parser explicitly uses FAILSAFE_SCHEMA to disable any JavaScript evaluation and limit parsing to plain scalars, sequences, and mappings.

// src/config-parser.ts – lines 82-90
config = yaml.load(configContent, {
  schema: yaml.FAILSAFE_SCHEMA,
  json: false,
  filename: configPath,
});

FAILSAFE_SCHEMA guarantees that only native YAML types are allowed, preventing hidden code execution or arbitrary object instantiation that could lead to remote code injection attacks. This strict parsing ensures that the input to the JSON Schema validator contains only safe, serializable data structures.

AJV Schema Validation

Once the YAML is parsed into a JavaScript object, Shannon validates it using AJV (Another JSON Schema Validator) configured for comprehensive error reporting. The validator is instantiated with allErrors: true and verbose: true to capture every constraint violation simultaneously, and extended with ajv-formats to support URI format checks defined in the schema.

// src/config-parser.ts – lines 33-41
const ajv = new Ajv({ allErrors: true, verbose: true });
addFormats(ajv);

The validation execution occurs immediately after parsing:

// src/config-parser.ts – validation execution
const isValid = validateSchema(config);
if (!isValid) {
  const errors = validateSchema.errors || [];
  // build a readable error message
}

If any constraint from configs/config-schema.json fails—such as an invalid login_type enum value, a malformed URI in login_url, or string lengths outside defined bounds—the function throws a detailed error message listing all violations.

Post-Schema Security Validation

After JSON Schema validation passes, Shannon performs additional security checks that catch malicious content patterns not covered by structural schema constraints. These checks scan credentials, login flow steps, rule URLs, and descriptions for dangerous content.

The security validation is implemented in src/config-parser.ts (lines 64-84 and 164-198) and examines:

  • Credentials – Usernames and passwords are scanned for patterns such as ../, <, >, and javascript: to prevent injection attacks
  • Login flow steps – Each step in the authentication sequence is vetted against the same dangerous patterns
  • Rule definitions – Both avoid and focus arrays are inspected for path traversal attempts or script injection in url_path and description fields
  • Rule-type constraints – Specific validations ensure path-type rules start with a slash, method rules contain valid HTTP verbs, and domain rules contain dots

These checks prevent configuration-based attacks that could lead to path traversal, code execution, or unauthorized network requests even when the YAML structure is technically valid.

Configuration Sanitization and Distribution

Following successful validation, the configuration undergoes normalization to ensure consistent data handling. The sanitization process trims whitespace, lower-cases enumerated strings where appropriate, and prepares the data for agent consumption.

// src/config-parser.ts – lines 190-207 (sanitizeRule)
// src/config-parser.ts – lines 230-256 (sanitizeAuthentication)

The distributeConfig function then splits the validated and sanitized configuration into the DistributedConfig object, separating avoid, focus, and authentication sections for independent agent consumption.

Practical Example: Parsing and Validating Configuration

Below is a complete example demonstrating the validation pipeline with a valid Shannon configuration file:


# example-config.yaml

authentication:
  login_type: form
  login_url: https://app.example.com/login
  credentials:
    username: alice
    password: secret123
    totp_secret: JBSWY3DPEHPK3PXP
  login_flow:
    - "Enter username"
    - "Enter password"
    - "Submit form"
  success_condition:
    type: url_contains
    value: /dashboard
rules:
  avoid:
    - description: "Skip admin endpoints"
      type: path
      url_path: /admin
  focus:
    - description: "Test API injection vectors"
      type: path
      url_path: /api/v1/users

To parse and validate this configuration:

import { parseConfig, distributeConfig } from './src/config-parser.js';

async function load() {
  try {
    const cfg = await parseConfig('./configs/example-config.yaml');
    console.log('✅ Config loaded and validated');

    const distributed = distributeConfig(cfg);
    console.log('Distributed config for agents:', distributed);
  } catch (err) {
    console.error('❌ Config error:', err.message);
    // Handle the error (e.g., abort the pentest run)
  }
}

load();

When validation fails, AJV produces descriptive error messages indicating the specific path and constraint violation:

try {
  const cfg = await parseConfig('invalid.yaml');
} catch (e) {
  // AJV errors are formatted like:
  // root.authentication.login_url: must match format "uri"
  // root.rules.focus[0].type: must be equal to one of the allowed values
  console.error(e.message);
}

Summary

Shannon implements a comprehensive defense-in-depth strategy to validate YAML configuration files using JSON Schema and AJV:

  • Strict YAML parsing using js-yaml with FAILSAFE_SCHEMA prevents code execution during the parsing phase
  • Draft-07 JSON Schema validation via AJV enforces structural constraints, required fields, and format requirements defined in configs/config-schema.json
  • Comprehensive error reporting with AJV configured for allErrors: true captures every validation issue in a single pass
  • Secondary security validation scans for dangerous patterns including path traversal sequences and script injection attempts
  • Normalization pipeline sanitizes validated data through trimming, case normalization, and structured distribution to agents

Frequently Asked Questions

What version of JSON Schema does Shannon use?

Shannon uses JSON Schema Draft-07 for its configuration validation, as implemented by the AJV validator. The schema is defined in configs/config-schema.json and loaded by the src/config-parser.ts module, which compiles it into a validation function using ajv.compile().

How does Shannon prevent code injection during YAML parsing?

Shannon prevents code injection by parsing YAML with the FAILSAFE_SCHEMA option from js-yaml, which disables JavaScript evaluation and restricts parsing to plain scalars, sequences, and mappings only. This security setting ensures that malicious YAML tags or constructors cannot execute arbitrary code during the parsing phase.

What happens when a configuration fails validation?

When validation fails, the parseConfig function throws a detailed error containing all AJV validation errors and security check failures. With AJV configured for allErrors: true, the error message lists every constraint violation—such as invalid URI formats or missing required fields—rather than failing on the first error, enabling rapid debugging of configuration issues.

Which dangerous patterns does Shannon check for after schema validation?

Shannon's post-schema security validation scans for patterns including ../ (path traversal), < and > (HTML/script tags), and javascript: (protocol handlers) within credentials, login flow steps, rule URLs, and descriptions. It also enforces rule-type-specific constraints, such as requiring path-type rules to start with a forward slash and domain rules to contain at least one dot.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →