Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Security Considerations

synkit is designed for parsing untrusted input. This page documents the security model, protections, and best practices for generated parsers.

No Unsafe Code

synkit uses zero unsafe blocks in core, macros, and kit crates. Memory safety is guaranteed by the Rust compiler.

# Verify yourself
grep -r "unsafe" core/src macros/src kit/src
# Returns no matches

Resource Exhaustion Protection

Recursion Limits

Deeply nested input like [[[[[[...]]]]]] can cause stack overflow. synkit provides configurable recursion limits:

use synkit::ParseConfig;

// Default: 128 levels (matches serde_json)
let config = ParseConfig::default();

// Stricter limit for untrusted input
let config = ParseConfig::new()
    .with_max_recursion_depth(32);

// Track depth manually in your parser
use synkit::RecursionGuard;

struct MyParser {
    depth: RecursionGuard,
    config: ParseConfig,
}

impl MyParser {
    fn parse_nested(&mut self) -> Result<(), MyError> {
        self.depth.enter(self.config.max_recursion_depth)?;
        // ... parse nested content ...
        self.depth.exit();
        Ok(())
    }
}

Token Limits

Prevent CPU exhaustion from extremely long inputs:

let config = ParseConfig::new()
    .with_max_tokens(100_000);  // Fail after 100k tokens

Buffer Limits (Streaming)

For incremental parsing, StreamConfig controls memory usage:

use synkit::StreamConfig;

let config = StreamConfig {
    max_chunk_size: 16 * 1024,      // 16KB max per chunk
    token_buffer_size: 1024,        // Token buffer capacity
    ast_buffer_size: 64,            // AST node buffer
    ..StreamConfig::default()
};

Exceeding limits produces explicit errors:

ErrorTrigger
StreamError::ChunkTooLargeInput chunk > max_chunk_size
StreamError::BufferOverflowToken buffer exceeded capacity
StreamError::ResourceLimitGeneric limit exceeded
Error::RecursionLimitExceededNesting depth > max_recursion_depth
Error::TokenLimitExceededToken count > max_tokens

Integer Safety

All span arithmetic uses saturating operations to prevent overflow panics:

// Span length - saturating subtraction
fn len(&self) -> usize {
    self.end().saturating_sub(self.start())
}

// Recursion guard - saturating increment
self.depth = self.depth.saturating_add(1);

// Cursor bounds - clamped to valid range
self.cursor = pos.clamp(self.range_start, self.range_end);

See Safety & Clamping for detailed behavior documentation.

Memory Safety

Generated TokenStream uses Arc for shared ownership:

pub struct TokenStream {
    source: Arc<str>,           // Shared source text
    tokens: Arc<Vec<Token>>,    // Shared token buffer
    // ... cursors are Copy types
}

Benefits:

  • fork() is zero-copy (Arc::clone only)
  • Thread-safe: TokenStream is Send + Sync
  • No dangling references possible

Fuzz Testing

synkit includes continuous fuzz testing via cargo-fuzz:

# Run lexer fuzzer
cargo +nightly fuzz run fuzz_lexer

# Run parser fuzzer
cargo +nightly fuzz run fuzz_parser

Fuzz targets exercise:

  • Arbitrary UTF-8 input
  • Edge cases in span arithmetic
  • Token stream operations
  • Incremental buffer management

Adding Fuzz Tests for Your Parser

#![no_main]
use libfuzzer_sys::fuzz_target;

fuzz_target!(|data: &[u8]| {
    if let Ok(s) = std::str::from_utf8(data) {
        // Ignore lex errors, just ensure no panics
        let _ = my_parser::TokenStream::lex(s);
    }
});

Security Checklist

When building a parser for untrusted input:

  • Set max_recursion_depth appropriate for your format
  • Set max_tokens to prevent CPU exhaustion
  • Use StreamConfig limits for streaming parsers
  • Handle all error variants (don’t unwrap)
  • Add fuzz tests for your grammar
  • Consider timeout limits at the application layer

Threat Model

synkit protects against:

ThreatProtection
Stack overflowRecursion limits
Memory exhaustionBuffer limits, Arc sharing
CPU exhaustionToken limits
Integer overflowSaturating arithmetic
Undefined behaviorNo unsafe code

synkit does NOT protect against:

ThreatMitigation
Regex backtracking (logos)Use logos’ regex restrictions
Application-level DoSAdd timeouts in your application
Malicious AST semanticsValidate AST after parsing

Reporting Vulnerabilities

Please open a Github security advisory.