[RFC] Template Target Resolution Consolidation
Status
Draft.
Abstract
Nuclei currently gives template authors several ways to influence where a request goes:
self-contained: true, which marks a template as runnable without user-supplied targets.- Raw HTTP request lines that contain a full URI, especially when combined with
unsafe: true(#7382). - Request annotations such as
@Host, plus related annotations such as@tls-sni,@timeout, and@once.
These features are useful, but they overlap enough that it is easy to blur target ownership, raw HTTP fidelity, wire headers, and transport overrides. This RFC lays out one user-facing model for target resolution while keeping current templates working.
The plan is simple: document one model, add tests that lock in today’s behavior, and warn on forms that leave too much room for interpretation.
Problem statement
Today, several template features can look like they do the same job:
- A self-contained HTTP template can embed
GET https://example.com/path HTTP/1.1and run without-u. - A target-bound raw HTTP template can also place
https://example.com/pathin the request line. - A raw HTTP template can use
@Host: example.comto override the destination for a request while still containing a normalHost:header. unsafe: truegives raw transport control and also has custom handling for absolute request-targets.
The result is unclear ownership:
- Who owns the destination: the scan input, the template, the raw request line, or the annotation?
- Does
unsafe: truemean "send exactly this raw request" or "use this embedded full URI as the target"? - Is a
Host:header a routing decision or just a wire header? - Does
@Hostmake a template self-contained? - Which behavior should reviewers rely on when preventing regressions?
This RFC separates those concerns instead of letting them collapse into one vague idea.
Goals
- Define one clear mental model for target resolution.
- Preserve existing behavior for currently valid templates.
- Explain how
self-contained, full URI request lines,unsafe, and annotations relate to each other. - Cover HTTP, network, and headless self-contained behavior.
- Give template authors and reviewers a practical guide.
- Identify warnings and tests that should land before any future deprecation.
Non-goals
- Do not remove support for
self-contained,unsafe, full URI request lines, or request annotations. - Do not make all overlapping forms aliases of each other.
- Do not change the default security posture that self-contained templates are disabled unless explicitly enabled.
- Do not redefine the full HTTP raw transport model in this RFC.
- Do not change request signing, authentication, clustering, or matcher semantics except where they depend on the effective destination.
Terms
Scan input target
The target supplied by the operator through -u, -l, input providers, workflows, or SDK equivalents.
Template-declared target
A destination embedded in the template itself, such as a self-contained HTTP URL, network host, or headless navigation URL.
Effective request destination
The scheme, host, and port Nuclei connects to for one request.
Request target
The path, query, or full request-target that appears in an HTTP request line or normal HTTP URL.
Wire Host header
The HTTP Host: header value sent in the request bytes. This may differ from the effective request destination.
Transport modifiers
Settings that alter how the request is transported without owning the template's execution mode, such as unsafe, @tls-sni, @timeout, and @once.
Current behavior inventory
Self-contained templates
self-contained: true is a template-level execution mode.
Current behavior:
- The template is excluded unless self-contained templates are enabled with
-escor the corresponding SDK/config option. - The template does not require a scan input target.
- The template is executed separately from target-bound scans.
- The template-level flag is propagated to supported protocol requests.
- HTTP, network, and headless currently have self-contained execution paths.
Protocol-specific behavior:
- HTTP self-contained requests derive their destination from the request path or URL and, for raw relative requests, from the raw
Host:header. - Network self-contained requests derive their destination from the request's declared host value.
- Headless self-contained requests derive their base target from the declared navigation URL.
Target-bound HTTP requests
For normal target-bound HTTP requests:
- The scan input target is the default destination source.
- Template paths and raw request paths are resolved against the scan input target.
- A raw request
Host:header controls the wire header value, not the fact that the template is target-bound.
Full URI in raw HTTP requests
Raw HTTP request lines may contain a full URI.
Current compatibility behavior:
- The full URI is parsed so its path and query can be used as request-target material.
- In target-bound templates, the embedded URI authority is not the same as declaring the template self-contained.
- With
unsafe: true, Nuclei rewrites the raw request bytes so the outbound raw request line uses a relative request-target rather than retaining the full URI. - Path automerge settings still affect how that request-target combines with the scan input target.
This is where things get muddy: a full URI looks like a destination, but in target-bound raw HTTP compatibility mode it mainly behaves like request-target material.
unsafe: true
unsafe: true is a transport fidelity setting.
Current behavior:
- It routes raw HTTP through the raw HTTP transport path.
- It allows malformed or non-RFC-compliant request forms that the normal client may reject or normalize.
- It preserves and sends custom raw request bytes after Nuclei performs compatibility substitutions such as annotation stripping and path adjustment.
- It does not by itself make a template self-contained.
- It does not by itself remove the need for scan input.
Request annotations
Annotations are request-local directives placed before the raw request line.
Current annotation categories:
@Host: overrides the effective HTTP request destination for that request.@tls-sni: overrides TLS SNI behavior for that request.@timeout: adjusts request timeout behavior when timeout annotations are enabled by the current execution mode.@once: alters request flow so the annotated request executes only once where supported.
Current behavior:
- Annotation lines are not sent on the wire in raw unsafe bytes.
@Hostis not equivalent toself-contained: true; it is a per-request destination override.@Hostis not equivalent to the rawHost:header; the annotation changes where Nuclei connects, while the header is the HTTP value sent to the server.
Proposal
Target resolution breaks down into four separate decisions:
- Execution mode: whether the template is target-bound or self-contained.
- Destination source: which value selects the scheme, host, and port for a request.
- Request-target source: which value supplies path and query material.
- Transport modifiers: which features affect raw bytes, TLS, timeout, and flow.
Canonical model
1. Execution mode
self-contained: true is the only template-level declaration that a template can run without user-supplied scan input.
If self-contained: true is absent, the template is target-bound. Target-bound templates still require scan input even if a raw HTTP request contains a full URI or an @Host annotation.
2. Destination source
Destination source is selected as follows:
| Context | Default destination source | Override source |
|---|---|---|
| Target-bound HTTP | Scan input target | @Host per request |
| Self-contained HTTP normal URL | Template URL | @Host per raw request where applicable |
| Self-contained HTTP raw full URI | Request-line URI | @Host per request where applicable |
| Self-contained HTTP raw relative path | Raw Host: header with default HTTP scheme |
@Host per request where applicable |
| Target-bound network | Scan input host/derived network port | Protocol request host rules where supported |
| Self-contained network | Declared network host | None in this RFC |
| Target-bound headless | Scan input target | Navigation actions may visit additional URLs as page behavior |
| Self-contained headless | First declared navigation URL | None in this RFC |
3. Request-target source
For HTTP:
- Normal HTTP
pathvalues determine path and query after template variables are evaluated. - Raw HTTP request lines determine path and query for raw requests.
- A full URI in a raw request line contributes path and query material under compatibility behavior.
- In target-bound templates, the full URI authority must not be documented as the canonical destination source.
4. Transport modifiers
Transport modifiers do not change execution mode.
unsafe: trueselects raw HTTP transport behavior.@tls-snicontrols SNI behavior.@timeoutcontrols timeout behavior where timeout annotations are active.@oncecontrols flow behavior.- Raw
Host:controls the wireHostheader.
Precedence rules
These rules define the public contract we want people to rely on.
- If a template has
self-contained: true, it is eligible to run without scan input only when self-contained templates are enabled. - If a template does not have
self-contained: true, it remains target-bound and requires scan input. - For target-bound HTTP requests, scan input provides the destination unless
@Hostis present. - For target-bound HTTP raw requests, a full URI request line supplies request-target path/query material under compatibility behavior.
@Hostoverrides the effective destination for that one HTTP request.- The raw
Host:header remains the wire header value and is not treated as a destination override. unsafe: trueaffects raw transport and request-byte handling, not template execution mode.@tls-sniaffects TLS SNI and does not imply@Host.@timeoutaffects timeout behavior and does not imply a destination change.- Annotation lines must not be sent as HTTP wire bytes.
Author guidance
Use self-contained: true when:
- The template intentionally contacts a destination embedded in the template.
- The operator should not need to pass
-uor-l. - The template should be guarded by
-esc.
Use normal target-bound templates when:
- The operator chooses the scan target.
- Paths, raw requests, payloads, and matchers should be applied to each supplied target.
Use @Host when:
- A single HTTP request needs to connect to a host different from the scan input target.
- The template still conceptually belongs to a target-bound scan.
- The wire
Host:header may need to remain distinct from the connection destination.
Use unsafe: true when:
- The request must be sent through raw HTTP transport.
- The template needs malformed paths, duplicate headers, ambiguous request bytes, or other non-normalized behavior.
- The goal is raw request fidelity, not target declaration.
Avoid using a full URI in a target-bound unsafe raw request as the only signal for destination intent. Prefer self-contained: true for template-owned destinations or @Host for request-local destination overrides.
Validation and warning policy
Warnings should land before any future breaking validation.
Recommended warnings:
- Target-bound raw HTTP request contains a full URI with an authority component and
self-contained: trueis absent. - Target-bound raw HTTP request combines a full URI authority with
unsafe: true; warn that the authority is handled as compatibility request-target material, not as the canonical destination. - Raw HTTP request contains both
@Hostand a full URI authority that differ; warn that@Hostdetermines the effective destination. - Self-contained HTTP raw relative request is missing a usable
Host:header. - Annotation values contain unresolved variables after evaluation.
Warnings should be deduplicated per template/request where possible so scans do not get noisy.
Backward compatibility
This proposal keeps current templates working.
No immediate syntax removal:
- Keep
self-contained: true. - Keep raw full URI support.
- Keep
unsafe: true. - Keep request annotations.
No immediate behavior change:
- Do not reinterpret every full URI request line as a destination override.
- Do not silently convert
@Hostinto self-contained execution. - Do not make
unsafe: trueimply self-contained execution.
If we ever need a breaking change, that should come in a separate RFC after warnings have been in place long enough for authors to react.
Alternatives considered
Make all forms equivalent
Treat self-contained, full URI raw requests, and @Host as aliases for destination ownership.
Rejected because it would collapse execution mode, request target, wire header, and transport behavior into one concept. It would also make target-bound templates unexpectedly targetless.
Strict breaking cleanup
Reject ambiguous combinations immediately.
Rejected for this RFC because existing templates and tests rely on compatibility behavior.
Documentation only
Document current behavior without introducing warnings or a canonical model.
Rejected because documentation alone does not give reviewers a regression contract and does not help authors spot ambiguous templates.
Rollout plan
- Publish the RFC, product spec, and technical spec.
- Add documentation examples for the canonical model.
- Add tests that freeze current behavior across HTTP, network, and headless self-contained execution.
- Add non-fatal warnings for ambiguous HTTP raw full URI forms.
- Evaluate warning telemetry and template corpus impact before considering stricter validation.
Acceptance criteria
- Users can explain whether a template is target-bound or self-contained by reading template-level syntax.
- Users understand that
unsafe: trueis transport behavior, not target ownership. - Users understand that
@Hostis a request-local destination override. - Users understand that raw
Host:is a wire header, not the same as@Host. - Existing templates continue to run without behavior changes.
- Reviewers have a test matrix that prevents accidental target-resolution regressions.
Source: projectdiscovery/nuclei