# stix-rs
[](https://www.rust-lang.org)
[](LICENSE)
**A complete, production-ready Rust implementation of STIX 2.1 (Structured Threat Information Expression)**
`stix-rs` provides full support for creating, parsing, and manipulating STIX 2.1 cyber threat intelligence data. Built for performance and type safety, it's ready for use in threat intelligence platforms, TAXII servers, and security tools.
---
## Features
### **100% STIX 2.1 Compliant**
- ✅ **All 18 STIX Domain Objects (SDOs)** - Malware, Indicator, ThreatActor, Campaign, etc.
- ✅ **All 17 Cyber Observable Objects (SCOs)** - File, Network Traffic, Process, etc.
- ✅ **All Relationship Objects (SROs)** - Relationship, Sighting
- ✅ **All Meta Objects** - Bundle, Marking Definition, Language Content, etc.
- ✅ **17 Vocabulary Enums** - Complete type-safe enumerations
### **Production-Ready Features**
- 🔍 **Bundle Query Helpers** - Powerful search and filter APIs
- ✅ **ID Validation** - Prevent invalid STIX references
- 📡 **MIME Type Constants** - Standard HTTP/TAXII content types
- 🔄 **Object Versioning** - Proper STIX object update handling
- 🎨 **Pattern Validation** - STIX pattern language syntax checking
- 📦 **Builder Pattern** - Ergonomic object construction
### 🛡️ **Type-Safe & Fast**
- Full Rust type safety with no runtime overhead
- Comprehensive error handling with `thiserror`
- Efficient serialization/deserialization with `serde`
- Zero-copy parsing where possible
---
## Installation
Add to your `Cargo.toml`:
```toml
[dependencies]
stix-rs = "0.1.0"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
chrono = "0.4"
```
---
## Quick Start
### Creating STIX Objects
```rust
use stix_rs::*;
use chrono::Utc;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create a Malware object
let malware = Malware::builder()
.name("Poison Ivy")
.description("Advanced persistent threat RAT")
.malware_types(vec!["remote-access-trojan".into()])
.is_family(true)
.aliases(vec!["PIVY".into()])
.first_seen(Utc::now())
.build()?;
// Create an Indicator
let indicator = Indicator::builder()
.name("Malicious domain")
.pattern("[domain-name:value = 'evil.com']")
.pattern_type(IndicatorPatternType::Stix)
.valid_from(Utc::now())
.validate_pattern(true) // Enable pattern validation
.build()?;
// Create a Bundle
let bundle = Bundle::new(vec![
malware.into(),
indicator.into(),
]);
// Serialize to JSON
let json = serde_json::to_string_pretty(&bundle)?;
println!("{}", json);
Ok(())
}
```
### Working with Bundles
```rust
use stix_rs::*;
// Load a bundle from JSON
let bundle: Bundle = serde_json::from_str(&json_data)?;
// Query by type
let all_malware = bundle.malware();
let all_indicators = bundle.indicators();
let all_threats = bundle.threat_actors();
// Find by ID
if let Some(obj) = bundle.get("malware--abc-123") {
println!("Found: {}", obj.type_());
}
// Filter generically
let identities = bundle.filter_by_type("identity");
// Count objects
println!("Total malware: {}", bundle.count_by_type("malware"));
println!("Object types: {:?}", bundle.object_types());
// Find references
let refs = bundle.find_references_to("malware--abc-123");
// Iterate
for obj in bundle.iter() {
println!("{}: {}", obj.type_(), obj.id());
}
```
### Common Properties & Marking
```rust
use stix_rs::*;
let mut malware = Malware::builder()
.name("BadWare")
.malware_types(vec!["trojan".into()])
.build()?;
// Add common properties
malware.common.labels = Some(vec!["apt".into(), "targeted".into()]);
malware.common.confidence = Some(95);
malware.common.lang = Some("en".into());
// Add external references (CVE, ATT&CK)
malware.common.external_references = Some(vec![
ExternalReference::builder()
.source_name("mitre-attack")
.external_id("S0020")
.url("https://attack.mitre.org/software/S0020/")
.build()?,
]);
// Add TLP marking
let tlp_red = MarkingDefinition::tlp("red");
malware.common.object_marking_refs = Some(vec![tlp_red.id().to_string()]);
```
### Pattern Validation
```rust
use stix_rs::pattern::{validate_pattern, PatternBuilder};
// Validate patterns
validate_pattern("[file:hashes.MD5 = 'abc123']")?;
validate_pattern("[ipv4-addr:value = '192.168.1.1']")?;
// Build patterns programmatically
let pattern = PatternBuilder::new()
.compare("file", "name", "=", "'malware.exe'")
.and()
.compare("file", "size", ">", "1000")
.build();
println!("{}", pattern);
// Output: [file:name = 'malware.exe' AND file:size > 1000]
```
### ID Validation
```rust
use stix_rs::*;
// Validate STIX IDs
assert!(is_valid_stix_id("malware--550e8400-e29b-41d4-a716-446655440000"));
assert!(!is_valid_stix_id("invalid-id"));
// Extract type from ID
let obj_type = extract_type_from_id("malware--abc-123");
assert_eq!(obj_type, Some("malware"));
// Validate reference types
assert!(is_valid_ref_for_type(
"malware--abc-123",
"malware"
));
```
### Object Versioning
```rust
use stix_rs::*;
let mut threat_actor = ThreatActor::builder()
.name("APT28")
.threat_actor_types(vec!["nation-state".into()])
.build()?;
// Make updates
threat_actor.description = Some("Also known as Fancy Bear".into());
// Create new version (updates modified timestamp, preserves ID)
threat_actor.common.new_version();
```
---
## 🌐 HTTP/TAXII Integration
### MIME Type Constants
```rust
use stix_rs::*;
// Use standard STIX/TAXII MIME types
println!("{}", MEDIA_TYPE_STIX); // application/stix+json;version=2.1
println!("{}", MEDIA_TYPE_TAXII); // application/taxii+json;version=2.1
```
### Example TAXII Server (Axum)
```rust
use axum::{Router, routing::get, Json, http::StatusCode};
use stix_rs::*;
async fn get_objects() -> (StatusCode, [(String, String); 1], Json<Bundle>) {
let bundle = load_threat_intel();
(
StatusCode::OK,
[("Content-Type".to_string(), MEDIA_TYPE_STIX.to_string())],
Json(bundle)
)
}
#[tokio::main]
async fn main() {
let app = Router::new()
.route("/collections/1/objects/", get(get_objects));
// ... serve
}
```
---
## Complete Object Support
### Domain Objects (SDOs)
| Attack Pattern | ✅ | ✅ | Complete |
| Campaign | ✅ | ✅ | Complete |
| Course of Action | ✅ | ✅ | Complete |
| Grouping | ✅ | ✅ | Complete |
| Identity | ✅ | ✅ | Complete |
| Incident | ✅ | ✅ | Complete |
| Indicator | ✅ | ✅ | Complete + Validation |
| Infrastructure | ✅ | ✅ | Complete |
| Intrusion Set | ✅ | ✅ | Complete |
| Location | ✅ | ✅ | Complete |
| Malware | ✅ | ✅ | Complete + Extended |
| Malware Analysis | ✅ | ✅ | Complete |
| Note | ✅ | ✅ | Complete |
| Observed Data | ✅ | ✅ | Complete |
| Opinion | ✅ | ✅ | Complete |
| Report | ✅ | ✅ | Complete |
| Threat Actor | ✅ | ✅ | Complete |
| Tool | ✅ | ✅ | Complete |
| Vulnerability | ✅ | ✅ | Complete |
### Cyber Observables (SCOs)
| Artifact | ✅ |
| Autonomous System | ✅ |
| Directory | ✅ |
| Domain Name | ✅ |
| Email Address | ✅ |
| Email Message | ✅ |
| File | ✅ |
| IPv4 Address | ✅ |
| IPv6 Address | ✅ |
| MAC Address | ✅ |
| Mutex | ✅ |
| Network Traffic | ✅ |
| Process | ✅ |
| Software | ✅ |
| URL | ✅ |
| User Account | ✅ |
| Windows Registry Key | ✅ |
| X.509 Certificate | ✅ |
### Relationship Objects (SROs)
| Relationship | ✅ |
| Sighting | ✅ |
### Meta Objects
| Bundle | ✅ + Query Helpers |
| Marking Definition | ✅ + TLP Support |
| Language Content | ✅ |
| Extension Definition | ✅ |
| External Reference | ✅ + Builder |
| Granular Marking | ✅ |
---
## Vocabulary Enums
All STIX 2.1 open vocabularies are implemented as type-safe enums:
- `MalwareType` - ransomware, trojan, backdoor, etc. (20 types)
- `ThreatActorType` - nation-state, criminal, hacktivist, etc. (12 types)
- `ThreatActorRole` - director, agent, sponsor, etc. (5 roles)
- `ThreatActorSophistication` - minimal, intermediate, advanced, etc. (7 levels)
- `AttackMotivation` - ideology, dominance, personal-gain, etc. (10 types)
- `AttackResourceLevel` - individual, club, organization, government (6 levels)
- `ToolType` - exploitation, remote-access, etc. (8 types)
- `InfrastructureType` - command-and-control, botnet, etc. (11 types)
- `ReportType` - threat-report, attack-pattern, etc. (11 types)
- `IndustrySector` - financial, healthcare, government, etc. (40+ sectors)
- `IndicatorType` - malicious-activity, anomalous-activity, etc.
- `ImplementationLanguage` - Python, C++, JavaScript, etc. (20+ languages)
- `IndicatorPatternType` - stix, pcre, snort, yara, suricata
- `IdentityClass` - individual, group, organization, system
- `HashAlgorithm` - MD5, SHA-1, SHA-256, SHA-512
- `RelationshipType` - targets, uses, indicates, etc.
- `EncryptionAlgorithm` - AES-256-GCM, ChaCha20-Poly1305
---
## 🧪 Testing
```bash
# Run all tests
cargo test
# Run with output
cargo test -- --nocapture
# Run specific test
cargo test bundle_query
# Check for compilation issues
cargo check
# Build release
cargo build --release
```
**Test Coverage:** 78 tests passing (57 unit + 21 integration/doc tests)
---
## Documentation
- **[Official STIX 2.1 Spec](https://docs.oasis-open.org/cti/stix/v2.1/os/stix-v2.1-os.html)** - OASIS specification
- **[STIX 2.1 Examples](https://oasis-open.github.io/cti-documentation/stix/examples.html)** - Official examples
### Generate API Docs
```bash
cargo doc --open
```
---
## Use Cases
### Threat Intelligence Platforms
Query and analyze threat data with type-safe APIs:
```rust
let apt_malware: Vec<_> = bundle.malware()
.iter()
.filter(|m| m.name.contains("APT"))
.collect();
```
### TAXII 2.1 Servers
Serve STIX bundles with proper MIME types:
```rust
response.header("Content-Type", MEDIA_TYPE_STIX);
```
### Security Orchestration (SOAR)
Parse and create STIX indicators programmatically:
```rust
let indicator = Indicator::builder()
.pattern(pattern)
.valid_from(Utc::now())
.build()?;
```
### Threat Feed Aggregators
Merge multiple STIX feeds efficiently:
```rust
let mut combined = Bundle::new(vec![]);
combined.objects.extend(feed1.objects);
combined.objects.extend(feed2.objects);
```
### Intelligence Sharing
Exchange standardized threat intelligence:
```rust
let bundle = Bundle::new(vec![
malware.into(),
threat_actor.into(),
relationship.into(),
]);
```
---
## Advanced Features
### Custom Properties
```rust
let identity = Identity::builder()
.name("ACME Corp")
.class(IdentityClass::Organization)
.property("x_industry", "financial")
.property("x_priority", 5)
.build()?;
```
### Extensions
```rust
let extension = ExtensionDefinition::builder()
.name("my-extension")
.version("1.0.0")
.schema("https://example.com/schema.json")
.extension_types(vec!["property-extension".into()])
.build()?;
```
### Granular Markings
```rust
malware.common.granular_markings = Some(vec![
GranularMarking {
marking_ref: Some("marking-definition--tlp-red".into()),
selectors: vec!["name".into(), "description".into()],
lang: None,
}
]);
```
---
### Development
```bash
# Clone the repository
git clone https://github.com/yourusername/stix-rs
cd stix-rs
# Run tests
cargo test
# Check formatting
cargo fmt --check
# Run clippy
cargo clippy
# Build docs
cargo doc --open
```
---
## 📝 License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
---
## Acknowledgments
- [OASIS CTI Technical Committee](https://www.oasis-open.org/committees/tc_home.php?wg_abbrev=cti) - STIX specification