NOTE: This is an early-access preview of BBOT Server. Basic features are documented below. Expect updates as development progresses, including blog posts and documentation describing the full range of features.
BBOT Server is a database and multiplayer hub for all your BBOT activities!
- Asset Tracking and Alerting
- Get detailed history for each individual asset
- Instantly alert on new vulnerabilities, open ports, etc.
- Scan Management
- Kick off concurrent scans on remote servers
- Monitor scan progress, statistics
- Collaboration
- Multi-user CLI
- Multiple concurrent scans
- Advanced Querying
- REST API
- Python SDK
- Export to JSON/CSV
- AI interaction via MCP
# clone the repo and cd into it
git clone [email protected]:blacklanternsecurity/bbot-server.git && cd bbot-server
# Install in editable mode
pipx install -e .Note: to update to the latest version, run git pull in the bbot-server directory.
Note: this requires Docker and Docker Compose to be installed.
# Start BBOT server using Docker Compose
bbctl server startBy default, BBOT Server listens on localhost. Use --listen to expose it to the network:
bbctl server start --listen 0.0.0.0The first time you start BBOT Server, an API key will be auto generated and put into ~/.config/bbot_server/config.yml:
# ~/.config/bbot_server/config.yml
# list of API keys to be considered valid
api_keys:
- deadbeef-9b4d-4208-890c-4ce9ad3b4710The api_keys value in config.yml is used by both the server (as a database of valid API keys), and by the client (it will pick one from the list and use it). Normally it just works and you don't have to mess with it. But to access BBOT Server remotely, you'll need to copy the API key from the server onto your local system, along with its URL:
# ~/.config/bbot_server/config.yml
url: http://1.2.3.4:8807/v1/
api_keys:
- deadbeef-9b4d-4208-890c-4ce9ad3b4710This tells bbctl (the client) where the server is, and gives it the means to authenticate.
To utilise the API key and interact with the BBOT Server via the HTTP API, set the X-API-Key HTTP header to the value of a valid API key.
BBOT Server can be configured via environment variables, which is useful for Docker deployments or CI/CD pipelines. The configuration uses a nested structure with double underscores (__) as delimiters.
All environment variables use the prefix BBOT_SERVER_.
# Server URL
export BBOT_SERVER_URL="http://localhost:8807/v1/"
# Authentication
export BBOT_SERVER_AUTH_ENABLED=true
export BBOT_SERVER_AUTH_HEADER="X-API-Key"
export BBOT_SERVER_API_KEY="deadbeef-9b4d-4208-890c-4ce9ad3b4710"
# Database URIs (nested configs)
export BBOT_SERVER_EVENT_STORE__URI="mongodb://localhost:27017/bbot_server"
export BBOT_SERVER_ASSET_STORE__URI="mongodb://localhost:27017/bbot_server"
export BBOT_SERVER_USER_STORE__URI="mongodb://localhost:27017/bbot_server"
# Message Queue URI
export BBOT_SERVER_MESSAGE_QUEUE__URI="redis://localhost:6379/0"
# Agent configuration
export BBOT_SERVER_AGENT__BASE_PRESET='{"modules": ["nmap"]}'
# CLI configuration
export BBOT_SERVER_CLI__HTTP_TIMEOUT=90
# Module-specific configuration (double-nested)
export BBOT_SERVER_MODULES__SOME_MODULE__SOME_OPTION="value"Note the double underscores (__) used to access nested configuration fields. This is required by the Pydantic settings framework.
API keys can be added and removed if you are on the server machine:
# add an API key
bbctl server apikey add
# list API keys
bbctl server apikey list
# revoke an API key
bbctl server apikey delete deadbeef-9b4d-4208-890c-4ce9ad3b4710You can output a BBOT scan directly to BBOT server with the following preset:
# bbot-server.yml
output_modules:
- http
config:
modules:
http:
# URL of BBOT Server
url: http://localhost:8807/v1/events/
# API Key header
headers:
x-api-key: deadbeef-9b4d-4208-890c-4ce9ad3b4710Note that this requires BBOT 3.0 or later (install with pipx install git+https://github.com/blacklanternsecurity/[email protected])
# Start a BBOT scan, sending output to BBOT server
bbot -t evilcorp.com -p subdomain-enum ./bbot-server.ymlIf you forgot to output a scan to BBOT server, you can easily ingest it after the fact:
# Ingest events from a past scan
cat ~/.bbot/scans/demonic_jimmy/output.json | bbctl event ingestTo start a scan in BBOT server, you need to first create a Preset and Target.
-
Create Preset
The preset defines which flags, modules, API keys, etc. will be used for the scan. It typically looks something like this:
my_preset.yml:include: - subdomain-enum - cloud-enum - code-enum modules: - nuclei config: modules: virustotal: api_key: deadbeef
# create a new scan preset bbctl scan preset create my_preset.ymlFor more guidance and examples on presets, check out the bbot docs.
-
Create Target
A target defines what's in-scope for the scan. They can also be used when filtering assets.
# create a new scan target bbctl scan target create --seeds evilcorp.txt --name "my_target"
-
Start Scan
Now that we've created a preset and target, we can start the scan:
# start the scan bbctl scan start --preset my_preset --target my_target --name "demonic_jimmy"
You can monitor the scan's progress in several ways:
This will output an activity whenever a change is detected to an asset, e.g. a change in DNS, new open port, vulnerability, or technology.
# Monitor changes to assets as they are discovered
bbctl activity tailIf you'd like, you can also tail the raw events as they stream in from the BBOT scan.
# Monitor raw BBOT events
bbctl event tailYou can monitor or stop an in-progress scan:
# List scan runs
bbctl scan list
# Stop the scan
bbctl scan cancel "demonic_jimmy"BBOT server categorizes its assets by target.
You can list targets like so:
# List targets
bbctl scan target list
# Create a new target
bbctl scan target create --seeds seeds.txt --blacklist blacklist.txt --name custom_target
# List only the assets that match your new target
bbctl asset list --target custom_targetYou can kick off a custom command or bash script whenever a certain activity happens, such as when a new technology or open port is discovered.
# Trigger a custom command whenever a new open port is discovered
bbctl activity tail --json | jq -r 'select(.type == "PORT_OPENED") | .netloc' | while read netloc
do
echo "New open port at $netloc"
./custom_script.sh "$netloc"
doneTODO
You can query and export the data even while a scan is running.
# List assets
bbctl asset list
# Export assets to CSV
bbctl asset list --csv > assets.csv
# Export assets as JSON
bbctl asset list --json | jq# List events
bbctl event list
# Export events to CSV
bbctl event list --csv > events.csv
# Export events as JSON
bbctl event list --json | jq# List technologies
bbctl technology list
# List technologies by specific domain
bbctl technology list --domain evilcorp.com# List findings
bbctl finding list
# Search findings for a certain string
bbctl finding list --search "IIS"Overarching statistics are stored for all assets, and can be queried by target or domain.
# List stats for all assets
bbctl asset stats | jq
# List stats for specific domain
bbctl asset stats --domain evilcorp.com | jqBBOT Server supports chat-based AI interaction via MCP (Model Context Protocol).
The SSE server listens at http://localhost:8807/v1/mcp/.
mcp.json (Cursor / VS Code):
{
"mcpServers": {
"bbot": {
"url": "http://localhost:8807/v1/mcp/",
"headers": {
"x-api-key": "deadbeef-9b4d-4208-890c-4ce9ad3b4710"
}
}
}
}After connecting your AI client to BBOT Server, you can ask it sensible questions like, "Use MCP to get all the bbot findings", "what are the top open ports?", "what else can you do with BBOT MCP?", etc.
NOTE: Authentication is currently broken in Cursor, Cline, and it seems most other VS Code forks. A workaround is to disable authentication with --no-authentication when starting the server. Obviously, be careful with this and don't be a dumbass.
bbctl server start --no-authenticationYou can interact fully with BBOT Server as a Python library. It supports either local or remote connections, and the interface to both is identical:
import asyncio
from bbot_server import BBOTServer
async def main():
# talk directly to local MongoDB + Redis
bbot_server = BBOTServer(interface="python")
# or to a remote BBOT Server instance (config must contain a valid API key)
bbot_server = BBOTServer(interface="http", url="http://bbot:8807/v1/")
# one-time setup
await bbot_server.setup()
hosts = await bbot_server.get_hosts()
print(f"hosts: {hosts}")
if __name__ == "__main__":
asyncio.run(main())from bbot_server import BBOTServer
if __name__ == "__main__":
# talk directly to local MongoDB + Redis
bbot_server = BBOTServer(interface="python", synchronous=True)
# or to a remote BBOT Server instance (config must contain a valid API key)
bbot_server = BBOTServer(interface="http", url="http://bbot:8807/v1/", synchronous=True)
# one-time setup
bbot_server.setup()
hosts = bbot_server.get_hosts()
print(f"hosts: {hosts}")When running tests, first start MongoDB and Redis via Docker:
docker run --ulimit nofile=64000:64000 --rm -p 27017:27017 mongo
docker run --rm -p 6379:6379 redisThen execute pytest:
# run all tests
poetry run pytest -v
# run specific tests
poetry run pytest -v -k test_applet_scansTailing activities in real time
AI Chat interaction via MCP
Scans
Technologies
Findings
REST API
Connect to the default URL at http://localhost:8807 to view and use the interactive API documentation.






