| Crates.io | derusted |
| lib.rs | derusted |
| version | 0.2.0 |
| created_at | 2025-11-27 13:01:36.442732+00 |
| updated_at | 2025-12-01 10:42:19.919643+00 |
| description | Programmable HTTPS interception and traffic inspection engine for security-critical applications |
| homepage | https://github.com/kumarimlab/derusted |
| repository | https://github.com/kumarimlab/derusted |
| max_upload_size | |
| id | 1953708 |
| size | 929,529 |
Production-ready Rust library for HTTPS MITM proxy with enterprise-grade security
Derusted is a high-performance forward proxy library built in Rust for HTTPS traffic inspection via dynamic TLS certificate generation. Built for safety, security, and developer experience.
Version: 0.2.0 | Status: โ Production Ready
โ ๏ธ v0.2.0 Breaking Changes: If upgrading from v0.1.x, see Migration Guide below.
[EMAIL REDACTED][CC REDACTED][SSN REDACTED][PHONE REDACTED][TOKEN REDACTED][API_KEY REDACTED]unsafe blocks)network-tests feature)Add Derusted to your Cargo.toml:
[dependencies]
derusted = "0.1.0"
Or use the latest from GitHub:
[dependencies]
derusted = { git = "https://github.com/your-org/derusted", tag = "v0.1.0" }
# Generate CA private key (4096-bit RSA)
openssl genrsa -out ca-key.pem 4096
# Generate CA certificate (valid for 10 years)
openssl req -new -x509 -days 3650 \
-key ca-key.pem \
-out ca-cert.pem \
-subj "/C=US/ST=CA/L=SF/O=YourOrg/OU=IT/CN=YourOrg MITM CA"
# Set environment variables
export CA_CERT=$(cat ca-cert.pem)
export CA_KEY=$(cat ca-key.pem)
use derusted::mitm::{CaKeyManager, CertificateAuthority, MitmInterceptor};
use std::sync::Arc;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Initialize CA from environment variables
let ca_manager = CaKeyManager::from_env("CA_CERT", "CA_KEY").await?;
// Create certificate authority with default config
let cert_authority = CertificateAuthority::new(ca_manager);
// Create MITM interceptor
let interceptor = Arc::new(MitmInterceptor::new(cert_authority));
// Use interceptor to handle TLS connections
// interceptor.intercept(client_stream, target_host, target_port).await?;
Ok(())
}
use derusted::mitm::CaKeyManager;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Load CA from Vault
let ca_manager = CaKeyManager::from_vault(
"http://vault.example.com:8200",
"s.YourVaultToken",
"secret/data/mitm/ca"
).await?;
// Use ca_manager as before...
Ok(())
}
use derusted::mitm::CaKeyManager;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Load CA from KMS
let ca_manager = CaKeyManager::from_kms(
"us-east-1",
"alias/mitm-ca-key",
"arn:aws:s3:::your-bucket/ca-cert.pem"
).await?;
Ok(())
}
use derusted::mitm::MitmInterceptor;
use std::time::Duration;
// Enable automatic bypass for pinned domains
let interceptor = MitmInterceptor::with_pinning(
cert_authority,
3, // max failures before bypass
Duration::from_secs(300), // bypass duration: 5 minutes
);
Built over 8 weeks with clear separation of concerns:
derusted/
โโโ src/
โ โโโ lib.rs # Public API exports
โ โโโ mitm/
โ โ โโโ ca_key_manager.rs # CA key management (Week 1)
โ โ โโโ certificate_authority.rs # Certificate generation + caching (Week 1)
โ โ โโโ interceptor.rs # MITM decision engine (Week 2-3, 6)
โ โ โโโ tls_config.rs # TLS configuration (Week 1)
โ โ โโโ logging.rs # PII redaction (Week 4)
โ โ โโโ log_storage.rs # SQLite storage (Week 4)
โ โ โโโ bypass.rs # Smart bypass system (Week 5)
โ โ โโโ pinning.rs # Pinning detection (Week 5)
โ โ โโโ http_parser.rs # HTTP/1.1 parsing (Week 2-3)
โ โ โโโ http2_mitm.rs # HTTP/2 MITM (Week 6)
โ โ โโโ error.rs # Error types
โ โโโ connection_pool.rs # Connection pooling (Week 7)
โ โโโ destination_filter.rs # SSRF protection
โ โโโ ...
โ
โโโ docs/
โ โโโ SECURITY_AUDIT.md # Complete security audit (Week 8)
โ โโโ THREAT_MODEL.md # Threat analysis (Week 8)
โ โโโ CA_ROTATION.md # Rotation procedures (Week 8)
โ โโโ CI_CD_NOTE.md # CI/CD decision (Week 8)
โ
โโโ pdocs/ # Weekly development summaries
โ โโโ WEEK1_FINAL_SUMMARY.md
โ โโโ WEEK2_SUMMARY.md
โ โโโ WEEK3_SUMMARY.md
โ โโโ WEEK4_FINAL_SUMMARY.md
โ โโโ WEEK5_SUMMARY.md
โ โโโ WEEK6_SUMMARY.md
โ โโโ WEEK7_SUMMARY.md
โ โโโ WEEK8_PLAN.md
โ
โโโ tests/
โโโ (150 passing tests)
Run the full test suite:
# Default: 148/152 tests pass (DNS tests excluded)
cargo test --lib
# With network tests enabled: 150/152 tests pass (requires DNS)
cargo test --lib --features network-tests
# With output
cargo test --lib -- --nocapture
# Specific module
cargo test --lib mitm::logging::tests
Note: By default, 148/152 tests pass. Two DNS-dependent tests (destination_filter::tests::test_allow_public_domain and test_dns_caching) are gated behind the network-tests feature flag to ensure compatibility with restricted/sandboxed environments. Enable them with --features network-tests to run all 150/152 tests (2 remain ignored).
Run security checks:
# Clippy lints
cargo clippy --all-targets -- -D warnings
# Security audit (requires cargo-audit)
cargo audit
# Format check
cargo fmt --all -- --check
Test Coverage: 150 tests covering:
| Optimization | Expected Impact | Status |
|---|---|---|
| Connection Pooling | +20-30% throughput | โ Implemented |
| Certificate Cache TTL | Bounded memory <50MB | โ Implemented |
| TLS Handshake Savings | 150-300ms per pooled connection | โ Implemented |
| Latency (p99) | <500ms for cached connections | โ Target met |
use derusted::connection_pool::{ConnectionPool, PoolConfig};
let config = PoolConfig {
max_idle_per_host: 10, // Max idle connections per host
idle_timeout: Duration::from_secs(90), // 90-second idle timeout
max_lifetime: Duration::from_secs(600), // 10-minute max lifetime
connection_timeout: Duration::from_secs(30),
};
let pool = ConnectionPool::with_config(config);
Overall Assessment: โ APPROVED FOR v0.1.0 RELEASE
| Category | Status | Details |
|---|---|---|
| CA Private Key | โ PASS | No logging, proper memory protection |
| PII Redaction | โ PASS | 6 patterns, 13 unit tests |
| Error Messages | โ PASS | No sensitive data exposure |
| Memory Safety | โ PASS | No unsafe blocks |
| Input Validation | โ PASS | SSRF protection, hostname validation |
| Dependencies | โ ๏ธ CONDITIONAL PASS | 6 CVEs, all non-blocking |
6 CVEs found, all assessed as non-blocking for v0.1.0:
Action Items for v0.2.0:
See docs/SECURITY_AUDIT.md for complete details.
Comprehensive documentation created during Week 8:
v0.2.0 introduces extensible JWT claims, which requires minor code changes.
Before (v0.1.x):
let claims = JwtClaims {
token_id: "...".to_string(),
user_id: 42,
allowed_regions: vec!["us-east".to_string()],
exp: ...,
iat: ...,
iss: Some("...".to_string()),
aud: Some("...".to_string()),
};
After (v0.2.0) - Recommended: Use constructor
// Simple, clean, backwards-compatible
let claims = JwtClaims::new(
"...".to_string(), // token_id
42, // user_id
vec!["us-east".to_string()], // allowed_regions
exp, // expiration
iat, // issued_at
Some("...".to_string()), // issuer
Some("...".to_string()), // audience
);
After (v0.2.0) - Alternative: Add extra field
let claims = JwtClaims {
token_id: "...".to_string(),
user_id: 42,
// ... other fields ...
extra: (), // โ Add this line
};
If you see type inference errors, add explicit type annotation:
// Before: let validator = JwtValidator::new(...)?;
// After:
let validator: JwtValidator<()> = JwtValidator::new(...)?;
Derusted is designed as a foundation library. These patterns follow industry standards from Envoy, goproxy, and mitmproxy.
Extend JwtClaims with application-specific fields:
use derusted::{JwtClaims, JwtValidator};
use serde::Deserialize;
// 1. Define your custom claims
#[derive(Debug, Clone, Default, Deserialize)]
struct SaasCustomClaims {
tier: Option<String>, // "free", "pro", "enterprise"
rate_limit_per_hour: Option<usize>,
features: Vec<String>,
}
// 2. Create validator for extended claims
let validator: JwtValidator<SaasCustomClaims> = JwtValidator::new(
secret.to_string(),
"HS256".to_string(),
"us-east".to_string(),
None,
None,
)?;
// 3. Validate and access custom fields
let claims = validator.validate(&format!("Bearer {}", token))?;
println!("Tier: {:?}", claims.extra.tier);
println!("Rate limit: {:?}", claims.extra.rate_limit_per_hour);
// 4. Create tokens with custom claims
let claims = JwtClaims::with_extra(
"token_123".to_string(),
42,
vec!["us-east".to_string()],
exp, iat, iss, aud,
SaasCustomClaims {
tier: Some("pro".to_string()),
rate_limit_per_hour: Some(10000),
features: vec!["advanced_routing".to_string()],
},
);
See examples/custom_auth.rs for a complete example.
Override rate limits per-request based on user tier:
use derusted::{RateLimiter, RateLimiterConfig};
let config = RateLimiterConfig {
requests_per_minute: 100, // Default (free tier)
burst_size: 20,
bucket_ttl_seconds: 3600,
max_buckets: 100_000,
};
let limiter = RateLimiter::new(config);
// Free tier: use default
limiter.check_limit("free_user_token").await?;
// Pro tier: 10,000 req/min
limiter.check_limit_with_override("pro_user_token", Some(10_000)).await?;
// Enterprise: 100,000 req/min
limiter.check_limit_with_override("enterprise_token", Some(100_000)).await?;
See examples/tiered_rate_limits.rs for a complete example.
Extend Config with custom fields using the Deref pattern:
use std::ops::Deref;
use derusted::Config;
// Your extended config
pub struct MyAppConfig {
base: Config,
pub custom_logger: Arc<MyLogger>,
pub feature_flags: FeatureFlags,
}
// Implement Deref for transparent access
impl Deref for MyAppConfig {
type Target = Config;
fn deref(&self) -> &Self::Target {
&self.base
}
}
// Now you can access both
config.destination_filter // derusted field (via Deref)
config.custom_logger // your custom field
See examples/custom_config.rs for a complete example.
Contributions are welcome! See CONTRIBUTING.md for guidelines.
git checkout -b feature/amazing-feature)cargo test --all
cargo clippy --all-targets -- -D warnings
cargo fmt --all
cargo audit
git commit -m 'Add amazing feature')git push origin feature/amazing-feature)See CHANGELOG.md for detailed version history.
Initial open source release after 8 weeks of development:
Core Features:
Known Limitations:
Licensed under the MIT License.
MIT License
Copyright (c) 2025 Kumar AS
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
See LICENSE for full details.
The following CVEs exist in indirect dependencies and are documented for transparency. None are blocking for v0.1.0 release:
| Dependency | Version | Advisory | Severity | Status | Notes |
|---|---|---|---|---|---|
| hpack | 0.3.0 | RUSTSEC-2024-0003 | CRITICAL | โ Unfixed | No patched version available. Tracked for v0.2.0 |
| h2 | 0.3.27 (indirect) | Unknown | Unknown | โ ๏ธ Old version | Newer h2 0.4.12 also in tree. Review needed |
| protobuf | 2.28.0 | RUSTSEC-2021-0073 | HIGH | โ Unfixed | Via pprof (dev-dependency). Low risk |
| idna | 0.2.x | Multiple | MEDIUM | โ Unfixed | Indirect dependency |
| ring | Various | Various | MEDIUM | โ Unfixed | Indirect dependency |
| rsa | Various | Various | MEDIUM | โ Unfixed | Indirect dependency |
| trust-dns-resolver | Old | Deprecated | LOW | โ ๏ธ Migration needed | Should migrate to hickory-dns in v0.2.0 |
Fixed in v0.1.0:
Impact Assessment: These CVEs are in HTTP/2 parsing, TLS, and DNS resolution libraries. The proxy operates in a trusted internal network environment where these risks are mitigated by network segmentation and access controls. Full remediation planned for v0.2.0.
Recommendations:
cargo audit regularly for new advisoriesTwo tests require network access and may fail in sandboxed CI environments:
destination_filter::tests::test_allow_public_domaindestination_filter::tests::test_dns_cachingThese tests perform actual DNS resolution to example.com. In restricted environments without DNS access, they will fail with "Operation not permitted". This does not indicate a bug in the library.
Solutions:
docker-compose upFor complete test results, see TEST_STATUS.md.
Built on the shoulders of giants:
Special thanks to the Rust community.
Built with โค๏ธ in Rust
Developed by the Pinaka Engineering Team | 8-week development cycle | November 2025