# attackstr
Grammar-driven security payload generation for scanners, fuzzers, and taint-aware tooling.
`attackstr` loads TOML grammars, expands contexts and variables deterministically, applies built-in or custom encodings, and returns payloads with source metadata. It is designed for crates.io use, not just the wider Santh workspace.
## Features
- TOML grammar loading from strings or directories
- Configurable include/exclude/runtime filtering
- Built-in encoding transforms plus custom encoders
- Marker injection for taint-tracking payloads
- Streaming iterator API with `iter_payloads`
- Serde support across payload/config/grammar types
- Mutation helpers for lightweight evasive variants
## Installation
```toml
[dependencies]
attackstr = "0.1"
```
## Quick Start
```rust
use attackstr::{PayloadConfig, PayloadDb};
let mut db = PayloadDb::with_config(
PayloadConfig::builder()
.max_per_category(16)
.deduplicate(true)
.build(),
);
db.load_toml(
r#"
[grammar]
name = "basic-xss"
sink_category = "xss"
[[contexts]]
name = "quoted-attr"
prefix = "\""
suffix = "\""
[[techniques]]
name = "svg-onload"
template = "<svg/onload={handler}>"
[[handlers]]
value = "alert(1)"
value = "confirm(1)"
[[encodings]]
name = "raw"
transform = "identity"
"#,
)?;
let payloads = db.payloads("xss");
assert_eq!(payloads.len(), 2);
assert!(payloads[0].text.contains("<svg/onload="));
# Ok::<(), attackstr::PayloadError>(())
```
## Grammar Format
Each grammar defines:
- `[grammar]` metadata
- `[[contexts]]` for prefix/suffix breakout wrappers
- `[[techniques]]` for templates
- `[[encodings]]` for final transforms
- `[[variables]]`-style arrays for substitution sets
Example:
```toml
[grammar]
name = "sql-basic"
sink_category = "sql-injection"
description = "Foundational SQLi payloads"
target_runtime = ["php", "node"]
[[contexts]]
name = "single-quoted"
prefix = "'"
suffix = "-- "
[[techniques]]
name = "boolean-tautology"
template = "{prefix} OR {tautology} {suffix}"
confidence = 0.95
expected_pattern = "(?i)sql|syntax|mysql"
[[tautologies]]
value = "1=1"
value = "'a'='a'"
[[encodings]]
name = "raw"
transform = "identity"
[[encodings]]
name = "url"
transform = "url_encode"
```
## Iterator APIs
Use cached category access when you want slices:
```rust
use attackstr::PayloadDb;
let mut db = PayloadDb::new();
db.load_toml(
r#"
[grammar]
name = "demo"
sink_category = "cmdi"
[[techniques]]
name = "ping"
template = "; ping -c 1 {host}"
[[hosts]]
value = "127.0.0.1"
"#,
)?;
let payloads = db.payloads("cmdi");
assert_eq!(payloads.len(), 1);
# Ok::<(), attackstr::PayloadError>(())
```
Use streaming iteration when you want to avoid materializing the whole category:
```rust
use attackstr::PayloadDb;
let mut db = PayloadDb::new();
db.load_toml(
r#"
[grammar]
name = "streaming"
sink_category = "xss"
[[techniques]]
name = "basic"
template = "<script>{call}</script>"
[[calls]]
value = "alert(1)"
value = "confirm(1)"
"#,
)?;
```rust
use attackstr::PayloadDb;
let mut db = PayloadDb::new();
db.register_encoding("reverse", |input| input.chars().rev().collect());
db.load_toml(
r#"
[grammar]
name = "custom-encoding"
sink_category = "demo"
[[techniques]]
name = "one"
template = "abc"
[[encodings]]
name = "reversed"
transform = "reverse"
"#,
)?;
assert_eq!(db.payloads("demo")[0].text, "cba");
# Ok::<(), attackstr::PayloadError>(())
```
## Examples
Run the bundled examples:
```bash
cargo run --example basic
cargo run --example toml_config
```
## Development
- `cargo fmt`
- `cargo check`
- `cargo test`
Contribution workflow is documented in [CONTRIBUTING.md](./CONTRIBUTING.md).
## License
MIT