Skip to content
Merged
Show file tree
Hide file tree
Changes from 39 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
969076f
Standardize preset naming, flag system, and event tags (#2959)
liquidsec Mar 23, 2026
0a7b629
Merge 3.0, fix stale flag/preset references in docs and tests
liquidsec Mar 23, 2026
ec6dd40
Add http_title field to pydantic and SQL event models
liquidsec Mar 23, 2026
e653c58
Fix azure_tenant crash on non-existent source_domain attribute
liquidsec Mar 23, 2026
7ed18cc
Add source_domain to event __slots__, restore in azure_tenant
liquidsec Mar 24, 2026
f940a64
Add unified .url property to BaseEvent, migrate all modules
liquidsec Mar 24, 2026
bc06f14
Rename noisy→loud, restore safe flag with test enforcement
liquidsec Mar 24, 2026
022876f
Improve lightfuzz preset descriptions with detailed feature tables
liquidsec Mar 24, 2026
48da875
Add host_metadata field, scope down BaseEvent __slots__ to subclasses
liquidsec Mar 24, 2026
78bd657
Make URL_UNVERIFIED inherit from DictHostEvent, data is now a dict
liquidsec Mar 24, 2026
5a75eb8
Migrate remaining modules from event.data to event.url for URL events
liquidsec Mar 24, 2026
f561bda
Migrate cloudcheck to host_metadata, simplify cloud tags
liquidsec Mar 24, 2026
c0e6759
Fix baddns_direct: check for cloudflare tag directly
liquidsec Mar 24, 2026
42b3cae
Update context strings and test assertions for URL dict data
liquidsec Mar 24, 2026
99ae4e1
Fix remaining test failures from URL dict migration
liquidsec Mar 24, 2026
7906990
Fix speculate passing URL dict to url_parents
liquidsec Mar 24, 2026
eca3e94
ruff format
liquidsec Mar 24, 2026
97cb6b7
Update tests for URL dict data and simplified cloud tags
liquidsec Mar 24, 2026
6dae4d2
Reclassify portscan and iis_shortnames as loud
liquidsec Mar 24, 2026
0a5051d
Fix test assertions for URL dict data and event_data lists
liquidsec Mar 24, 2026
3501f3a
Fix more test assertions: e.data -> e.url/e.pretty_string for URL events
liquidsec Mar 24, 2026
2db2eaf
Merge 3.0, resolve conflicts in retirejs and gowitness
liquidsec Mar 24, 2026
09f61de
Fix EventSeed url property, more test assertion fixes
liquidsec Mar 24, 2026
0a371a7
Fix remaining event.data references in modules and tests
liquidsec Mar 25, 2026
7863798
Fix bucket template filter and remaining test data references
liquidsec Mar 25, 2026
2f05546
Fix oauth event.data references for URL dict migration
liquidsec Mar 25, 2026
6a7971d
Move http_title and status_code into URL data dict
liquidsec Mar 25, 2026
624ee9e
Regenerate docs for portscan/iis_shortnames loud reclassification
liquidsec Mar 25, 2026
0c99434
Add test_host_metadata covering serialization, URL data dict, http_ti…
liquidsec Mar 25, 2026
7a33ad9
Add host_metadata structure assertions to cloudcheck test
liquidsec Mar 25, 2026
c13ed88
Fix speculate emitting duplicate URL_UNVERIFIEDs from URL dict events
liquidsec Mar 25, 2026
feadca4
Fix test_exclude_cdn: add cdn type tag alongside provider name
liquidsec Mar 25, 2026
96f34d1
Fix code_repository and social modules for DictHostEvent URL events
liquidsec Mar 25, 2026
7989ace
Fix DictHostEvent breakage in ffuf_shortnames and test monkeypatches
liquidsec Mar 25, 2026
79aac59
Fix trufflehog test: patch clone_git_repository instead of mutating e…
liquidsec Mar 25, 2026
9f6fbd8
Fix Docker-based test hangs: close pymongo client, await docker stop
liquidsec Mar 25, 2026
957c0c1
Cancel orphaned async tasks in test fixture teardown, fix portscan te…
liquidsec Mar 25, 2026
005f047
Fix kafka test hang: use auto_offset_reset=earliest and add timeout
liquidsec Mar 26, 2026
4cce566
remove source domain event attr
TheTechromancer Mar 26, 2026
3650dcc
Restore safe flag assertions in preset tests
liquidsec Mar 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 9 additions & 7 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ from bbot.modules.base import BaseModule
class my_module(BaseModule):
watched_events = ["DNS_NAME"]
produced_events = ["EMAIL_ADDRESS"]
flags = ["passive", "safe", "email-enum"]
flags = ["passive", "email-enum"]
meta = {
"description": "Query example.com for email addresses",
"created_date": "2025-01-01",
Expand Down Expand Up @@ -275,21 +275,23 @@ produced_events = ["OPEN_TCP_PORT"]
```

##### `flags` (list)
Tags that describe the module's behavior. Must include at least one safety flag (`safe` or `aggressive`) and one activity flag (`passive` or `active`).
Tags that describe the module's behavior. Must include at least one activity flag (`passive` or `active`). Must also include `safe`, `loud`, or `invasive` (or a combination of `loud` and `invasive`).

Common flags:
- `passive` / `active` - whether the module touches the target directly
- `safe` / `aggressive` - risk level
- `safe` - non-intrusive and non-destructive
- `loud` - generates a large amount of network traffic
- `invasive` - intrusive or potentially destructive
- `subdomain-enum` - participates in subdomain enumeration
- `web-basic` - basic web scanning
- `web` - basic web scanning
- `email-enum` - email discovery

```python
# crt.py - queries a third-party API, never touches the target
flags = ["subdomain-enum", "passive", "safe"]
flags = ["subdomain-enum", "passive"]

# sslcert.py - connects directly to target ports
flags = ["affiliates", "subdomain-enum", "email-enum", "active", "safe", "web-basic"]
flags = ["affiliates", "subdomain-enum", "email-enum", "active", "web"]
```

##### `meta` (dict)
Expand Down Expand Up @@ -797,7 +799,7 @@ from bbot.modules.templates.subdomain_enum import subdomain_enum


class crt(subdomain_enum):
flags = ["subdomain-enum", "passive", "safe"]
flags = ["subdomain-enum", "passive"]
watched_events = ["DNS_NAME"]
produced_events = ["DNS_NAME"]
meta = {
Expand Down
30 changes: 15 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,16 +144,16 @@ output_modules:

```bash
# run a light web scan against www.evilcorp.com
bbot -t www.evilcorp.com -p web-basic
bbot -t www.evilcorp.com -p web

# run a heavy web scan against www.evilcorp.com
bbot -t www.evilcorp.com -p web-thorough
bbot -t www.evilcorp.com -p web-heavy
```

<!-- BBOT WEB-BASIC PRESET EXPANDABLE -->
<!-- BBOT WEB PRESET EXPANDABLE -->

<details>
<summary><b><code>web-basic.yml</code></b></summary>
<summary><b><code>web.yml</code></b></summary>

```yaml
description: Quick web scan
Expand All @@ -162,43 +162,43 @@ include:
- iis-shortnames

flags:
- web-basic
- web

```

</details>

<!-- END BBOT WEB-BASIC PRESET EXPANDABLE -->
<!-- END BBOT WEB PRESET EXPANDABLE -->

<!-- BBOT WEB-THOROUGH PRESET EXPANDABLE -->
<!-- BBOT WEB-HEAVY PRESET EXPANDABLE -->

<details>
<summary><b><code>web-thorough.yml</code></b></summary>
<summary><b><code>web-heavy.yml</code></b></summary>

```yaml
description: Aggressive web scan

include:
# include the web-basic preset
- web-basic
# include the web preset
- web

flags:
- web-thorough
- web-heavy

```

</details>

<!-- END BBOT WEB-THOROUGH PRESET EXPANDABLE -->
<!-- END BBOT WEB-HEAVY PRESET EXPANDABLE -->

### 5) Everything Everywhere All at Once

```bash
# everything everywhere all at once
bbot -t evilcorp.com -p kitchen-sink --allow-deadly
bbot -t evilcorp.com -p kitchen-sink

# roughly equivalent to:
bbot -t evilcorp.com -p subdomain-enum cloud-enum code-enum email-enum spider web-basic paramminer dirbust-light web-screenshots --allow-deadly
bbot -t evilcorp.com -p subdomain-enum cloud-enum code-enum email-enum spider web paramminer dirbust-light web-screenshots
```

<!-- BBOT KITCHEN-SINK PRESET EXPANDABLE -->
Expand All @@ -215,7 +215,7 @@ include:
- code-enum
- email-enum
- spider
- web-basic
- web
- paramminer
- dirbust-light
- web-screenshots
Expand Down
28 changes: 18 additions & 10 deletions bbot/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,16 +168,6 @@ async def _main():
sys.exit(0)
return

# deadly modules (no scan required yet)
deadly_modules = [
m for m in baked_preset.scan_modules if "deadly" in baked_preset.preloaded_module(m).get("flags", [])
]
if deadly_modules and not options.allow_deadly:
log.hugewarning(f"You enabled the following deadly modules: {','.join(deadly_modules)}")
log.hugewarning("Deadly modules are highly intrusive")
log.hugewarning("Please specify --allow-deadly to continue")
return False

try:
scan = Scanner(preset=baked_preset)
except (PresetAbortError, ValidationError) as e:
Expand Down Expand Up @@ -241,6 +231,24 @@ async def _main():
f'YOUR TARGET CONTAINS A CLOUD DOMAIN: "{event.host}". You\'re in for a wild ride!'
)

# warn about loud/invasive modules
loud_modules = []
invasive_modules = []
for m in scan.preset.scan_modules:
flags = scan.preset.preloaded_module(m).get("flags", [])
if "loud" in flags:
loud_modules.append(m)
if "invasive" in flags:
invasive_modules.append(m)
if loud_modules:
log.hugewarning(
f"LOUD modules enabled: {','.join(loud_modules)}. These generate a lot of traffic. To exclude, use -ef loud"
)
if invasive_modules:
log.hugewarning(
f"INVASIVE modules enabled: {','.join(invasive_modules)}. These may be intrusive or destructive. To exclude, use -ef invasive"
)

if not options.yes:
log.hugesuccess(f"Scan ready. Press enter to execute {scan.name}")
input()
Expand Down
Loading
Loading