| Crates.io | kalamari |
| lib.rs | kalamari |
| version | 0.0.2 |
| created_at | 2026-01-14 14:36:37.27607+00 |
| updated_at | 2026-01-14 20:05:43.409849+00 |
| description | Lightweight headless browser for security testing. Fast, pure Rust, no Chrome. |
| homepage | https://bountyy.fi |
| repository | https://github.com/bountyyfi/kalamari |
| max_upload_size | |
| id | 2042932 |
| size | 580,341 |
Lightweight Headless Browser for Security Testing
Features | Installation | Quick Start | API Reference | Lonkero Integration
Kalamari is a pure Rust headless browser designed specifically for XSS scanning, web crawling, and security testing. Unlike traditional headless browsers that require Chrome/Chromium binaries (~200MB+), Kalamari is entirely self-contained with minimal dependencies.
Built as a drop-in replacement for Chrome headless in security scanners like Lonkero.
Kalamari addresses all key integration requirements for Lonkero:
| Feature | Chrome-based | Kalamari |
|---|---|---|
| Binary size | ~200MB | ~10MB |
| Memory/page | ~100-300MB | ~10-20MB |
| Startup time | 1-3s | Instant |
| XSS detection | External | Built-in |
| Request interception | CDP Fetch | RequestInterceptor trait |
| Iframe support | Native | Recursive processing |
| MutationObserver | Native | JS stub |
| PDF generation | Native | Feature-gated |
| Auth session | Manual | AuthSession extractor |
| SPA routes | Manual | ScriptAnalyzer |
| WebSocket discovery | Manual | ScriptAnalyzer |
| Timer control | Native | TimerQueue |
| CSP analysis | Manual | CspAnalyzer |
| Parallel scanning | Thread pool | BrowserPool |
Add to your Cargo.toml:
[dependencies]
kalamari = "0.1"
# With optional features
kalamari = { version = "0.1", features = ["pdf", "websocket"] }
Or install the CLI:
cargo install kalamari
use kalamari::{Browser, BrowserConfig, PageConfig};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let browser = Browser::launch().await?;
let page = browser.new_page().await?;
page.navigate("https://example.com").await?;
println!("Title: {:?}", page.title());
for link in page.links() {
println!("Link: {}", link);
}
Ok(())
}
use kalamari::{Browser, PageConfig, XssTriggerType};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let browser = Browser::for_security_scanning().await?;
let page = browser.new_page_with_config(PageConfig::for_xss_scanning()).await?;
page.navigate("https://target.com/search?q=<script>alert(1)</script>").await?;
let result = page.analyze_xss();
for trigger in result.triggers {
if trigger.is_confirmed() {
println!("CONFIRMED XSS: {:?} - {}", trigger.trigger_type, trigger.payload);
}
}
Ok(())
}
use kalamari::{StoredXssTest, StoredXssTester};
let test = StoredXssTest::new("https://example.com/post", "<script>alert(1)</script>")
.field("comment")
.reflect_at("https://example.com/posts")
.reflect_at("https://example.com/profile");
let tester = StoredXssTester::new();
// Execute test via page methods
use kalamari::{CspAnalyzer, CspBypass};
let analyzer = CspAnalyzer::new();
let csp = "default-src 'self'; script-src 'self' 'unsafe-inline'";
let analysis = analyzer.parse(csp);
println!("Security Score: {}/100", analysis.security_score);
println!("Blocks inline: {}", analysis.blocks_inline);
for bypass in &analysis.bypasses {
println!("Bypass: {:?} - {}", bypass, bypass.description());
}
use kalamari::BrowserPool;
use std::sync::Arc;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let pool = BrowserPool::new(8).await?; // 8 browsers
let urls = vec![
"https://example.com/page1".to_string(),
"https://example.com/page2".to_string(),
"https://example.com/page3".to_string(),
];
let results = pool.map(&urls, |page, url| async move {
page.navigate(&url).await?;
Ok(page.analyze_xss())
}).await;
for result in results {
if let Ok(xss) = result {
if xss.is_vulnerable() {
println!("XSS found!");
}
}
}
Ok(())
}
use kalamari::{Browser, RequestInterceptor, InterceptAction, AuthHeaderInjector};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let browser = Browser::launch().await?;
// Use built-in auth injector
let auth = AuthHeaderInjector::new()
.bearer_token("your-jwt-token")
.header("x-api-key", "secret");
// Or set directly on browser
browser.set_auth_token("your-jwt-token");
Ok(())
}
use kalamari::{Browser, AuthSession};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let browser = Browser::launch().await?;
let page = browser.new_page().await?;
page.navigate("https://example.com/login").await?;
// ... perform login ...
let session = page.extract_auth_session();
println!("Session ID: {:?}", session.session_id);
println!("Bearer Token: {:?}", session.bearer_token);
println!("CSRF Token: {:?}", session.csrf_token);
println!("Authenticated: {}", session.is_authenticated);
Ok(())
}
use kalamari::{ScriptAnalyzer, ScriptSource};
let analyzer = ScriptAnalyzer::new();
let scripts = page.get_script_sources();
for script in &scripts {
// Find routes
let routes = analyzer.find_routes(script);
for route in routes {
println!("Route: {} (auth: {})", route.path, route.requires_auth);
}
// Find WebSocket endpoints
let ws_endpoints = analyzer.find_websocket_endpoints(script);
for endpoint in ws_endpoints {
println!("WebSocket: {}", endpoint.url);
}
}
use kalamari::FrameworkDetector;
let detector = FrameworkDetector::new();
let html = page.content()?;
let scripts = page.get_script_sources();
let script_contents: Vec<String> = scripts.iter().map(|s| s.content.clone()).collect();
let frameworks = detector.detect_all(&html, &script_contents);
for fw in frameworks {
println!("Framework: {:?} {:?}", fw.framework, fw.version);
for sink in fw.sinks {
println!(" Sink: {} (risk: {})", sink.name, sink.risk);
}
}
# Fetch a URL and display info
kalamari fetch https://example.com
# Check for XSS vulnerabilities
kalamari xss "https://example.com/search?q=<script>alert(1)</script>"
# Crawl a website
kalamari crawl https://example.com
# Extract forms
kalamari forms https://example.com/login
┌──────────────────────────────────────────────────────────────┐
│ KALAMARI BROWSER │
├──────────────────────────────────────────────────────────────┤
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────┐ │
│ │ HTTP Layer │ │ DOM Engine │ │ JS Runtime │ │
│ │ (reqwest) │──│ (html5ever) │──│ (boa_engine) │ │
│ └──────────────┘ └──────────────┘ └──────────────────┘ │
│ │ │ │ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────┐ │
│ │ Interceptor │ │ Iframe │ │ XSS Detection │ │
│ │ Chain │ │ Handler │ │ (alert hooks) │ │
│ └──────────────┘ └──────────────┘ └──────────────────┘ │
│ │ │ │ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────┐ │
│ │ Cookie │ │ Form │ │ Security │ │
│ │ Jar │ │ Extractor │ │ (CSP, SRI) │ │
│ └──────────────┘ └──────────────┘ └──────────────────┘ │
└──────────────────────────────────────────────────────────────┘
| Type | Description |
|---|---|
Browser |
Main browser instance |
Page |
Individual page/tab |
BrowserPool |
Pool for parallel scanning |
BrowserMetrics |
Performance metrics |
| Type | Description |
|---|---|
CspAnalyzer |
CSP parsing and bypass detection |
SriChecker |
Subresource integrity validation |
DomClobberDetector |
DOM clobbering detection |
| Type | Description |
|---|---|
XssDetector |
XSS trigger detection |
StoredXssTest |
Stored XSS test configuration |
PayloadGenerator |
XSS payload generation |
| Type | Description |
|---|---|
RequestInterceptor |
Request/response middleware |
NetworkEvent |
Captured network events |
AuthHeaderInjector |
Auth header injection |
| Feature | Description | Dependencies |
|---|---|---|
default |
Core functionality | None |
websocket |
WebSocket support | tokio-tungstenite |
pdf |
PDF generation (pure Rust) | printpdf |
full |
All features | All above |
| Crate | Purpose |
|---|---|
boa_engine |
JavaScript execution (pure Rust) |
html5ever |
HTML parsing (spec-compliant) |
reqwest |
HTTP client (rustls TLS) |
tokio |
Async runtime |
Kalamari is optimized for security testing, not full browser emulation:
flush_timers() or execute_ready_timers() to executeCopyright (c) 2026 Bountyy Oy. All rights reserved.
This software is licensed under the Bountyy Oy Source-Available License. You may view, study, and use the software for personal, non-commercial purposes. Commercial use requires a separate license agreement.
See LICENSE for full terms. For licensing inquiries: info@bountyy.fi