diff --git a/pkg/catalog/config/constants.go b/pkg/catalog/config/constants.go index b820dc199..f7fca13bf 100644 --- a/pkg/catalog/config/constants.go +++ b/pkg/catalog/config/constants.go @@ -31,7 +31,7 @@ const ( CLIConfigFileName = "config.yaml" ReportingConfigFilename = "reporting-config.yaml" // Version is the current version of nuclei - Version = `v3.4.9` + Version = `v3.4.10` // Directory Names of custom templates CustomS3TemplatesDirName = "s3" CustomGitHubTemplatesDirName = "github" diff --git a/pkg/protocols/protocols.go b/pkg/protocols/protocols.go index 702aa5729..c3ee5c19c 100644 --- a/pkg/protocols/protocols.go +++ b/pkg/protocols/protocols.go @@ -447,21 +447,8 @@ func (e *ExecutorOptions) ApplyNewEngineOptions(n *ExecutorOptions) { return } - // The types.Options include the ExecutionID among other things e.Options = n.Options.Copy() - - // Keep the template-specific fields, but replace the rest - /* - e.TemplateID = n.TemplateID - e.TemplatePath = n.TemplatePath - e.TemplateInfo = n.TemplateInfo - e.TemplateVerifier = n.TemplateVerifier - e.RawTemplate = n.RawTemplate - e.Variables = n.Variables - e.Constants = n.Constants - */ e.Output = n.Output - e.Options = n.Options e.IssuesClient = n.IssuesClient e.Progress = n.Progress e.RateLimiter = n.RateLimiter @@ -470,8 +457,6 @@ func (e *ExecutorOptions) ApplyNewEngineOptions(n *ExecutorOptions) { e.Browser = n.Browser e.Interactsh = n.Interactsh e.HostErrorsCache = n.HostErrorsCache - e.StopAtFirstMatch = n.StopAtFirstMatch - e.ExcludeMatchers = n.ExcludeMatchers e.InputHelper = n.InputHelper e.FuzzParamsFrequency = n.FuzzParamsFrequency e.FuzzStatsDB = n.FuzzStatsDB @@ -479,10 +464,6 @@ func (e *ExecutorOptions) ApplyNewEngineOptions(n *ExecutorOptions) { e.Colorizer = n.Colorizer e.WorkflowLoader = n.WorkflowLoader e.ResumeCfg = n.ResumeCfg - e.ProtocolType = n.ProtocolType - e.Flow = n.Flow - e.IsMultiProtocol = n.IsMultiProtocol - e.templateCtxStore = n.templateCtxStore e.JsCompiler = n.JsCompiler e.AuthProvider = n.AuthProvider e.TemporaryDirectory = n.TemporaryDirectory diff --git a/pkg/templates/compile.go b/pkg/templates/compile.go index 6554e8cde..8a8d69675 100644 --- a/pkg/templates/compile.go +++ b/pkg/templates/compile.go @@ -64,6 +64,13 @@ func Parse(filePath string, preprocessor Preprocessor, options *protocols.Execut newBase.TemplateInfo = tplCopy.Options.TemplateInfo newBase.TemplateVerifier = tplCopy.Options.TemplateVerifier newBase.RawTemplate = tplCopy.Options.RawTemplate + + if tplCopy.Options.Variables.Len() > 0 { + newBase.Variables = tplCopy.Options.Variables + } + if len(tplCopy.Options.Constants) > 0 { + newBase.Constants = tplCopy.Options.Constants + } tplCopy.Options = newBase tplCopy.Options.ApplyNewEngineOptions(options) @@ -156,12 +163,16 @@ func Parse(filePath string, preprocessor Preprocessor, options *protocols.Execut // Compile the workflow request if len(template.Workflows) > 0 { compiled := &template.Workflow - compileWorkflow(filePath, preprocessor, options, compiled, options.WorkflowLoader) + compileWorkflow(filePath, preprocessor, tplCopy.Options, compiled, tplCopy.Options.WorkflowLoader) template.CompiledWorkflow = compiled - template.CompiledWorkflow.Options = options + template.CompiledWorkflow.Options = tplCopy.Options } - // options.Logger.Error().Msgf("returning cached template %s after recompiling %d requests", tplCopy.Options.TemplateID, tplCopy.Requests()) - return template, nil + + if isCachedTemplateValid(template) { + // options.Logger.Error().Msgf("returning cached template %s after recompiling %d requests", tplCopy.Options.TemplateID, tplCopy.Requests()) + return template, nil + } + // else: fallthrough to re-parse template from scratch } } @@ -579,6 +590,50 @@ func parseTemplate(data []byte, srcOptions *protocols.ExecutorOptions) (*Templat return template, nil } +// isCachedTemplateValid validates that a cached template is still usable after +// option updates +func isCachedTemplateValid(template *Template) bool { + // no requests or workflows + if template.Requests() == 0 && len(template.Workflows) == 0 { + return false + } + + // options not initialized + if template.Options == nil { + return false + } + + // executer not available for non-workflow template + if len(template.Workflows) == 0 && template.Executer == nil { + return false + } + + // compiled workflow not available + if len(template.Workflows) > 0 && template.CompiledWorkflow == nil { + return false + } + + // template ID mismatch + if template.Options.TemplateID != template.ID { + return false + } + + // executer exists but no requests or flow available + if template.Executer != nil { + // NOTE(dwisiswant0): This is a basic sanity check since we can't access + // private fields, but we can check requests tho + if template.Requests() == 0 && template.Options.Flow == "" { + return false + } + } + + if template.Options.Options == nil { + return false + } + + return true +} + var ( jsCompiler *compiler.Compiler jsCompilerOnce = sync.OnceFunc(func() {