Skip to content

Plugin System

CommonHuman-Lab edited this page Jun 1, 2026 · 1 revision

Plugin System

Scanners are independent PyPI packages. The orchestrator (and worker nodes) discover them via Python entry points at startup. The core never contains scanner logic — install what you need, uninstall what you don't.

Entry point format

# In the scanner package's pyproject.toml:
[project.entry-points."gloomproxy.scanners"]
xss = "gloomscan_xss.scanner:XSSScanner"

BaseScanner interface

from gloomproxy_sdk import BaseScanner, Finding, ScanContext, Target
from gloomproxy_sdk.manifest import PluginManifest, TrustLevel

class XSSScanner(BaseScanner):
    name        = "xss"
    version     = "1.0.0"
    description = "Reflected and stored XSS detection"
    author      = "CommonHuman-Lab"
    tags        = ["xss", "active", "http"]

    @classmethod
    def manifest(cls) -> PluginManifest:
        return {
            "trust_level": TrustLevel.COMMUNITY,
            "resources": {"max_runtime": 120, "max_findings": 500},
            "sdk_min_version": "0.1.0",
        }

    def initialize(self, context: ScanContext) -> None:
        self._cfg = context.config

    async def scan(self, target: Target) -> list[Finding]:
        return [
            Finding(
                scanner="xss",
                type="reflected_xss",
                severity="high",
                target=target.url,
                evidence="<script>alert(1)</script> reflected unescaped",
                title="Reflected XSS",
            )
        ]

    def teardown(self) -> None:
        pass  # close HTTP sessions etc.

Plugin manifest

Every plugin optionally declares a manifest() classmethod. The sandbox reads it at execution time to resolve resource limits and select the right isolation policy. If omitted, COMMUNITY defaults apply.

@classmethod
def manifest(cls) -> PluginManifest:
    return {
        "trust_level": TrustLevel.COMMUNITY,   # CORE | VERIFIED | COMMUNITY | EXPERIMENTAL
        "resources": {
            "max_runtime": 120,          # seconds — capped by trust-tier ceiling
            "max_memory_mb": 256,        # MB  — advisory in asyncio, hard in subprocess/container
            "max_findings": 500,         # gateway rejects findings beyond this
            "max_events_per_sec": 10.0,  # token-bucket rate
            "max_event_burst": 50,       # burst capacity
        },
        "sdk_min_version": "0.1.0",
    }

Finding schema

All findings pass the validation gateway before reaching the event bus. The orchestrator injects correlation_id, worker_id, and schema_version automatically — scanners do not set these.

{
  "id": "uuid",
  "schema_version": "1.0",
  "scanner": "string (required)",
  "type": "string (required)",
  "severity": "info | low | medium | high | critical",
  "target": "url string (required)",
  "evidence": "string (required, max 64 KB)",
  "title": "string",
  "description": "string",
  "remediation": "string",
  "confidence": "float 0.0–1.0",
  "request": "raw HTTP request",
  "response": "raw HTTP response",
  "references": ["url"],
  "tags": ["string"],
  "extra": {},
  "correlation_id": "uuid (orchestrator-injected)",
  "worker_id": "string (orchestrator-injected)",
  "timestamp": "unix float"
}

SDK (gloomproxy_sdk)

The SDK is the only package plugin authors need to import. It provides the scanner base class, finding model, scan context, event emitter, and plugin manifest types.

from gloomproxy_sdk import (
    BaseScanner, Finding, ScanContext, Target,
    PluginManifest, TrustLevel,
)
from gloomproxy_sdk.exceptions import InitializationError, ScanError
from gloomproxy_sdk.utils.http import ScanHttpClient

The SDK is versioned independently. Workers and orchestrators log a compat warning at startup for any installed plugin whose sdk_min_version or sdk_max_version bounds do not include the installed SDK version. Incompatible plugins are loaded but their warning is visible in GET /api/plugins.

Installing a scanner plugin

# During development — install editable from the scanner package dir
pip install -e /path/to/stingxss

# Or from PyPI once published
pip install stingxss

# Reload without restarting:
curl -X POST http://localhost:8000/api/plugins/reload
# or click Reload in the Plugins UI

Clone this wiki locally