Compare commits

...
Author SHA1 Message Date
Mzack9999 cd6657c332 Reset unresolved 2026-10-26 16:45:38 +01:00
Mzack9999 7f9c303d83 Count skips 2026-10-26 12:19:59 +01:00
Mzack9999 426b847866 Merge dev 2026-10-26 12:04:13 +01:00
Mzack9999 dcfc4aced0 Omit target 2026-10-26 11:41:00 +01:00
Mzack9999 fdf7f5fde3 Show skips 2026-10-26 00:38:39 +01:00
Mzack9999 f19e771955 Fix review 2026-10-26 00:36:19 +01:00
Mzack9999 9f5ab95cc6 Merge dev 2026-10-26 00:27:47 +01:00
Mzack9999 13a505b3c7 unresolved logging 2026-07-23 22:03:01 +04:00
17 changed files with 259 additions and 16 deletions

No files matched your search

+1
View File
@@ -498,6 +498,7 @@ on extensive configurability, massive extensibility and ease of use.`)
flagSet.StringVar(&memProfile, "profile-mem", "", "generate memory (heap) profile & trace files"),
flagSet.BoolVar(&options.VerboseVerbose, "vv", false, "display templates loaded for scan"),
flagSet.BoolVarP(&options.ShowVarDump, "show-var-dump", "svd", false, "show variables dump for debugging"),
flagSet.BoolVarP(&options.LogUnresolved, "log-unresolved", "lu", false, "log per-request warnings for unresolved template variables (summary is always printed)"),
flagSet.IntVarP(&options.VarDumpLimit, "var-dump-limit", "vdl", 255, "limit the number of characters displayed in var dump"),
flagSet.BoolVarP(&options.EnablePprof, "enable-pprof", "ep", false, "enable pprof debugging server"),
flagSet.CallbackVarP(printTemplateVersion, "templates-version", "tv", "shows the version of the installed nuclei-templates"),
+9
View File
@@ -910,6 +910,15 @@ func (r *Runner) RunEnumeration() error {
r.progress.Stop()
timeTaken := time.Since(now)
if counter, ok := r.progress.(progress.UnresolvedCounter); ok && counter.SkippedUnresolved() > 0 {
skipped := counter.SkippedUnresolved()
msg := fmt.Sprintf("Skipped %d request(s) due to unresolved variables", skipped)
if !r.options.LogUnresolved {
msg += " (use -log-unresolved to see details)"
}
r.Logger.Info().Msg(msg)
}
// Print pool/tracker stats if available (single dialers lookup, reads under lock)
if dialers := protocolstate.GetDialersWithId(r.options.ExecutionId); dialers != nil {
dialers.Lock()
+28 -4
View File
@@ -17,6 +17,7 @@ import (
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/generators"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/marker"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/render"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/unresolvedvars"
"github.com/projectdiscovery/nuclei/v3/pkg/utils/json"
"github.com/projectdiscovery/retryablehttp-go"
"github.com/projectdiscovery/utils/errkit"
@@ -92,6 +93,16 @@ type GeneratedRequest struct {
// Input is not thread safe and should not be shared between concurrent
// goroutines.
func (rule *Rule) Execute(input *ExecuteRuleInput) (err error) {
// a rule with unresolved variables can never build a request, so it is
// skipped and counted like any other request with unresolved variables
if rule.unresolvedErr != nil {
var target string
if input.Input != nil && input.Input.MetaInput != nil {
target = input.Input.MetaInput.Input
}
unresolvedvars.Skip(rule.options.Progress, rule.options.Options, rule.options.TemplateID, target, rule.unresolvedErr)
return nil
}
if !rule.isInputURLValid(input.Input) {
return errkit.Newf("rule not applicable: invalid input url: %v", input.Input.MetaInput.Input)
}
@@ -459,6 +470,8 @@ func (rule *Rule) executeRuleValues(input *ExecuteRuleInput, ruleComponent compo
// Compile compiles a fuzzing rule and initializes it for operation
func (rule *Rule) Compile(generator *generators.PayloadGenerator, options *protocols.ExecutorOptions) error {
// a recompiled rule must not keep the result of an earlier compile
rule.unresolvedErr = nil
// If a payload generator is specified from base request, use it
// for payload values.
if generator != nil {
@@ -506,7 +519,7 @@ func (rule *Rule) Compile(generator *generators.PayloadGenerator, options *proto
for _, key := range rule.Keys {
evaluatedKey, err := rule.evaluateVars(key)
if err != nil {
return errors.Wrap(err, "could not evaluate key")
return rule.compileVarsError(err, "could not evaluate key")
}
rule.keysMap[strings.ToLower(evaluatedKey)] = struct{}{}
@@ -516,7 +529,7 @@ func (rule *Rule) Compile(generator *generators.PayloadGenerator, options *proto
for _, value := range rule.ValuesRegex {
evaluatedValue, err := rule.evaluateVars(value)
if err != nil {
return errors.Wrap(err, "could not evaluate value regex")
return rule.compileVarsError(err, "could not evaluate value regex")
}
compiled, err := regexp.Compile(evaluatedValue)
@@ -531,7 +544,7 @@ func (rule *Rule) Compile(generator *generators.PayloadGenerator, options *proto
for _, value := range rule.KeysRegex {
evaluatedValue, err := rule.evaluateVars(value)
if err != nil {
return errors.Wrap(err, "could not evaluate key regex")
return rule.compileVarsError(err, "could not evaluate key regex")
}
compiled, err := regexp.Compile(evaluatedValue)
@@ -553,7 +566,7 @@ func (rule *Rule) Compile(generator *generators.PayloadGenerator, options *proto
evalReplaceRegex, err := rule.evaluateVars(rule.ReplaceRegex)
if err != nil {
return errors.Wrap(err, "could not evaluate replace regex")
return rule.compileVarsError(err, "could not evaluate replace regex")
}
compiled, err := regexp.Compile(evalReplaceRegex)
@@ -566,3 +579,14 @@ func (rule *Rule) Compile(generator *generators.PayloadGenerator, options *proto
return nil
}
// compileVarsError returns the error for a rule value that failed to evaluate
// at compile time. Unresolved variables do not fail the template: the rule is
// kept and every execution is skipped and counted at scan time instead.
func (rule *Rule) compileVarsError(err error, message string) error {
if unresolvedvars.Is(err) {
rule.unresolvedErr = errors.Wrap(err, message)
return nil
}
return errors.Wrap(err, message)
}
+3
View File
@@ -100,6 +100,9 @@ type Rule struct {
replaceRegex *regexp.Regexp `yaml:"-" json:"-"`
options *protocols.ExecutorOptions
generator *generators.PayloadGenerator
// unresolvedErr is set when a rule value has unresolved variables at
// compile time; executions of the rule are then skipped and counted
unresolvedErr error
}
// ruleType is the type of rule enum declaration
+74
View File
@@ -0,0 +1,74 @@
package fuzz
import (
"context"
"sync/atomic"
"testing"
"github.com/projectdiscovery/nuclei/v3/pkg/progress"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/contextargs"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/variables"
"github.com/projectdiscovery/nuclei/v3/pkg/types"
"github.com/projectdiscovery/nuclei/v3/pkg/utils"
"github.com/stretchr/testify/require"
)
type unresolvedProgress struct {
progress.Progress
skipped atomic.Int64
}
func (p *unresolvedProgress) IncrementSkippedUnresolved(count int64) { p.skipped.Add(count) }
func (p *unresolvedProgress) SkippedUnresolved() uint64 { return uint64(p.skipped.Load()) }
func TestUnresolvedRuleVariablesAreSkipped(t *testing.T) {
tests := map[string]*Rule{
"keys": {Part: "query", Keys: []string{`{{to_lower("{{nosuchkey}}")}}`}},
"keys-regex": {Part: "query", KeysRegex: []string{`{{to_lower("{{nosuchkey}}")}}`}},
"values-regex": {Part: "query", ValuesRegex: []string{`{{to_lower("{{nosuchkey}}")}}`}},
"replace-regex": {Part: "query", Type: "replace-regex", ReplaceRegex: `{{to_lower("{{nosuchkey}}")}}`},
}
for name, rule := range tests {
t.Run(name, func(t *testing.T) {
prog := &unresolvedProgress{}
executorOpts := &protocols.ExecutorOptions{
TemplateID: "unresolved-fuzz",
Variables: variables.Variable{InsertionOrderedStringMap: *utils.NewEmptyInsertionOrderedStringMap(0)},
Constants: map[string]interface{}{},
Options: &types.Options{},
Progress: prog,
}
// the template still loads
require.NoError(t, rule.Compile(nil, executorOpts))
input := &ExecuteRuleInput{Input: contextargs.NewWithInput(context.Background(), "http://127.0.0.1/?a=1")}
require.NoError(t, rule.Execute(input))
require.NoError(t, rule.Execute(input))
require.Equal(t, uint64(2), prog.SkippedUnresolved())
})
}
}
func TestRecompiledRuleClearsUnresolvedError(t *testing.T) {
rule := &Rule{Part: "query", Keys: []string{`{{to_lower("{{nosuchkey}}")}}`}}
prog := &unresolvedProgress{}
executorOpts := &protocols.ExecutorOptions{
TemplateID: "unresolved-fuzz",
Variables: variables.Variable{InsertionOrderedStringMap: *utils.NewEmptyInsertionOrderedStringMap(0)},
Constants: map[string]interface{}{},
Options: &types.Options{},
Progress: prog,
}
require.NoError(t, rule.Compile(nil, executorOpts))
require.Error(t, rule.unresolvedErr)
// the same rule now compiles with values that resolve
rule.Keys = []string{"a"}
require.NoError(t, rule.Compile(nil, executorOpts))
require.NoError(t, rule.unresolvedErr)
input := &ExecuteRuleInput{Input: contextargs.NewWithInput(context.Background(), "http://127.0.0.1/?a=1")}
_ = rule.Execute(input)
require.Zero(t, prog.SkippedUnresolved())
}
+26 -2
View File
@@ -34,6 +34,17 @@ type Progress interface {
IncrementFailedRequestsBy(count int64)
}
// UnresolvedCounter is implemented by a Progress that also counts requests
// skipped because template variables could not be resolved. It is separate
// from Progress so that custom Progress implementations keep compiling.
type UnresolvedCounter interface {
// IncrementSkippedUnresolved increments the count of requests skipped because
// template variables could not be resolved.
IncrementSkippedUnresolved(count int64)
// SkippedUnresolved returns how many requests were skipped for unresolved variables.
SkippedUnresolved() uint64
}
// TaskTracker is implemented by a Progress that also counts template
// executions. The engine counts one task for each template it runs on a
// target, and one for each self-contained template. Unlike the request total,
@@ -47,8 +58,9 @@ type TaskTracker interface {
}
var (
_ Progress = &StatsTicker{}
_ TaskTracker = &StatsTicker{}
_ Progress = &StatsTicker{}
_ TaskTracker = &StatsTicker{}
_ UnresolvedCounter = &StatsTicker{}
)
// StatsTicker is a progress instance for showing program stats
@@ -99,6 +111,7 @@ func (p *StatsTicker) Init(hostCount int64, rulesCount int, requestCount int64)
p.stats.AddCounter("requests", uint64(0))
p.stats.AddCounter("errors", uint64(0))
p.stats.AddCounter("matched", uint64(0))
p.stats.AddCounter("unresolved", uint64(0))
p.stats.AddCounter("total", uint64(requestCount))
p.stats.AddCounter("tasks", uint64(0))
p.stats.AddCounter("totalTasks", uint64(0))
@@ -174,6 +187,17 @@ func (p *StatsTicker) IncrementFailedRequestsBy(count int64) {
p.stats.IncrementCounter("errors", int(count))
}
// IncrementSkippedUnresolved increments requests skipped due to unresolved variables.
func (p *StatsTicker) IncrementSkippedUnresolved(count int64) {
p.stats.IncrementCounter("unresolved", int(count))
}
// SkippedUnresolved returns the number of requests skipped due to unresolved variables.
func (p *StatsTicker) SkippedUnresolved() uint64 {
count, _ := p.stats.GetCounter("unresolved")
return count
}
func (p *StatsTicker) makePrintCallback() func(stats clistats.StatisticsClient) interface{} {
return func(stats clistats.StatisticsClient) interface{} {
builder := &strings.Builder{}
+20
View File
@@ -0,0 +1,20 @@
package progress
import (
"testing"
"github.com/stretchr/testify/require"
)
func TestSkippedUnresolvedCounter(t *testing.T) {
p, err := NewStatsTicker(-1, false, false, false, 0)
require.NoError(t, err)
p.Init(1, 1, 10)
counter, ok := p.(UnresolvedCounter)
require.True(t, ok)
require.Equal(t, uint64(0), counter.SkippedUnresolved())
counter.IncrementSkippedUnresolved(1)
counter.IncrementSkippedUnresolved(2)
require.Equal(t, uint64(3), counter.SkippedUnresolved())
}
@@ -2,6 +2,7 @@ package expressions
import (
"errors"
"fmt"
"regexp"
"strings"
@@ -9,6 +10,10 @@ import (
"github.com/projectdiscovery/nuclei/v3/pkg/operators/common/dsl"
)
// ErrUnresolvedVariables is wrapped by every error that reports unresolved
// template variables, so callers can classify it with errors.Is.
var ErrUnresolvedVariables = errors.New("unresolved variables")
var (
numericalExpressionRegex = regexp.MustCompile(`^[0-9+\-/\W]+$`)
unresolvedVariablesRegex = regexp.MustCompile(`(?:%7[B|b]|\{){2}([^}]+)(?:%7[D|d]|\}){2}["'\)\}]*`)
@@ -38,7 +43,7 @@ func ContainsUnresolvedVariables(items ...string) error {
unresolvedVariables = append(unresolvedVariables, match[1])
}
if len(unresolvedVariables) > 0 {
return errors.New("unresolved variables found: " + strings.Join(unresolvedVariables, ","))
return fmt.Errorf("%w found: %s", ErrUnresolvedVariables, strings.Join(unresolvedVariables, ","))
}
}
@@ -72,7 +77,7 @@ func ContainsVariablesWithNames(names map[string]interface{}, items ...string) e
}
}
if len(unresolvedVariables) > 0 {
return errors.New("unresolved variables with values found: " + strings.Join(unresolvedVariables, ","))
return fmt.Errorf("%w with values found: %s", ErrUnresolvedVariables, strings.Join(unresolvedVariables, ","))
}
}
@@ -109,7 +114,7 @@ func ContainsVariablesWithIgnoreList(skipNames map[string]interface{}, items ...
}
if len(unresolvedVariables) > 0 {
return errors.New("unresolved variables with values found: " + strings.Join(unresolvedVariables, ","))
return fmt.Errorf("%w with values found: %s", ErrUnresolvedVariables, strings.Join(unresolvedVariables, ","))
}
return nil
@@ -40,7 +40,12 @@ func TestUnresolvedVariablesCheck(t *testing.T) {
}
for _, test := range tests {
err := ContainsUnresolvedVariables(test.data)
require.Equal(t, test.err, err, "could not get unresolved variables")
if test.err == nil {
require.NoError(t, err, "could not get unresolved variables")
continue
}
require.EqualError(t, err, test.err.Error(), "could not get unresolved variables")
require.ErrorIs(t, err, ErrUnresolvedVariables)
}
}
@@ -0,0 +1,35 @@
package unresolvedvars
import (
"errors"
"github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/nuclei/v3/pkg/progress"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/expressions"
"github.com/projectdiscovery/nuclei/v3/pkg/types"
)
// Is reports whether err is (or wraps) an unresolved-variables error.
func Is(err error) bool {
return errors.Is(err, expressions.ErrUnresolvedVariables)
}
// Skip records a request skipped due to unresolved variables and optionally logs it.
// Per-request warnings are muted unless options.LogUnresolved is set; use the end-of-scan
// summary from progress.UnresolvedCounter instead.
func Skip(prog progress.Progress, options *types.Options, templateID, target string, err error) {
if counter, ok := prog.(progress.UnresolvedCounter); ok {
counter.IncrementSkippedUnresolved(1)
}
// The user asked for these lines, so they are logged at info level: the
// default log level hides warnings unless -v is set.
if options == nil || !options.LogUnresolved {
return
}
// self-contained requests have no input target
if target == "" {
gologger.Info().Msgf("[%s] Could not make request: %v\n", templateID, err)
return
}
gologger.Info().Msgf("[%s] Could not make request for %s: %v\n", templateID, target, err)
}
@@ -0,0 +1,22 @@
package unresolvedvars
import (
"errors"
"fmt"
"testing"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/expressions"
"github.com/projectdiscovery/utils/errkit"
"github.com/stretchr/testify/require"
)
func TestIs(t *testing.T) {
require.True(t, Is(expressions.ContainsUnresolvedVariables("{{user}}")))
require.True(t, Is(expressions.ContainsVariablesWithIgnoreList(nil, "{{user}}")))
require.True(t, Is(fmt.Errorf("%w `%v` found in request", expressions.ErrUnresolvedVariables, "{{user}}")))
require.True(t, Is(errkit.Wrap(expressions.ContainsUnresolvedVariables("{{user}}"), "could not build request")))
// an unrelated error that only mentions the phrase is not a skip
require.False(t, Is(errors.New("unresolved variables found: user")))
require.False(t, Is(errors.New("connection refused")))
require.False(t, Is(nil))
}
+7 -2
View File
@@ -20,6 +20,7 @@ import (
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/generators"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/helpers/eventcreator"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/helpers/responsehighlighter"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/unresolvedvars"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/utils/vardump"
protocolutils "github.com/projectdiscovery/nuclei/v3/pkg/protocols/utils"
templateTypes "github.com/projectdiscovery/nuclei/v3/pkg/templates/types"
@@ -140,7 +141,11 @@ func (request *Request) execute(input *contextargs.Context, domain string, metad
// to resolve. See https://github.com/projectdiscovery/nuclei/issues/7374.
resolverVars := generators.MergeMaps(vars, metadata)
if dnsClient, varErr = request.getDnsClient(request.options, resolverVars); varErr != nil {
gologger.Warning().Msgf("[%s] Could not make dns request for %s: %v\n", request.options.TemplateID, domain, varErr)
if unresolvedvars.Is(varErr) {
unresolvedvars.Skip(request.options.Progress, request.options.Options, request.options.TemplateID, domain, varErr)
} else {
gologger.Warning().Msgf("[%s] Could not make dns request for %s: %v\n", request.options.TemplateID, domain, varErr)
}
return nil
}
}
@@ -154,7 +159,7 @@ func (request *Request) execute(input *contextargs.Context, domain string, metad
requestString := compiledRequest.String()
if varErr := expressions.ContainsUnresolvedVariables(requestString); varErr != nil {
gologger.Warning().Msgf("[%s] Could not make dns request for %s: %v\n", request.options.TemplateID, question, varErr)
unresolvedvars.Skip(request.options.Progress, request.options.Options, request.options.TemplateID, question, varErr)
return nil
}
if request.options.Options.Debug || request.options.Options.DebugRequests || request.options.Options.StoreResponse {
+5
View File
@@ -24,6 +24,7 @@ import (
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/hostratelimit"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/interactsh"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/render"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/unresolvedvars"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/headless/engine"
protocolutils "github.com/projectdiscovery/nuclei/v3/pkg/protocols/utils"
templateTypes "github.com/projectdiscovery/nuclei/v3/pkg/templates/types"
@@ -185,6 +186,10 @@ func (request *Request) executeRequestWithPayloads(input *contextargs.Context, p
timeStart := time.Now()
out, createdPage, err := instance.Run(input, request.Steps, payloads, options)
runDuration := time.Since(timeStart)
if unresolvedvars.Is(err) {
unresolvedvars.Skip(request.options.Progress, request.options.Options, request.options.TemplateID, input.MetaInput.Input, err)
return nil
}
if err != nil {
request.options.Output.Request(request.options.TemplatePath, input.MetaInput.Input, request.Type().String(), err)
request.options.Progress.IncrementFailedRequestsBy(1)
+2 -2
View File
@@ -339,7 +339,7 @@ func (r *requestGenerator) makeSelfContainedRequest(ctx context.Context, input *
}
if err := expressions.ContainsUnresolvedVariables(parts[1]); err != nil && !r.request.SkipVariablesCheck {
return nil, errkit.Newf("unresolved variables `%v` found in request", parts[1])
return nil, fmt.Errorf("%w `%v` found in request", expressions.ErrUnresolvedVariables, parts[1])
}
parsed, err := urlutil.ParseURL(parts[1], true)
@@ -367,7 +367,7 @@ func (r *requestGenerator) makeSelfContainedRequest(ctx context.Context, input *
if err := expressions.ContainsUnresolvedVariables(data); err != nil && !r.request.SkipVariablesCheck {
// early exit: if there are any unresolved variables in `path` after evaluation
// then return early since this will definitely fail
return nil, errkit.Newf("unresolved variables `%v` found in request", data)
return nil, fmt.Errorf("%w `%v` found in request", expressions.ErrUnresolvedVariables, data)
}
urlx, err := urlutil.ParseURL(data, true)
+6 -1
View File
@@ -39,6 +39,7 @@ import (
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/interactsh"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/marker"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/protocolstate"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/unresolvedvars"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/utils/vardump"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/http/httpclientpool"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/http/httputils"
@@ -683,6 +684,10 @@ executionLoop:
if err == types.ErrNoMoreRequests {
return false, true, nil, nil
}
if unresolvedvars.Is(err) {
unresolvedvars.Skip(request.options.Progress, request.options.Options, request.options.TemplateID, input.MetaInput.Input, err)
return false, true, nil, nil
}
return false, true, nil, err
}
// ideally if http template used a custom port or hostname
@@ -1140,7 +1145,7 @@ func (request *Request) executeRequest(input *contextargs.Context, generatedRequ
varErr = expressions.ContainsUnresolvedVariables(item)
}
if varErr != nil && !request.SkipVariablesCheck {
gologger.Warning().Msgf("[%s] Could not make http request for %s: %v\n", request.options.TemplateID, input.MetaInput.Input, varErr)
unresolvedvars.Skip(request.options.Progress, request.options.Options, request.options.TemplateID, input.MetaInput.Input, varErr)
return ErrMissingVars
}
}
+2 -1
View File
@@ -29,6 +29,7 @@ import (
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/interactsh"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/render"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/replacer"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/unresolvedvars"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/utils/vardump"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/network/networkclientpool"
protocolutils "github.com/projectdiscovery/nuclei/v3/pkg/protocols/utils"
@@ -400,7 +401,7 @@ func (request *Request) executeRequestWithPayloads(variables map[string]interfac
interactshURLs = result.InteractURLs
if err := expressions.ContainsUnresolvedVariables(data); err != nil {
gologger.Warning().Msgf("[%s] Could not make network request for %s: %v\n", request.options.TemplateID, actualAddress, err)
unresolvedvars.Skip(request.options.Progress, request.options.Options, request.options.TemplateID, actualAddress, err)
return nil
}
+5
View File
@@ -254,6 +254,10 @@ type Options struct {
VerboseVerbose bool
// ShowVarDump displays variable dump
ShowVarDump bool
// LogUnresolved enables per-request warnings when a request is skipped because
// template variables could not be resolved. By default those skips are counted
// and summarized once at the end of the scan instead of flooding the log.
LogUnresolved bool
// VarDumpLimit limits the number of characters displayed in var dump
VarDumpLimit int
// No-Color disables the colored output.
@@ -704,6 +708,7 @@ func (options *Options) Copy() *Options {
Verbose: options.Verbose,
VerboseVerbose: options.VerboseVerbose,
ShowVarDump: options.ShowVarDump,
LogUnresolved: options.LogUnresolved,
VarDumpLimit: options.VarDumpLimit,
NoColor: options.NoColor,
UpdateTemplates: options.UpdateTemplates,