Modular Framework Architecture
[2.6.0] - 2026-04-16
Summary
Blue-Tap 2.6.0 is the Modular Framework release — every module now implements the Module protocol, produces typed RunEnvelope output, and is auto-registered in a global ModuleRegistry. The CLI was redesigned around the assessment workflow (discover → recon → vulnscan → exploit → extract → fuzz → report). The hardware layer gained a unified resolve_active_hci() resolver. The report pipeline is fully adapter-driven with per-family outcome validation enforced at call time.
Added — Module Protocol (framework/module)
Moduleabstract base class — definesrun(ctx: RunContext) → RunEnvelope;__init_subclass__hook auto-registers every subclass in the globalModuleRegistrywithout a manualModuleDescriptorblockRunContextdataclass — single typed argument toModule.run():target,adapter,options,session_id,dry_run; replaces ad-hoc kwargs scattered across entry points- Typed option descriptors —
OptAddress,OptPort,OptBool,OptInt,OptStr,OptChoice,OptFlag; each validates its value at resolution time and raisesValueErroron invalid input OptionsContainer— ordered dict ofOptioninstances; resolves CLI args + env-var overrides at invocation time beforeModule.run()is calledModuleInvoker— resolvesmodule_idfrom the registry, buildsRunContextfrom CLI params, callsModule.run(), and streamsCliEventsto the operator consoleModuleLoader— importsModuleclasses fromentry_pointstrings (package.module:Class); caches loaded classes to avoid repeated importsautoload.py— imports all family__init__.pyfiles so subclass auto-registration fires before the registry is queried for the first time
Added — Phase-Verb CLI Architecture (interfaces/cli)
discover—classic / ble / allsub-verbs wrappingDiscoveryScannerviaModuleInvoker; replaces the flatscancommand with an explicit workflow steprecon—sdp / rfcomm / gatt / hci-capture / sniffer / lmp-sniffsub-verbs consolidating the formerrecon+capturefamilies into one phase commandexploit— sub-commands:bias,bluffs,knob,ctkd,enc-downgrade,ssp-downgrade,hijack,pin-brute; grouped under Crypto/Key Attacks and Full Chainextract— sub-commands:contacts,messages,audio,media,push,snarf,at; covers all post-exploitation data paths in one placedos—BLE / Classic / Raw-ACLsub-commands forwarded to the DoS runner with protocol groupingfuzz—campaign+ 9 protocol sub-commands (sdp-deep,l2cap-sig,rfcomm-raw,ble-att,ble-smp,bnep,obex,at-deep,lmp) pluscrashes / minimize / replay / corpusanalysis commandsdoctor— hardware diagnostics: adapter list, DarkFirmware probe, USB dongle detection by VID:PID, HCI sanity checkauto— orchestrateddiscover → recon → vulnscan → exploitchain with--dry-runsupport and per-phase skip/abort handlingfleet— multi-target orchestration; per-target error isolation so one failure no longer aborts the full runrunner/plugins— genericblue-tap run <module_id>entry point;pluginslists registered modules and shows descriptor info_module_runner.py— single shared helper for all family CLIs: resolves module, buildsRunContext, streams events, writes session envelope
Added — Outcome Validation Taxonomy
VALID_OUTCOMES_BY_FAMILY(framework/contracts/result_schema.py) — per-familyfrozensetof allowedmodule_outcomevalues;make_execution()raisesValueErroron any unlisted value so bugs surface in tests not in production envelopes- Family outcome sets — discovery (
observed / merged / correlated / partial / not_applicable); assessment (confirmed / inconclusive / pairing_required / not_applicable / not_detected); exploitation (success / unresponsive / recovered / aborted / not_applicable); post_exploitation (extracted / connected / streamed / transferred / partial); fuzzing (crash_found / timeout / corpus_grown / no_findings / crash_detected / reproduced) _infer_family_from_module_id()— extracts the family prefix from<family>.<name>module IDs; unknown families skip validation for backward compatibility with pre-2.6 modules
Added — Registry Extensions
ModuleDescriptor.category— optional sub-family grouping field (e.g."pairing","l2cap","ble") for DoS and CVE check sub-classification within a familyModuleDescriptor.references—tuple[str, ...]of external references (CVEs, RFCs, specs) associated with the module; surfaced inblue-tap plugins info <module>outputModuleRegistry.try_get(module_id)— returnsModuleDescriptor | None; avoidsKeyErrorwhen probing for optional or plugin-provided modules
Added — Hardware Adapter Resolution
resolve_active_hci(explicit=None)(hardware/adapter.py) — priority-ordered HCI resolution: explicit arg →BT_TAP_DARKFIRMWARE_HCIenv var → RTL8761B USB VID:PID probe → first UP adapter fromhciconfig→"hci0"as last resort- Process-lifetime cache — result stored in
_ACTIVE_HCI_CACHEafter first hardware probe;reset_active_hci_cache()clears it on hot-plug or adapter-list refresh - RTL8761B identified by VID:PID (
0bda:8771) not HCI slot position — fixes false "DarkFirmware unavailable" in multi-adapter setups where the scan adapter ≠ firmware dongle
Added — Native Module Classes
CveCheckModule(modules/assessment/base.py) — wraps legacy check functions into theModuleprotocol; subclasses declarecheck_fnandmodule_idwithout duplicating envelope constructionVulnScanModule(modules/assessment/vulnscan_module.py) — thinModulesubclass delegating tovuln_scanner.run()and wrapping the result in a canonicalRunEnvelopeDiscoveryScanner(modules/discovery/scanner.py) —Moduleclass for Classic/BLE/combined scans; registered as"discovery.scanner"via auto-registration_e0.py(modules/exploitation/) — E0 encryption-mode downgrade probe helper shared byknob.pyandbias.pyDoSCheckModule(modules/exploitation/dos/base.py) — shared base for BLE / Classic / Raw-ACL DoS checks; handles timing evidence, recovery probe wiring, and envelope constructionFuzzCampaign(modules/fuzzing/campaign.py) —Modulewrapping the full engine lifecycle: seed corpus, run, collect crashes, finalizeRunEnvelope; supports campaign resume and crash exportReconCampaign(modules/reconnaissance/campaign.py) —Modulewrapping the multi-collector recon pipeline into a singleRunEnvelope; registered as"reconnaissance.campaign"
Added — Documentation Site (MkDocs)
mkdocs.yml— Material theme configuration with structured nav tree, light/dark mode, code block highlightsdocs/getting-started/— installation, hardware setup (single/dual adapter), quick start, IVI simulatordocs/guide/— per-phase operator guides: discovery, recon, vulnerability assessment, exploitation, DoS, fuzzing, post-exploitation, sessions and reporting, automationdocs/workflows/— end-to-end scenario walkthroughs: full pentest, quick assessment, fuzzing campaign, encryption downgrade, audio eavesdropping, custom playbooksdocs/developer/— architecture overview, module system, writing a module, report adapters, plugin entry-pointsdocs/reference/— hardware compatibility matrix, platform notes, troubleshooting referencedocs/cve/— CVE detection matrix, DoS CVE matrix, expansion roadmap; CVE specs moved from flatcve-detection-specs/→cve/specs/
Added — Testing
conftest.py— shared fixtures: mock adapter, target MAC, tmp session directory, registry reset between tests- 13
test_userflow_*.py— end-to-end operator workflow coverage: discover→recon→report, vulnscan fleet, BIAS, KNOB, DoS runner, fuzzing campaign, PBAP/OPP, A2DP/AVRCP, report generation, session resume, console output, playbook execution test_cli_facades.py— Click command registration smoke tests for every phase-verb subcommand; catches missing imports and mis-wired groupstest_outcome_validator.py—VALID_OUTCOMES_BY_FAMILYenforcement: valid outcomes pass, invalid ones raiseValueErrortest_module_runtime_e2e.py—Module.run()→RunEnveloperound-trip for one module per family; validates schema, run_id, and outcome fieldstest_hci_vsc_concurrency.py—HciVscClientconcurrent command safety under multi-thread accesstest_dos_migration.py— DoS adapter post-migration regression:accepts()family-prefix matching,ingest(), section output shape
Changed
- Report adapter
accepts()— all adapters match both legacy module name strings and modern"family.name"prefixes;DiscoveryReportAdapteradditionally accepts any"discovery.*"prefix - Envelope module label — renamed
"attack"→"exploitation"across all envelope builders to align with module family taxonomy - Session store — atomic JSON writes via write-to-temp +
os.replace(), correlation IDs on every operation, session-resume by name lookup, path configurable viaBT_TAP_SESSIONS_DIR - Module
__init__.pyfiles — all family__init__.pydropped manualModuleDescriptorblocks;__init_subclass__auto-registration handles all modules _check_darkfirmware_available()— identifies RTL8761B by USB VID:PID and readsBT_TAP_DARKFIRMWARE_HCIenv var; scan adapter no longer assumed to be the firmware dongle- All recon collectors — call
resolve_active_hci()instead of hardcoding"hci0"; structured WARNING-level logging on socket errors - All post-exploitation modules —
resolve_active_hci()used in PBAP/MAP/OPP/A2DP/AVRCP/HFP paths set_verbosity()— propagates to root logger so-v/-vvflags apply consistently across all modulesrun_cmd()— explicittimeout=on all subprocess calls; stderr captured to avoid dangling file descriptorsparse_sdp_records()— handles malformed XML with a logged warning instead of raisingParseErrorconfirm_destructive()— acceptsdry_runkwarg; logs the operator confirmation prompt to the audit log- Fleet scan — per-target errors captured in envelope without aborting the full run
vuln_scanner._run_hcitool_info()— callsresolve_active_hci()instead of defaulting to"hci0"- Report generator — accepts explicit session path; no module-specific logic remains in generator
output.py— addedchannel_table(),bare_table(),print_table()helpers; demo runner uses shared formatters- README — condensed to focused project summary with badge row and quick-start matching the phase-verb CLI
Fixed
clone_device_identitycallers —bias.py/hijack.pycheckedif not clone_device_identity(...)which evaluatedFalseafter bool→dict migration; fixed toresult.get("success", False)- Recon capture-stop —
HCICapture.stop()returns a path string; two copy-paste blocks called.get("success")on it raisingAttributeError - Recon lmp-sniff / nrf-sniff —
artifactsvariable referenced inbuild_recon_result()but never initialized;NameErroron every execution - L2CAP checks — two
_check_ecred_*functions had unreachablereturn []afterfinallyblocks; removed dead code preventing results from being returned btmgmt public-addrerrors — handled safely instead of crashing the adapter command- DoS result/report normalization — aligned DoS result dict keys with report adapter field expectations
- HFP reconnect socket leak — socket closed in
finallyblock during reconnection - RAM BDADDR patching — corrected controller memory write sequence for RTL8761B
Removed
- Deprecated top-level packages —
blue_tap/attack/,blue_tap/cli.py,blue_tap/core/,blue_tap/fuzz/,blue_tap/recon/,blue_tap/report/(all were deprecation-notice stubs with no active consumers) - Auto envelope builder —
framework/envelopes/auto.py; auto-pentest uses phase-verb CLI with per-phase family envelopes - Auto report adapter —
framework/reporting/adapters/auto.pyremoved alongside the auto envelope AutoPentestmodule —modules/exploitation/auto.pyretired; superseded byblue-tap autoCLI command- Flat family CLI files —
interfaces/cli/assessment.py,discovery.py,exploitation.py,fuzzing.py,post_exploitation.py,reconnaissance.pyreplaced by phase-verb commands - Retired test files —
test_auto_envelope.py,test_cli_events_coverage.py,test_cli_startup_bootstrap.py,test_discovery_regressions.py,test_media_data_regressions.py,test_recon_revamp.py; replaced by userflow tests