interactsh 0.2.0

Async Rust client for polling out-of-band interaction servers.
Documentation
# interactsh

Async client for polling out-of-band interaction servers. Generate unique URLs, inject them into payloads, and correlate DNS/HTTP interactions back to the original probe. Used for detecting blind XSS, SSRF, SQL injection, and other vulnerabilities where the target makes outbound requests.

```rust
use interactsh::{InteractshClient, ClientConfig, InteractionContext};

#[tokio::main]
async fn main() -> interactsh::Result<()> {
    let client = InteractshClient::new(ClientConfig::default()).await?;
    
    // Generate a URL tagged with context
    let url = client.generate_url(
        InteractionContext::new("blind-xss")
            .with_attribute("target", "https://app.example.com")
    )?;
    
    println!("Payload URL: {}", url.url);
    
    // Poll for interactions
    let interactions = client.poll().await?;
    for interaction in interactions {
        println!("Got {} interaction from {:?}",
            interaction.event.protocol,
            interaction.context.label
        );
    }
    
    Ok(())
}
```

## Why this exists

Blind vulnerabilities require out-of-band detection. You inject a URL into a payload. If the target is vulnerable, it makes a request back to that URL. Most tools either lack OOB detection entirely or embed hardcoded interactsh logic that cannot be reused.

This crate provides an async client that handles URL generation with cryptographic nonces, correlation ID management, and interaction polling. It works with public interactsh servers or self-hosted instances.

## URL generation

Each generated URL contains:

- A correlation ID (configurable length, default 14 chars)
- A unique nonce (configurable length, default 16 chars)
- The server hostname

The combination ensures global uniqueness while letting you correlate interactions back to specific probes.

```rust
let url = client.generate_url(InteractionContext::new("probe-123"))?;
// URL format: {correlation_id}{nonce}.{server}
// Example: abc123def456ghi.oast.pro
```

## Context tracking

Attach metadata to URLs for later correlation:

```rust
let context = InteractionContext::new("ssrf-test")
    .with_attribute("template_id", "CVE-2021-44228")
    .with_attribute("target_host", "api.internal");

let url = client.generate_url(context)?;
```

When polling returns interactions, the context is restored from the nonce mapping.

## Polling

The `poll()` method retrieves all interactions for your correlation ID:

```rust
let interactions = client.poll().await?;
for item in interactions {
    println!("Protocol: {}", item.event.protocol);
    println!("Raw request: {:?}", item.event.raw_request);
    println!("Matched context: {}", item.context.label);
}
```

Unknown interactions (wrong correlation ID or forgotten nonces) are filtered out automatically.

## Configuration

```rust
use interactsh::ClientConfig;

let config = ClientConfig {
    server: "oast.fun".to_string(),
    token: Some("api-key".to_string()),
    correlation_id_length: 20,
    nonce_length: 12,
    ..ClientConfig::default()
};
```

Load from TOML:

```rust
let config = ClientConfig::from_toml_str(r#"
    server = "oast.fun"
    token = "secret-api-key"
    correlation_id_length = 16
"#)?;
```

## Error handling

Errors are typed by stage:

- `ConfigProblem::Empty` — Missing required fields
- `ConfigProblem::MustBeGreaterThanZero` — Invalid length settings
- `TransportStage::Send` — Network failure
- `TransportStage::Timeout` — Request timeout
- `TransportStage::ReadBody` — Response body read failure

## Self-hosted servers

Point at your own interactsh instance:

```rust
let config = ClientConfig {
    server: "oast.internal.corp".to_string(),
    default_scheme: "https".to_string(),
    ..ClientConfig::default()
};
```

## Contributing

Pull requests are welcome. There is no such thing as a perfect crate. If you find a bug, a better API, or just a rough edge, open a PR. We review quickly.

## License

MIT. Copyright 2026 CORUM COLLECTIVE LLC.

[![crates.io](https://img.shields.io/crates/v/interactsh.svg)](https://crates.io/crates/interactsh)
[![docs.rs](https://docs.rs/interactsh/badge.svg)](https://docs.rs/interactsh)