Docs / Development and architecture / Advanced Module Development
GitHub

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 agent and campaign.
  • 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=True for options without a sensible default.
  • Clear descriptions: they appear in show options and 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

  1. Start from an existing module such as modules/scanner/http/security_headers_detect.py.
  2. Create the new file under the matching family, then run sync now and search <name>.
  3. use ..., set, run against an authorized local target.
  4. inventory --only broken to verify the static contract.
  5. agent metadata for agent block coverage.
  6. 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 critical severity.
  • Heavy imports at module load time (prefer local imports inside run).