rust-yaml implements comprehensive security measures to protect against common YAML parsing vulnerabilities, including the billion laughs attack, resource exhaustion, and malformed document attacks.
rust-yaml enforces configurable resource limits to prevent resource exhaustion attacks:
- Max Depth: Limits nesting depth of collections (default: 1000)
- Max Anchors: Limits number of anchors per document (default: 10,000)
- Max Document Size: Limits total document size in bytes (default: 100MB)
- Max String Length: Limits individual string length (default: 10MB)
- Max Alias Depth: Limits alias expansion depth (default: 100)
- Max Collection Size: Limits items in a single collection (default: 1,000,000)
- Max Complexity Score: Limits overall document complexity (default: 1,000,000)
The billion laughs attack (exponential entity expansion) is prevented through:
- Alias expansion depth tracking
- Cyclic reference detection
- Complexity scoring for nested structures
- Collection size limits
Example of prevented attack:
# This would expand exponentially without protection
a: &a ["lol", "lol", "lol", "lol", "lol", "lol", "lol", "lol", "lol"]
b: &b [*a, *a, *a, *a, *a, *a, *a, *a, *a]
c: &c [*b, *b, *b, *b, *b, *b, *b, *b, *b]
# ... would expand to 9^n itemsrust-yaml detects and prevents cyclic alias references:
# This cyclic reference is detected and rejected
a: &a
b: *b
b: &b
a: *ause rust_yaml::{Yaml, YamlConfig, Limits};
let mut config = YamlConfig::default();
config.limits = Limits::strict();
let yaml = Yaml::with_config(config);Strict limits:
- Max depth: 50
- Max anchors: 100
- Max document size: 1MB
- Max string length: 64KB
- Max alias depth: 5
- Max collection size: 10,000
- Timeout: 5 seconds
let config = YamlConfig::secure();
let yaml = Yaml::with_config(config);Balanced security for production use with reasonable limits.
let mut config = YamlConfig::default();
config.limits = Limits::permissive();Higher limits for trusted sources:
- Max depth: 10,000
- Max anchors: 100,000
- Max document size: 1GB
- Max string length: 100MB
use rust_yaml::{Limits, YamlConfig};
use std::time::Duration;
let mut limits = Limits::default();
limits.max_depth = 100;
limits.max_anchors = 500;
limits.max_document_size = 5 * 1024 * 1024; // 5MB
limits.timeout = Some(Duration::from_secs(10));
let mut config = YamlConfig::default();
config.limits = limits;Never parse untrusted YAML without resource limits:
// BAD - No protection
let yaml = Yaml::new();
let result = yaml.load_str(untrusted_input); // Vulnerable!
// GOOD - Protected parsing
let config = YamlConfig::secure();
let yaml = Yaml::with_config(config);
let result = yaml.load_str(untrusted_input); // ProtectedSelect limits based on your use case:
- Configuration files: Use
strict()limits - User-generated content: Use
strict()with custom timeout - Internal data: Use
default()orpermissive() - Large datasets: Use custom limits with appropriate sizes
Resource limit errors should be handled appropriately:
match yaml.load_str(input) {
Ok(value) => process_value(value),
Err(e) if e.to_string().contains("limit") => {
// Log security event
log::warn!("Resource limit exceeded: {}", e);
// Return safe error to user
return Err("Document too complex");
}
Err(e) => {
// Handle other parsing errors
return Err(format!("Invalid YAML: {}", e));
}
}Use the ResourceTracker to monitor actual usage:
let tracker = ResourceTracker::new();
// After parsing, check statistics
let stats = tracker.stats();
log::debug!("Max depth: {}, Anchors: {}, Complexity: {}",
stats.max_depth, stats.anchor_count, stats.complexity_score);Even with security limits, validate parsed content:
let value = yaml.load_str(input)?;
// Validate expected structure
if !validate_schema(&value) {
return Err("Invalid document structure");
}
// Sanitize values if needed
let sanitized = sanitize_values(value);- Attack: Nested aliases causing exponential growth
- Protection: Alias depth limits, complexity scoring
- Attack: Deeply nested structures causing stack overflow
- Protection: Max depth limits
- Attack: Huge arrays/maps consuming memory
- Protection: Collection size limits
- Attack: Multi-gigabyte strings
- Protection: String length limits
- Attack: Thousands of anchors slowing parsing
- Protection: Anchor count limits
Run security tests to verify protection:
cargo test --test security_limitsTests include:
- A Billion laughs attack prevention
- Cyclic reference detection
- Resource limit enforcement
- Timeout handling
If you discover a security vulnerability:
- Do not create a public issue
- Email security concerns to the maintainers
- Include:
- Description of the vulnerability
- Steps to reproduce
- Potential impact
- Suggested fix (if any)
- Security updates are released as patch versions
- Critical vulnerabilities trigger immediate releases
- Subscribe to security advisories for notifications
Last updated: 2025-08-16