Skip to content
Merged
45 changes: 30 additions & 15 deletions bbot/modules/output/stdout.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import sys
import json

from bbot.logger import log_to_stderr
from bbot.modules.output.base import BaseOutputModule


Expand All @@ -15,12 +15,23 @@ class Stdout(BaseOutputModule):
"in_scope_only": "Whether to only show in-scope events",
"accept_dupes": "Whether to show duplicate events, default True",
}
vuln_severity_map = {
"INFO": "HUGEINFO",
"LOW": "HUGEWARNING",
"MEDIUM": "HUGEWARNING",
"HIGH": "CRITICAL",
"CRITICAL": "CRITICAL",
# base RGB hue per severity (matches the 🟦🟨🟧🟥🟪 convention from FINDING.severity_colors)
# all hues normalized so the brightest channel is 255 — gives a uniform brightness range per row
finding_severity_rgb = {
"INFO": (113, 161, 255), # blue
"LOW": (255, 215, 0), # yellow
"MEDIUM": (255, 135, 0), # orange
"HIGH": (255, 0, 0), # red
"CRITICAL": (207, 0, 255), # purple
}
# brightness multiplier per confidence — CONFIRMED also adds bold
# tuned so even UNKNOWN stays legible on dark terminals (brightest channel ~115)
finding_confidence_brightness = {
"CONFIRMED": 1.00,
"HIGH": 0.82,
"MEDIUM": 0.65,
"LOW": 0.55,
"UNKNOWN": 0.45,
}
format_choices = ["text", "json"]

Expand Down Expand Up @@ -61,16 +72,20 @@ async def handle_text(self, event, event_json):
else:
event_str = self.human_event_str(event)

# log findings in vivid colors based on severity
if event.type == "FINDING":
severity = event.data.get("severity", "INFO")
if severity in self.vuln_severity_map:
loglevel = self.vuln_severity_map[severity]
log_to_stderr(event_str, level=loglevel, logname=False)
else:
log_to_stderr(event_str, level="HUGEINFO", logname=False)
# color findings: severity picks the hue, confidence dims the brightness
if event.type == "FINDING" and isinstance(event.data, dict) and sys.stdout.isatty():
event_str = self._colorize_finding(event_str, event.data)

print(event_str)

def _colorize_finding(self, event_str, data):
Comment thread
ausmaster marked this conversation as resolved.
Resolved
severity = str(data.get("severity", "INFO")).upper()
confidence = str(data.get("confidence", "UNKNOWN")).upper()
r, g, b = self.finding_severity_rgb.get(severity, self.finding_severity_rgb["INFO"])
mult = self.finding_confidence_brightness.get(confidence, 0.65)
r, g, b = int(r * mult), int(g * mult), int(b * mult)
bold = "1;" if confidence == "CONFIRMED" else ""
return f"\033[{bold}38;2;{r};{g};{b}m{event_str}\033[0m"

async def handle_json(self, event, event_json):
print(json.dumps(event_json))
Loading