Production-ready Rust implementation of MAEC 5.0 (Malware Attribute Enumeration and Characterization)
maec-rs provides a complete, type-safe implementation of the MAEC 5.0 specification for representing and sharing structured malware analysis data. Built for threat intelligence platforms, malware analysis tools, and security orchestration systems.
- โ All Core Objects - Package, MalwareFamily, MalwareInstance, Behavior, Capability, etc.
- โ All Open Vocabularies - Type-safe enums for labels, delivery vectors, capabilities, etc.
- โ JSON & XML Serialization - Dual format support via serde
- โ Builder Pattern - Ergonomic object construction with validation
- โ Type-Safe IDs - Automatic ID generation and validation
- โ STIX Integration - Reference STIX Cyber Observable Objects
- ๐ Comprehensive Error Handling - thiserror-based errors with context
- โ Full Validation - Required fields, ID formats, schema compliance
- ๐ก MIME Type Constants - Standard HTTP/TAXII content types
- ๐งช Well-Tested - 30+ unit and integration tests
- ๐ Fully Documented - Rustdoc with examples for all public APIs
- โก Zero Unsafe Code - Memory-safe and thread-safe
- Type-safe with no runtime overhead
- Efficient serialization/deserialization
- Follows Rust API guidelines
- Clippy-clean with no warnings
Add to your Cargo.toml:
[dependencies]
maec-rs = "0.1.0"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
chrono = "0.4"use maec::{Package, MalwareFamily, Behavior, Name, FieldData, Capability, BehaviorVocab};
use chrono::Utc;
fn main() -> maec::Result<()> {
// Create a behavior
let behavior = Behavior::builder()
.name(BehaviorVocab::CaptureKeyboardInput)
.description("Captures keyboard input for exfiltration")
.timestamp(Utc::now())
.build()?;
// Create a capability
let capability = Capability::builder()
.name("credential-theft")
.description("Steals user credentials")
.add_behavior_ref(behavior.id())
.build()?;
// Create a malware family
let family = MalwareFamily::builder()
.name(Name::new("AgentTesla"))
.description("Keylogger and information stealer")
.add_label("keylogger")
.add_label("infostealer")
.add_alias(Name::new("AgentTeslaV2"))
.add_capability(capability)
.field_data(
FieldData::builder()
.first_seen(Utc::now())
.add_delivery_vector("email")
.build()?
)
.build()?;
// Create a package
let package = Package::builder()
.add_malware_family(family)
.add_behavior(behavior)
.build()?;
// Serialize to JSON
let json = serde_json::to_string_pretty(&package)?;
println!("{}", json);
Ok(())
}use maec::{Package, MalwareFamily, Name};
// Load a package from JSON
let json_data = std::fs::read_to_string("malware_analysis.json")?;
let package: Package = serde_json::from_str(&json_data)?;
// Validate the package
package.validate()?;
// Query malware families
for family in package.malware_families() {
println!("Family: {}", family.name.value);
println!(" Labels: {:?}", family.labels);
println!(" Capabilities: {}", family.common_capabilities.len());
}
// Query behaviors
for behavior in package.behaviors() {
println!("Behavior: {}", behavior.name);
if let Some(desc) = &behavior.description {
println!(" Description: {}", desc);
}
}
// Access malware instances
for instance in package.malware_instances() {
println!("Instance ID: {}", instance.id);
println!(" Object refs: {:?}", instance.instance_object_refs);
}use maec::{MalwareInstance, Name, FieldData};
let instance = MalwareInstance::builder()
.add_instance_object_ref("file--12345678-1234-1234-1234-123456789abc")
.name(Name::new("sample.exe"))
.add_label("ransomware")
.description("WannaCry ransomware sample")
.field_data(
FieldData::builder()
.first_seen(Utc::now())
.add_delivery_vector("email-attachment")
.build()?
)
.build()?;
println!("Instance ID: {}", instance.id);use maec::{Behavior, ExternalReference, BehaviorVocab};
let behavior = Behavior::builder()
.name(BehaviorVocab::FileSystemInstantiation)
.description("Injects code into legitimate processes")
.add_technique_ref(
ExternalReference::attack_technique("T1055", "Process Injection")
)
.build()?;use maec::{
MalwareFamily, MalwareLabel, DeliveryVector, ProcessorArchitecture,
Name, FieldData,
};
use chrono::Utc;
// Type-safe malware labels
let family = MalwareFamily::builder()
.name(Name::new("WannaCry"))
.add_label(MalwareLabel::Ransomware.as_ref())
.add_label(MalwareLabel::Worm.as_ref())
.field_data(
FieldData::builder()
.first_seen(Utc::now())
.add_delivery_vector(DeliveryVector::EmailAttachment.as_ref())
.add_delivery_vector(DeliveryVector::ExploitKitLandingPage.as_ref())
.build()?
)
.build()?;
// Supported processor architectures
let architectures = vec![
ProcessorArchitecture::X86,
ProcessorArchitecture::X8664,
ProcessorArchitecture::Arm,
];Package - Top-level container for all MAEC data
let package = Package::builder()
.schema_version("5.0")
.add_malware_family(family)
.build()?;MalwareFamily - Related malware instances with common lineage
let family = MalwareFamily::builder()
.name(Name::new("Emotet"))
.add_label("trojan")
.add_label("banking")
.build()?;MalwareInstance - Individual malware sample
let instance = MalwareInstance::builder()
.add_instance_object_ref("file--uuid")
.name(Name::new("malware.exe"))
.build()?;Behavior - Specific purpose of malware code (e.g., keylogging)
use maec::BehaviorVocab;
let behavior = Behavior::builder()
.name(BehaviorVocab::CaptureKeyboardInput)
.description("Captures keyboard input")
.build()?;Capability - High-level malware capability (e.g., credential theft)
let capability = Capability::new("credential-theft");Type-Safe Enumerations for all MAEC open vocabularies:
MalwareLabel- ransomware, trojan, keylogger, rootkit, etc. (34 types)DeliveryVector- email-attachment, phishing, exploit-kit, etc. (17 vectors)ProcessorArchitecture- x86, x86-64, arm, mips, etc. (8 architectures)CapabilityVocab- anti-detection, data-theft, persistence, etc. (19 capabilities)AnalysisConclusionType- benign, malicious, suspicious, indeterminateAnalysisType- static, dynamic, combinationConfidenceMeasure- low, medium, high, none, unknownObfuscationMethod- packing, code-encryption, string-obfuscation, etc.CommonAttribute- Platform, protocol, vulnerability references, etc.MalwareConfigurationParameter- C2 addresses, mutex names, etc.OsFeature- Registry keys, services, hooks, WMI, etc.EntityAssociation- Relationship types between MAEC entities
Name - Malware name with optional source and confidence
let name = Name::with_source("WannaCry",
ExternalReference::new("Kaspersky"));FieldData - Temporal data and delivery vectors
let field_data = FieldData::builder()
.first_seen(Utc::now())
.add_delivery_vector("email")
.build()?;Relationship - Links between MAEC objects
let rel = Relationship::new(
"malware-instance--123",
"variant-of",
"malware-family--456"
);MAEC complements STIX by providing detailed malware analysis. Reference STIX Cyber Observable Objects:
use std::collections::HashMap;
let mut observables = HashMap::new();
observables.insert(
"file--12345".to_string(),
serde_json::json!({
"type": "file",
"name": "malware.exe",
"hashes": {
"MD5": "abc123...",
"SHA-256": "def456..."
}
})
);
let package = Package::builder()
.observable_objects(observables)
.build()?;The maec CLI provides format conversion and validation:
# Convert JSON to pretty JSON
maec to-json malware.json
# Convert JSON to XML (limited support)
maec to-xml malware.json
# Generate JSON Schema
maec schema > maec-package-schema.jsonSee the examples/ directory:
basic.rs- Creating and serializing MAEC packages- More examples coming soon!
Run examples:
cargo run --example basic# Run all tests
cargo test
# Run with output
cargo test -- --nocapture
# Run specific test
cargo test json_roundtrip
# Check formatting
cargo fmt --check
# Run clippy
cargo clippy -- -D warningsTest Coverage: 26+ tests passing (23 unit + 3 integration + vocabulary tests)
maec-rs/
โโโ src/
โ โโโ lib.rs # Public API & re-exports
โ โโโ common/ # CommonProperties, MaecObject trait, helpers
โ โโโ error.rs # MaecError types with thiserror
โ โโโ objects/ # MAEC object implementations
โ โ โโโ package.rs # Package with builder
โ โ โโโ malware_family.rs
โ โ โโโ malware_instance.rs
โ โ โโโ behavior.rs
โ โ โโโ capability.rs
โ โ โโโ types.rs # Name, FieldData
โ โ โโโ ...
โ โโโ bin/maec.rs # CLI tool
โโโ schemas/ # MAEC 5.0 JSON schemas (reference)
โโโ tests/ # Integration tests
โโโ examples/ # Usage examples
Part of the Threatwise threat intelligence ecosystem:
- stix-rs - STIX 2.1 implementation (complete, production-ready)
- taxii-rs - TAXII 2.1 server/client
- maec-rs - You are here!
- Core MAEC 5.0 objects (Package, MalwareFamily, MalwareInstance, Behavior, Capability)
- All MAEC 5.0 open vocabularies (12+ vocabulary enumerations)
- Builder pattern for all objects
- JSON serialization/deserialization
- JSON Schema generation
- Comprehensive error handling with thiserror
- ID generation and validation (UUID-based)
- CLI tool (to-json, to-xml, schema)
- Full documentation with examples
- 100% MAEC 5.0 Specification Compliance
- Additional object types (DynamicFeatures, StaticFeatures, AnalysisMetadata)
- Behavior vocabulary enum (190+ behaviors - currently use strings)
- MalwareAction vocabulary enum (210+ actions - currently use strings)
- Operating System vocabulary enum (110+ OS versions)
- Enhanced STIX integration helpers
- More examples and tutorials
- Query helpers and filtering APIs
- Validation against MAEC JSON schemas
- Bundle merging and deduplication
- Performance optimizations with rkyv
Contributions welcome! This project follows Rust API guidelines and maintains high code quality standards.
- Fork the repository
- Create a feature branch
- Make your changes with tests
- Run
cargo fmt && cargo clippy && cargo test - Submit a pull request
This project is licensed under either of:
- MIT License (LICENSE-MIT or http://opensource.org/licenses/MIT)
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
at your option.
- OASIS CTI Technical Committee - MAEC specification
- MITRE Corporation - MAEC project leadership
- Issues: GitHub Issues
- Documentation: docs.rs/maec-rs
- MAEC Specification: MAEC 5.0 Docs