Files
Dwi Siswanto c50f92fdd3 refactor: enforce scan network restrictions in network helpers
Pass scan options through rendering, variables, matchers, and extractors
so resolve(), public_ip()/publicip(), and jarm() honor -lna and -eh.
These helpers previously performed network I/O outside the scan's network
policy.

Use the scan dialer for HTTP and JARM connections and reject restricted
IP addresses in DNS answers. Validate original and normalized hostnames
to prevent exclusion bypasses through DNS escapes and trailing dots.

Enforce -eh with or without -lna, including in unsigned templates.
Keep local access available without -lna unless excluded, and preserve
configured DNS resolvers, including local ones.

Bind helpers at evaluation time without storing scan state in cached
expressions. Reject network helper calls without initialized scan
context.

Fixes #7769

Signed-off-by: Dwi Siswanto <[email protected]>
2026-09-23 18:53:49 +07:00

124 lines
2.5 KiB
Go

package variables
import "github.com/projectdiscovery/nuclei/v3/pkg/types"
// Scope contains values used while evaluating template variables.
//
// Data values are terminal values from runtime, options, constants, payloads,
// or protocol context. Template values are produced from the template variables
// section and may be re-rendered when later data becomes available.
type Scope struct {
values map[string]scopeValue
options *types.Options
}
type scopeValueKind uint8
const (
scopeValueData scopeValueKind = iota
scopeValueTemplate
)
type scopeValue struct {
value interface{}
kind scopeValueKind
}
// NewScope creates an empty variable evaluation scope.
func NewScope() *Scope {
return &Scope{values: make(map[string]scopeValue)}
}
// WithOptions binds this scope to the current scan without adding template variables.
func (s *Scope) WithOptions(options *types.Options) *Scope {
s.options = options
return s
}
// AddData adds terminal data values to the scope.
func (s *Scope) AddData(values ...map[string]interface{}) *Scope {
if s == nil {
return s
}
for _, valueMap := range values {
for key, value := range valueMap {
s.AddDataValue(key, value)
}
}
return s
}
// AddDataValue adds one terminal data value to the scope.
func (s *Scope) AddDataValue(key string, value interface{}) *Scope {
if s == nil {
return s
}
s.values[key] = scopeValue{value: value, kind: scopeValueData}
return s
}
// AddTemplate adds values produced from template variables.
func (s *Scope) AddTemplate(values map[string]interface{}) *Scope {
if s == nil {
return s
}
for key, value := range values {
s.AddTemplateValue(key, value)
}
return s
}
// AddTemplateValue adds one value produced from template variables.
func (s *Scope) AddTemplateValue(key string, value interface{}) *Scope {
if s == nil {
return s
}
s.values[key] = scopeValue{value: value, kind: scopeValueTemplate}
return s
}
// Values returns a plain value map for render evaluation.
func (s *Scope) Values() map[string]interface{} {
if s == nil || len(s.values) == 0 {
return nil
}
values := make(map[string]interface{}, len(s.values))
for key, value := range s.values {
values[key] = value.value
}
return values
}
func (s *Scope) clone() *Scope {
if s == nil {
return NewScope()
}
clone := NewScope().WithOptions(s.options)
for key, value := range s.values {
clone.values[key] = value
}
return clone
}
func (s *Scope) get(key string) (scopeValue, bool) {
if s == nil {
return scopeValue{}, false
}
value, ok := s.values[key]
return value, ok
}