Scans Settings
The Settings -> Scans area is an admin-only foundation for managing scan behavior without changing the scan execution pipeline.
It has two subsections:
- Scan Profiles
- Plugins
Clients do not have access to settings mutation. Hackers continue to use scan/profile APIs according to existing RBAC, but profile and plugin setting changes are admin-only.
Scan Profiles
The Scan Profiles subsection lists profiles returned by the backend profile registry. The public GET /api/v1/scan-profiles endpoint returns enabled built-in profiles from backend/configs/config.yaml plus enabled database-backed custom profiles.
Each profile includes:
- ID
- name
- description
- ordered plugin chain
- source (
configorcustom) - built-in flag
- enabled flag
- plugin count
- supported scope types derived from registered plugin metadata
Built-in config-backed profiles remain read-only in the UI. The UI does not rewrite config.yaml.
Custom Profile Builder
Admins can create custom scan profiles from the registered plugin catalog. The MVP builder uses a horizontal ordered pipeline with stage cards, add/remove controls, and move-left/move-right controls. It is intentionally simpler than a free-form canvas, but it presents profiles as scan workflows rather than plain CRUD forms.
Validation rules:
- profile ID must use lowercase letters, numbers, underscore, or dash
- name is required
- at least one plugin is required
- every plugin ID must exist in the registry
- every plugin must be enabled
- every plugin must support
profile_scan - duplicate plugins are rejected
- a custom profile cannot override a built-in config-backed profile ID
Custom profiles are global in this MVP. The custom_scan_profiles.organization_id column is nullable and reserved for future organization-specific profiles.
Persistence
Custom profiles are stored in PostgreSQL in custom_scan_profiles:
idorganization_id(currently null/global)namedescriptionpluginsJSONB ordered arraycreated_bycreated_atupdated_atenabled
API and worker load config profiles first, then merge enabled custom profiles. Config profiles win; custom profiles cannot override them.
Plugin Catalog
The Plugins subsection reads from GET /api/v1/plugins. The registry is the source of truth.
Catalog entries include:
- plugin ID and name
- type
- version
- enabled state
- description
- supported asset types
- supported execution modes
- option schema, when declared
- profile usage list
The MVP UI is read-oriented for plugin enablement. It does not enable or disable plugins from the browser.
Profile Builder Option Indicators
When a plugin declares configurable options, the Scan Profile builder marks it directly in the workflow UI:
configurablemeans the plugin has optional settings available.required optionsmeans the plugin schema contains at least one required setting.- The available plugin list also shows
configorrequired configbadges before the plugin is added to the pipeline.
In the selected pipeline, configurable plugin stages show a settings button. Click it to open the plugin configuration panel without leaving the profile builder.
The configuration panel uses the same validation and storage as the Plugins catalog drawer. For header_list options, admins edit values in a table:
| Header Name | Header Value |
|---|---|
X-Test-Header |
demo |
Click Save Plugin Configuration to persist the settings.
!!! important
Plugin settings are currently global per plugin. If nuclei_test has custom_headers configured, those headers apply whenever nuclei_test runs. Per-profile plugin settings are future work.
UI Example: Configure a Plugin with Custom Headers
Use this flow when a plugin declares a header_list option, such as nuclei_test. You can configure it either from the plugin catalog or directly from a configurable stage in the profile builder.
Catalog flow:
- Open Settings -> Scans.
- Select the Plugins tab.
- Search for the plugin, for example
nuclei_test. - Click the plugin card to open the plugin details drawer.
- In Configurable Options, find Custom HTTP headers.
- Click Add Row.
- Fill the table:
| Header Name | Header Value |
|---|---|
X-Test-Header |
demo |
- Click Save Configuration.
Profile builder flow:
- Open Settings -> Scans.
- Select Scan Profiles.
- Add a plugin that shows
configorrequired configin the available plugins list. - In Selected Pipeline, click the settings button on that plugin stage.
- Fill the header rows and click Save Plugin Configuration.
The saved value is stored in PostgreSQL in plugin_settings.settings for that plugin ID:
{
"custom_headers": [
{ "name": "X-Test-Header", "value": "demo" }
]
}
When the worker runs a plugin, it loads the saved settings, validates them against the plugin option schema, and injects them into PluginInput.Settings. A wrapper that supports custom headers should read input.Settings["custom_headers"] through the shared validation helpers and pass each header as separate process arguments.
For nuclei_test, each saved header becomes separate Nuclei arguments:
-H "X-Test-Header: demo"
The wrapper must pass this as separate exec args, not as a shell string.
!!! note
nuclei_test is currently intended for manual/retry option testing and is not included in built-in scan profiles. It appears in the plugin catalog and configurable options UI because it declares an option schema.
!!! warning Do not store secrets, API keys, bearer tokens, or production credentials in custom headers yet. This MVP stores settings as JSONB and does not provide secret storage.
Plugin Option Schema
Plugins can declare safe configurable options through PluginOptionSchema:
keylabeltype:string,select,number,boolean,string_list, orheader_listrequireddefaultdescriptionsensitiveallowed_valuesfor dropdown/select optionsminandmaxfor numeric bounds
Settings are stored in PostgreSQL in plugin_settings as JSONB by plugin ID. Admin endpoints validate submitted values against the plugin schema before saving.
Secrets and API keys are intentionally out of scope for this MVP. Header settings are for non-secret test headers only until dedicated secret storage exists.
nmap_vulns Options
nmap_vulns demonstrates non-header plugin settings. It appears in the plugin catalog with dropdown and number inputs generated from its option schema:
| Option | UI control | Allowed values | Default |
|---|---|---|---|
script_preset |
dropdown | vuln, safe_vuln |
vuln |
timing |
dropdown | T2, T3, T4 |
T3 |
max_retries |
number input | 0-5 |
1 |
host_timeout_seconds |
number input | 10-300 |
60 |
Admins can add nmap_vulns to a custom profile, normally after naabu or nmap, so it can consume known service assets. It is not part of built-in config profiles.
Safe Custom Headers
The header_list option type accepts values like:
[
{ "name": "X-Test-Header", "value": "demo" }
]
Validation rules:
- header names must be valid HTTP token characters
- header names cannot be empty
- header names cannot contain
: - header names cannot contain CR/LF
- header values cannot contain CR/LF
- header values are capped at 1024 characters
Plugins receive settings through structured PluginInput.Settings. Wrappers must pass values to external tools as separate exec arguments and must not concatenate raw settings into shell strings.
nuclei_test
nuclei_test is a separate plugin wrapper used to prove safe option plumbing.
Behavior:
- registered in the plugin catalog
- not included in default config-backed scan profiles
- supports manual and retry execution modes
- accepts
custom_headersthroughPluginInput.Settings - passes each header to nuclei as separate
-H,Header: valuearguments - test mode reports how many configured headers were accepted without exposing secret material
nuclei_test does not replace the normal nuclei wrapper.
Future Work
Planned extensions:
- organization-specific custom profiles
- per-profile plugin settings
- secret storage for API keys and sensitive headers
- richer profile diff/history/audit views
- advanced visual builder for complex workflows