Configuration
BlackRainbow engagements are defined in YAML config files. The config is parsed by load_config() and validated by 7 Pydantic models. Every field is type-checked at load time.
Config File
Default filename: blackrainbow.yaml. Override with br run --config <path>.
Generate from a template:
br init --template htb # Creates blackrainbow.yaml
br init --template webapp # Web application template
Complete Example
target:
type: network-service
host: 10.10.10.5
label: htb-example
port: 80
protocol: tcp
url: http://10.10.10.5
scope:
networks:
- 10.10.10.0/24
exclude:
- 10.10.10.1
engagement:
purpose: |
Full compromise of target host. Obtain root-level access.
Capture user.txt and root.txt flags as proof.
rules:
- No denial of service
- No data destruction
- No attacking out-of-scope hosts
operator: pitl0rd
plugins:
- recon
- id: credential-access
numTests: 10
severity: high
config:
wordlist: /usr/share/wordlists/rockyou.txt
strategies:
- sequential
model:
provider: ollama
model: blackrainbow-v0
host: http://localhost:11434
temperature: 0.3
output:
report: ./reports/
capture: ./captures/
format: markdown
training_export: true
Top-Level Keys
| Key | Type | Required | Description |
|---|---|---|---|
target | Object | Yes | Target definition |
engagement | Object | Yes | Engagement metadata |
plugins | List | No | Plugin references |
strategies | List | No | Strategy IDs |
frameworks | List | No | Framework references (e.g., MITRE ATT&CK) |
model | Object | No | AI model configuration |
output | Object | No | Output and capture settings |
Pydantic Models
Seven models validate the config. All use strict type checking.
BlackRainbowConfig
The root model. Contains all other models.
class BlackRainbowConfig(BaseModel):
target: TargetConfig
engagement: EngagementConfig
plugins: List[PluginRefConfig] = []
strategies: List[str] = []
frameworks: List[str] = []
model: Optional[ModelConfig] = None
output: OutputConfig = Field(default_factory=OutputConfig)
TargetConfig
| Field | Type | Default | Description |
|---|---|---|---|
type | str | "network-service" | Target type (validated against allowed set) |
host | str | (required) | Target hostname or IP |
label | str | None | Human-readable label for reports |
port | int | None | Specific port |
protocol | str | None | Protocol (e.g., tcp, udp) |
url | str | None | Full URL (for web targets) |
scope | ScopeConfig | {} | Network scope constraints |
Allowed type values:
network-serviceweb-applicationactive-directorycloud-serviceai-systemninjatocustom
ScopeConfig
| Field | Type | Default | Description |
|---|---|---|---|
networks | List[str] | [] | In-scope CIDRs |
exclude | List[str] | [] | Excluded hosts/CIDRs |
EngagementConfig
| Field | Type | Default | Description |
|---|---|---|---|
purpose | str | (required) | Engagement objective |
rules | List[str] | [] | Rules of engagement |
operator | str | "unknown" | Operator name |
PluginRefConfig
Supports two forms in YAML. Both are normalized to the same model at parse time.
Short form (string):
plugins:
- recon
Normalizes to {"id": "recon"}.
Long form (dict):
plugins:
- id: recon
numTests: 10
severity: high
config:
scan_type: full
| Field | Type | Default | Description |
|---|---|---|---|
id | str | (required) | Plugin ID from registry |
numTests | int | 5 | Number of test sequences to generate |
severity | str | "medium" | Minimum severity level |
config | Dict[str, Any] | {} | Plugin-specific configuration |
File references are also accepted as IDs:
plugins:
- file://./my-plugin.py
ModelConfig
| Field | Type | Default | Description |
|---|---|---|---|
provider | str | "ollama" | Model provider |
model | str | "blackrainbow-v0" | Model name |
host | str | "http://localhost:11434" | Provider API endpoint |
temperature | float | 0.3 | Inference temperature |
OutputConfig
| Field | Type | Default | Description |
|---|---|---|---|
report | str | "./reports/" | Report output directory |
capture | str | "./captures/" | Capture output directory |
format | str | "markdown" | Output format (validated) |
training_export | bool | true | Export results as training data |
Allowed format values:
markdownjsonhtmlpdf
Template System
Templates live in templates/ at the repo root. The br init command copies a template to the working directory.
htb.yaml
HackTheBox / CTF template. Target type network-service. Includes scope for 10.10.10.0/24, recon plugin, and Ollama model config. All target-specific fields use CHANGEME placeholders.
webapp.yaml
Web application assessment template. Target type web-application. Includes a url field, recon plugin, and a web-exploit plugin reference (long form with severity override). Rules include restrictions on automated credential stuffing.
Adding Templates
Create a new YAML file in templates/:
# templates/ad.yaml
target:
type: active-directory
host: CHANGEME
label: ad-TARGET
scope:
networks:
- CHANGEME/24
exclude: []
engagement:
purpose: |
Active Directory domain compromise assessment.
Demonstrate full kill chain from initial access to domain admin.
rules:
- No denial of service
- No data destruction
operator: CHANGEME
plugins:
- recon
- id: credential-access
severity: high
strategies: []
output:
report: ./reports/
capture: ./captures/
format: markdown
training_export: true
Then add the template name to the --template Click choice in cli.py:
@click.option(
"--template",
type=click.Choice(["htb", "webapp", "ad"]),
default="htb",
)
Config Loading
load_config(path) handles the full parse chain:
- Read the YAML file.
- Validate it is a non-empty mapping.
- Normalize plugin references (string to dict).
- Construct and return
BlackRainbowConfig(Pydantic validates all fields).
Errors:
FileNotFoundError: config file does not exist.ValueError: YAML is empty, not a mapping, or fails Pydantic validation.
Config to Context
config_to_context(config) converts a validated config into an EngagementContext for plugin consumption:
EngagementContext(
target=config.target.model_dump(),
purpose=config.engagement.purpose,
scope=config.target.scope.model_dump(),
strategies=[s for s in config.strategies],
)
This is the bridge between static config and runtime state. The engine adds previous_results, discovered_services, credentials, and model as the engagement progresses.