Development and architecture
Advanced Module Development
When to write a module?
- Internal detection missing from
search. - Proprietary API to test repeatedly.
- Integration of an in-house tool into
agentandcampaign. - Reusable module for an authorized test environment.
In most engagements, search + scanner + agent are sufficient.
Writing a module has a maintenance cost: tests, documentation, version compatibility.
Module anatomy
Class and inheritance
from core.framework.base_module import BaseModule, ModuleResult
from core.framework.scanner import Scanner # for an HTTP scanner
class Module(Scanner):
__info__ = { ... }
rhost = OptString(...)
def run(self): ...
def check(self): ... # optional
Common categories: BaseModule, Scanner, Exploit, Auxiliary,
Post, Payload.
__info__ metadata
__info__ = {
"name": "HTTP header detection",
"description": "Observe an authorized HTTP response.",
"author": "Your Team",
"references": ["https://owasp.org/"],
"tags": ["http", "headers"],
"cve": ["CVE-2026-00000"], # if applicable
"reliability": "high",
"agent": {
"risk": "read",
"effects": ["network_probe"],
"expected_requests": 1,
"reversible": True,
"approval_required": False,
"produces": ["technology_fingerprint"],
},
"attack": {
"tactics": ["TA0007"],
"techniques": ["T1046"],
"prerequisites": ["HTTP reachability"],
"detections": ["WAF access log"],
"artifacts": ["HTTP access log"],
},
}
The agent block guides the autonomous orchestrator (budget, approvals).
The attack block feeds attack catalog and Navigator exports.
Options
from core.framework.option.option_string import OptString
from core.framework.option.option_port import OptPort
from core.framework.option.option_bool import OptBool
rhost = OptString("", "Target host", required=True)
rport = OptPort(80, "Port", required=True)
ssl = OptBool(False, "HTTPS")
path = OptString("/", "Path")
Rules:
- Short, consistent names (
rhost,rport) for script compatibility. required=Truefor options without a sensible default.- Clear descriptions: they appear in
show optionsand agent reports.
ModuleResult return value
return ModuleResult(
success=True,
finding={
"title": "Missing security headers",
"severity": "medium",
"url": url,
"missing_headers": ["Content-Security-Policy"],
},
evidence=response.headers,
message="Observation complete",
)
Usual severities: info, low, medium, high, critical.
Error handling
def run(self):
try:
response = requests.get(url, timeout=self.timeout)
except requests.Timeout:
return ModuleResult(success=False, message="Timeout")
except requests.RequestException as exc:
return ModuleResult(success=False, message=str(exc))
Never let an unhandled exception interrupt console or agent execution.
check method
For exploits and validations:
def check(self):
if self._vulnerable():
return ModuleResult(success=True, message="Target appears vulnerable")
return ModuleResult(success=False, message="Target does not appear vulnerable")
Development cycle
- Start from an existing module such as
modules/scanner/http/security_headers_detect.py. - Create the new file under the matching family, then run
sync nowandsearch <name>. use ...,set,runagainst an authorized local target.inventory --only brokento verify the static contract.agent metadatafor agent block coverage.- Run focused tests and keep concise module documentation in
README.
Useful developer commands
new scanner http header_audit
edit
reload
check
inventory --only broken
agent metadata annotate --apply --family scanner
Marketplace publication
See the marketplace chapter. Summary: extension.toml, minimal permissions,
market install ./path, validation on an authorized local target.
Anti-patterns
- Catch-all module (scan + exploit + report).
- Hard-coded credentials in code.
- No network timeout.
- Systematic
criticalseverity. - Heavy imports at module load time (prefer local imports inside
run).