From b14e63404710fbc28d869fbacf982e0a8b79341e Mon Sep 17 00:00:00 2001
From: Ice3man
Date: Mon, 28 Apr 2025 18:56:35 +0530
Subject: [PATCH 001/135] feat: added support to mssql for execute query
---
pkg/js/generated/ts/mssql.ts | 28 ++++++++++++++++++++
pkg/js/libs/mssql/mssql.go | 51 ++++++++++++++++++++++++++++++++++++
2 files changed, 79 insertions(+)
diff --git a/pkg/js/generated/ts/mssql.ts b/pkg/js/generated/ts/mssql.ts
index 947aa0e9e..632abaa2e 100755
--- a/pkg/js/generated/ts/mssql.ts
+++ b/pkg/js/generated/ts/mssql.ts
@@ -63,5 +63,33 @@ export class MSSQLClient {
}
+ /**
+ * ExecuteQuery connects to MS SQL database using given credentials and executes a query.
+ * It returns the results of the query or an error if something goes wrong.
+ * @example
+ * ```javascript
+ * const mssql = require('nuclei/mssql');
+ * const client = new mssql.MSSQLClient;
+ * const result = client.ExecuteQuery('acme.com', 1433, 'username', 'password', 'master', 'SELECT @@version');
+ * log(to_json(result));
+ * ```
+ */
+ public ExecuteQuery(host: string, port: number, username: string): SQLResult | null | null {
+ return null;
+ }
+
+
+}
+
+
+
+/**
+ * SQLResult Interface
+ */
+export interface SQLResult {
+
+ Count?: number,
+
+ Columns?: string[],
}
diff --git a/pkg/js/libs/mssql/mssql.go b/pkg/js/libs/mssql/mssql.go
index 5660cc2a6..6b2c408d0 100644
--- a/pkg/js/libs/mssql/mssql.go
+++ b/pkg/js/libs/mssql/mssql.go
@@ -11,6 +11,7 @@ import (
_ "github.com/microsoft/go-mssqldb"
"github.com/praetorian-inc/fingerprintx/pkg/plugins/services/mssql"
+ "github.com/projectdiscovery/nuclei/v3/pkg/js/utils"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/protocolstate"
)
@@ -132,3 +133,53 @@ func isMssql(host string, port int) (bool, error) {
}
return false, nil
}
+
+// ExecuteQuery connects to MS SQL database using given credentials and executes a query.
+// It returns the results of the query or an error if something goes wrong.
+// @example
+// ```javascript
+// const mssql = require('nuclei/mssql');
+// const client = new mssql.MSSQLClient;
+// const result = client.ExecuteQuery('acme.com', 1433, 'username', 'password', 'master', 'SELECT @@version');
+// log(to_json(result));
+// ```
+func (c *MSSQLClient) ExecuteQuery(host string, port int, username, password, dbName, query string) (*utils.SQLResult, error) {
+ if host == "" || port <= 0 {
+ return nil, fmt.Errorf("invalid host or port")
+ }
+ if !protocolstate.IsHostAllowed(host) {
+ // host is not valid according to network policy
+ return nil, protocolstate.ErrHostDenied.Msgf(host)
+ }
+
+ target := net.JoinHostPort(host, fmt.Sprintf("%d", port))
+
+ connString := fmt.Sprintf("sqlserver://%s:%s@%s?database=%s&connection+timeout=30",
+ url.PathEscape(username),
+ url.PathEscape(password),
+ target,
+ dbName)
+
+ db, err := sql.Open("sqlserver", connString)
+ if err != nil {
+ return nil, err
+ }
+ defer db.Close()
+
+ db.SetMaxOpenConns(1)
+ db.SetMaxIdleConns(0)
+
+ rows, err := db.Query(query)
+ if err != nil {
+ return nil, err
+ }
+
+ data, err := utils.UnmarshalSQLRows(rows)
+ if err != nil {
+ if data != nil && len(data.Rows) > 0 {
+ return data, nil
+ }
+ return nil, err
+ }
+ return data, nil
+}
From 088425d3510eec19aaf0a6414e418ce904703932 Mon Sep 17 00:00:00 2001
From: Mzack9999
Date: Thu, 1 May 2025 22:44:29 +0200
Subject: [PATCH 002/135] adding mssql check
---
pkg/js/libs/mssql/mssql.go | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/pkg/js/libs/mssql/mssql.go b/pkg/js/libs/mssql/mssql.go
index 6b2c408d0..938318a85 100644
--- a/pkg/js/libs/mssql/mssql.go
+++ b/pkg/js/libs/mssql/mssql.go
@@ -154,6 +154,14 @@ func (c *MSSQLClient) ExecuteQuery(host string, port int, username, password, db
target := net.JoinHostPort(host, fmt.Sprintf("%d", port))
+ ok, err := c.IsMssql(host, port)
+ if err != nil {
+ return nil, err
+ }
+ if !ok {
+ return nil, fmt.Errorf("not a mssql service")
+ }
+
connString := fmt.Sprintf("sqlserver://%s:%s@%s?database=%s&connection+timeout=30",
url.PathEscape(username),
url.PathEscape(password),
From a7a009084c0dc0b74772a1f3bee56829af6a8205 Mon Sep 17 00:00:00 2001
From: 23kbps <86248851+23kbps@users.noreply.github.com>
Date: Sat, 3 May 2025 15:28:18 +0700
Subject: [PATCH 003/135] Fix ingress template in helm chart
---
helm/templates/interactsh-ingress.yaml | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/helm/templates/interactsh-ingress.yaml b/helm/templates/interactsh-ingress.yaml
index 9c80eb4fe..58cc3701d 100644
--- a/helm/templates/interactsh-ingress.yaml
+++ b/helm/templates/interactsh-ingress.yaml
@@ -1,6 +1,7 @@
{{- if .Values.interactsh.ingress.enabled -}}
{{- $fullName := include "nuclei.fullname" . -}}
-{{- $svcPort := .Values.service.port -}}
+{{- $svcPort := .Values.interactsh.service.port -}}
+{{- $svcName := .Values.interactsh.service.name -}}
{{- if and .Values.interactsh.ingress.className (not (semverCompare ">=1.20-0" .Capabilities.KubeVersion.GitVersion)) }}
{{- if not (hasKey .Values.interactsh.ingress.annotations "kubernetes.io/ingress.class") }}
{{- $_ := set .Values.interactsh.ingress.annotations "kubernetes.io/ingress.class" .Values.interactsh.ingress.className}}
@@ -49,11 +50,11 @@ spec:
backend:
{{- if semverCompare ">=1.20-0" $.Capabilities.KubeVersion.GitVersion }}
service:
- name: {{ $fullName }}
+ name: {{ $svcName }}
port:
number: {{ $svcPort }}
{{- else }}
- serviceName: {{ $fullName }}
+ serviceName: {{ $svcName }}
servicePort: {{ $svcPort }}
{{- end }}
{{- end }}
From 4801cc65ef40a681eaa81f14ebba9a9952191c81 Mon Sep 17 00:00:00 2001
From: Sandeep Singh
Date: Wed, 7 May 2025 17:22:15 +0530
Subject: [PATCH 004/135] feat: fixed max-host-error blocking + progress
mismatch + misc (#6193)
* feat: fixed max-host-error blocking wrong port for template with error
* feat: log total results with time taken at end of execution
* bugfix: skip non-executed requests with progress in flow protocol
* feat: fixed request calculation in http protocol for progress
* misc adjustments
---------
Co-authored-by: Ice3man
---
internal/runner/runner.go | 27 +++++++-
pkg/core/execute_options.go | 2 +
pkg/output/multi_writer.go | 10 +++
pkg/output/output.go | 9 +++
pkg/output/output_stats.go | 3 +
pkg/progress/progress.go | 4 +-
.../common/hosterrorscache/hosterrorscache.go | 18 ++++--
pkg/protocols/http/build_request.go | 8 ---
pkg/protocols/http/http.go | 21 +-----
pkg/protocols/http/request.go | 14 ++--
pkg/protocols/http/request_generator.go | 64 +++++++++++++++++++
pkg/testutils/testutils.go | 4 ++
pkg/tmplexec/flow/flow_executor.go | 16 +++++
pkg/tmplexec/flow/flow_internal.go | 9 +++
14 files changed, 168 insertions(+), 41 deletions(-)
diff --git a/internal/runner/runner.go b/internal/runner/runner.go
index 85fe0ea75..424d27116 100644
--- a/internal/runner/runner.go
+++ b/internal/runner/runner.go
@@ -702,6 +702,7 @@ func (r *Runner) RunEnumeration() error {
}()
}
+ now := time.Now()
enumeration := false
var results *atomic.Bool
results, err = r.runStandardEnumeration(executorOpts, store, executorEngine)
@@ -725,11 +726,17 @@ func (r *Runner) RunEnumeration() error {
}
r.fuzzFrequencyCache.Close()
+ r.progress.Stop()
+ timeTaken := time.Since(now)
// todo: error propagation without canonical straight error check is required by cloud?
// use safe dereferencing to avoid potential panics in case of previous unchecked errors
if v := ptrutil.Safe(results); !v.Load() {
- gologger.Info().Msgf("No results found. Better luck next time!")
+ gologger.Info().Msgf("Scan completed in %s. No results found.", shortDur(timeTaken))
+ } else {
+ matchCount := r.output.ResultCount()
+ gologger.Info().Msgf("Scan completed in %s. %d matches found.", shortDur(timeTaken), matchCount)
}
+
// check if a passive scan was requested but no target was provided
if r.options.OfflineHTTP && len(r.options.Targets) == 0 && r.options.TargetsFilePath == "" {
return errors.Wrap(err, "missing required input (http response) to run passive templates")
@@ -738,6 +745,24 @@ func (r *Runner) RunEnumeration() error {
return err
}
+func shortDur(d time.Duration) string {
+ if d < time.Minute {
+ return d.String()
+ }
+
+ // Truncate to the nearest minute
+ d = d.Truncate(time.Minute)
+ s := d.String()
+
+ if strings.HasSuffix(s, "m0s") {
+ s = s[:len(s)-2]
+ }
+ if strings.HasSuffix(s, "h0m") {
+ s = s[:len(s)-2]
+ }
+ return s
+}
+
func (r *Runner) isInputNonHTTP() bool {
var nonURLInput bool
r.inputProvider.Iterate(func(value *contextargs.MetaInput) bool {
diff --git a/pkg/core/execute_options.go b/pkg/core/execute_options.go
index aa47bc44f..fae26b456 100644
--- a/pkg/core/execute_options.go
+++ b/pkg/core/execute_options.go
@@ -110,6 +110,8 @@ func (e *Engine) executeTemplateSpray(ctx context.Context, templatesList []*temp
defer wp.Wait()
for _, template := range templatesList {
+ template := template
+
select {
case <-ctx.Done():
return results
diff --git a/pkg/output/multi_writer.go b/pkg/output/multi_writer.go
index 8ea729b4b..17b1c725a 100644
--- a/pkg/output/multi_writer.go
+++ b/pkg/output/multi_writer.go
@@ -65,3 +65,13 @@ func (mw *MultiWriter) RequestStatsLog(statusCode, response string) {
writer.RequestStatsLog(statusCode, response)
}
}
+
+func (mw *MultiWriter) ResultCount() int {
+ count := 0
+ for _, writer := range mw.writers {
+ if count := writer.ResultCount(); count > 0 {
+ return count
+ }
+ }
+ return count
+}
diff --git a/pkg/output/output.go b/pkg/output/output.go
index 5c84bed30..e85774b83 100644
--- a/pkg/output/output.go
+++ b/pkg/output/output.go
@@ -54,6 +54,8 @@ type Writer interface {
RequestStatsLog(statusCode, response string)
// WriteStoreDebugData writes the request/response debug data to file
WriteStoreDebugData(host, templateID, eventType string, data string)
+ // ResultCount returns the total number of results written
+ ResultCount() int
}
// StandardWriter is a writer writing output to file and screen for results.
@@ -79,6 +81,8 @@ type StandardWriter struct {
// JSONLogRequestHook is a hook that can be used to log request/response
// when using custom server code with output
JSONLogRequestHook func(*JSONLogRequest)
+
+ resultCount atomic.Int32
}
var _ Writer = &StandardWriter{}
@@ -287,6 +291,10 @@ func NewStandardWriter(options *types.Options) (*StandardWriter, error) {
return writer, nil
}
+func (w *StandardWriter) ResultCount() int {
+ return int(w.resultCount.Load())
+}
+
// Write writes the event to file and/or screen.
func (w *StandardWriter) Write(event *ResultEvent) error {
// Enrich the result event with extra metadata on the template-path and url.
@@ -336,6 +344,7 @@ func (w *StandardWriter) Write(event *ResultEvent) error {
_, _ = w.outputFile.Write([]byte("\n"))
}
}
+ w.resultCount.Add(1)
return nil
}
diff --git a/pkg/output/output_stats.go b/pkg/output/output_stats.go
index 7b0d509cd..68a234d85 100644
--- a/pkg/output/output_stats.go
+++ b/pkg/output/output_stats.go
@@ -49,3 +49,6 @@ func (tw *StatsOutputWriter) RequestStatsLog(statusCode, response string) {
tw.Tracker.TrackStatusCode(statusCode)
tw.Tracker.TrackWAFDetected(response)
}
+func (tw *StatsOutputWriter) ResultCount() int {
+ return 0
+}
diff --git a/pkg/progress/progress.go b/pkg/progress/progress.go
index 1ffb22cee..853fb103d 100644
--- a/pkg/progress/progress.go
+++ b/pkg/progress/progress.go
@@ -120,9 +120,7 @@ func (p *StatsTicker) IncrementRequests() {
// SetRequests sets the counter by incrementing it with a delta
func (p *StatsTicker) SetRequests(count uint64) {
- value, _ := p.stats.GetCounter("requests")
- delta := count - value
- p.stats.IncrementCounter("requests", int(delta))
+ p.stats.IncrementCounter("requests", int(count))
}
// IncrementMatched increments the matched counter by 1.
diff --git a/pkg/protocols/common/hosterrorscache/hosterrorscache.go b/pkg/protocols/common/hosterrorscache/hosterrorscache.go
index 3943eef7e..3039dbdf0 100644
--- a/pkg/protocols/common/hosterrorscache/hosterrorscache.go
+++ b/pkg/protocols/common/hosterrorscache/hosterrorscache.go
@@ -89,6 +89,9 @@ func (c *Cache) NormalizeCacheValue(value string) string {
u, err := url.ParseRequestURI(value)
if err != nil || u.Host == "" {
+ if strings.Contains(value, ":") {
+ return normalizedValue
+ }
u, err2 := url.ParseRequestURI("https://" + value)
if err2 != nil {
return normalizedValue
@@ -236,14 +239,19 @@ func (c *Cache) GetKeyFromContext(ctx *contextargs.Context, err error) string {
// should be reflected in contextargs but it is not yet reflected in some cases
// and needs refactor of ScanContext + ContextArgs to achieve that
// i.e why we use real address from error if present
- address := ctx.MetaInput.Address()
- // get address override from error
+ var address string
+
+ // 1. the address carried inside the error (if the transport sets it)
if err != nil {
- tmp := errkit.GetAttrValue(err, "address")
- if tmp.Any() != nil {
- address = tmp.String()
+ if v := errkit.GetAttrValue(err, "address"); v.Any() != nil {
+ address = v.String()
}
}
+
+ if address == "" {
+ address = ctx.MetaInput.Address()
+ }
+
finalValue := c.NormalizeCacheValue(address)
return finalValue
}
diff --git a/pkg/protocols/http/build_request.go b/pkg/protocols/http/build_request.go
index 3cde12d88..1cb9553c9 100644
--- a/pkg/protocols/http/build_request.go
+++ b/pkg/protocols/http/build_request.go
@@ -123,14 +123,6 @@ func (g *generatedRequest) URL() string {
return ""
}
-// Total returns the total number of requests for the generator
-func (r *requestGenerator) Total() int {
- if r.payloadIterator != nil {
- return len(r.request.Raw) * r.payloadIterator.Remaining()
- }
- return len(r.request.Path)
-}
-
// Make creates a http request for the provided input.
// It returns ErrNoMoreRequests as error when all the requests have been exhausted.
func (r *requestGenerator) Make(ctx context.Context, input *contextargs.Context, reqData string, payloads, dynamicValues map[string]interface{}) (gr *generatedRequest, err error) {
diff --git a/pkg/protocols/http/http.go b/pkg/protocols/http/http.go
index 78710f79c..0b30a7408 100644
--- a/pkg/protocols/http/http.go
+++ b/pkg/protocols/http/http.go
@@ -501,7 +501,6 @@ func (request *Request) Compile(options *protocols.ExecutorOptions) error {
request.Threads = options.GetThreadsForNPayloadRequests(request.Requests(), request.Threads)
}
}
-
return nil
}
@@ -517,24 +516,8 @@ func (request *Request) RebuildGenerator() error {
// Requests returns the total number of requests the YAML rule will perform
func (request *Request) Requests() int {
- if request.generator != nil {
- payloadRequests := request.generator.NewIterator().Total()
- if len(request.Raw) > 0 {
- payloadRequests = payloadRequests * len(request.Raw)
- }
- if len(request.Path) > 0 {
- payloadRequests = payloadRequests * len(request.Path)
- }
- return payloadRequests
- }
- if len(request.Raw) > 0 {
- requests := len(request.Raw)
- if requests == 1 && request.RaceNumberRequests != 0 {
- requests *= request.RaceNumberRequests
- }
- return requests
- }
- return len(request.Path)
+ generator := request.newGenerator(false)
+ return generator.Total()
}
const (
diff --git a/pkg/protocols/http/request.go b/pkg/protocols/http/request.go
index 2cc32f5bf..6d8ad3e1d 100644
--- a/pkg/protocols/http/request.go
+++ b/pkg/protocols/http/request.go
@@ -41,7 +41,6 @@ import (
"github.com/projectdiscovery/rawhttp"
convUtil "github.com/projectdiscovery/utils/conversion"
"github.com/projectdiscovery/utils/errkit"
- errorutil "github.com/projectdiscovery/utils/errors"
httpUtils "github.com/projectdiscovery/utils/http"
"github.com/projectdiscovery/utils/reader"
sliceutil "github.com/projectdiscovery/utils/slice"
@@ -484,7 +483,6 @@ func (request *Request) ExecuteWithResults(input *contextargs.Context, dynamicVa
if err == types.ErrNoMoreRequests {
return true, nil
}
- request.options.Progress.IncrementFailedRequestsBy(int64(generator.Total()))
return true, err
}
// ideally if http template used a custom port or hostname
@@ -541,14 +539,19 @@ func (request *Request) ExecuteWithResults(input *contextargs.Context, dynamicVa
if errors.Is(execReqErr, ErrMissingVars) {
return true, nil
}
+
if execReqErr != nil {
+ request.markHostError(updatedInput, execReqErr)
+
// if applicable mark the host as unresponsive
- requestErr = errorutil.NewWithErr(execReqErr).Msgf("got err while executing %v", generatedHttpRequest.URL())
+ reqKitErr := errkit.FromError(execReqErr)
+ reqKitErr.Msgf("got err while executing %v", generatedHttpRequest.URL())
+
+ requestErr = reqKitErr
request.options.Progress.IncrementFailedRequestsBy(1)
} else {
request.options.Progress.IncrementRequests()
}
- request.markHostError(updatedInput, execReqErr)
// If this was a match, and we want to stop at first match, skip all further requests.
shouldStopAtFirstMatch := generatedHttpRequest.original.options.Options.StopAtFirstMatch || generatedHttpRequest.original.options.StopAtFirstMatch || request.StopAtFirstMatch
@@ -585,6 +588,7 @@ func (request *Request) ExecuteWithResults(input *contextargs.Context, dynamicVa
requestErr = gotErr
}
if skip || gotErr != nil {
+ request.options.Progress.SetRequests(uint64(generator.Remaining() + 1))
break
}
}
@@ -1212,7 +1216,7 @@ func (request *Request) newContext(input *contextargs.Context) context.Context {
// markHostError checks if the error is a unreponsive host error and marks it
func (request *Request) markHostError(input *contextargs.Context, err error) {
- if request.options.HostErrorsCache != nil {
+ if request.options.HostErrorsCache != nil && err != nil {
request.options.HostErrorsCache.MarkFailedOrRemove(request.options.ProtocolType.String(), input, err)
}
}
diff --git a/pkg/protocols/http/request_generator.go b/pkg/protocols/http/request_generator.go
index b15df1be9..4c4c701a8 100644
--- a/pkg/protocols/http/request_generator.go
+++ b/pkg/protocols/http/request_generator.go
@@ -135,3 +135,67 @@ func (r *requestGenerator) hasMarker(request string, mark flowMark) bool {
fo, hasOverrides := parseFlowAnnotations(request)
return hasOverrides && fo == mark
}
+
+// Remaining returns the number of requests that are still left to be
+// generated (and therefore to be sent) by this generator.
+func (r *requestGenerator) Remaining() int {
+ var sequence []string
+ switch {
+ case len(r.request.Path) > 0:
+ sequence = r.request.Path
+ case len(r.request.Raw) > 0:
+ sequence = r.request.Raw
+ default:
+ return 0
+ }
+
+ remainingInCurrentPass := 0
+ for i := r.currentIndex; i < len(sequence); i++ {
+ if !r.hasMarker(sequence[i], Once) {
+ remainingInCurrentPass++
+ }
+ }
+
+ if r.payloadIterator == nil {
+ return remainingInCurrentPass
+ }
+
+ numRemainingPayloadSets := r.payloadIterator.Remaining()
+ totalValidInSequence := 0
+ for _, req := range sequence {
+ if !r.hasMarker(req, Once) {
+ totalValidInSequence++
+ }
+ }
+
+ // Total remaining = remaining in current pass + (remaining payload sets * requests per full pass)
+ return remainingInCurrentPass + numRemainingPayloadSets*totalValidInSequence
+}
+
+func (r *requestGenerator) Total() int {
+ var sequence []string
+ switch {
+ case len(r.request.Path) > 0:
+ sequence = r.request.Path
+ case len(r.request.Raw) > 0:
+ sequence = r.request.Raw
+ default:
+ return 0
+ }
+
+ applicableRequests := 0
+ additionalRequests := 0
+ for _, request := range sequence {
+ if !r.hasMarker(request, Once) {
+ applicableRequests++
+ } else {
+ additionalRequests++
+ }
+ }
+
+ if r.payloadIterator == nil {
+ return applicableRequests + additionalRequests
+ }
+
+ return (applicableRequests * r.payloadIterator.Total()) + additionalRequests
+}
diff --git a/pkg/testutils/testutils.go b/pkg/testutils/testutils.go
index d59af2f7b..5f791c2c1 100644
--- a/pkg/testutils/testutils.go
+++ b/pkg/testutils/testutils.go
@@ -133,6 +133,10 @@ func (m *MockOutputWriter) Colorizer() aurora.Aurora {
return m.aurora
}
+func (m *MockOutputWriter) ResultCount() int {
+ return 0
+}
+
// Write writes the event to file and/or screen.
func (m *MockOutputWriter) Write(result *output.ResultEvent) error {
if m.WriteCallback != nil {
diff --git a/pkg/tmplexec/flow/flow_executor.go b/pkg/tmplexec/flow/flow_executor.go
index 6e71cf840..62112e0f8 100644
--- a/pkg/tmplexec/flow/flow_executor.go
+++ b/pkg/tmplexec/flow/flow_executor.go
@@ -51,6 +51,8 @@ type FlowExecutor struct {
// these are keys whose values are meant to be flatten before executing
// a request ex: if dynamic extractor returns ["value"] it will be converted to "value"
flattenKeys []string
+
+ executed *mapsutil.SyncLockMap[string, struct{}]
}
// NewFlowExecutor creates a new flow executor from a list of requests
@@ -98,6 +100,7 @@ func NewFlowExecutor(requests []protocols.Request, ctx *scan.ScanContext, option
results: results,
ctx: ctx,
program: program,
+ executed: mapsutil.NewSyncLockMap[string, struct{}](),
}
return f, nil
}
@@ -243,6 +246,7 @@ func (f *FlowExecutor) ExecuteWithResults(ctx *scan.ScanContext) error {
// pass flow and execute the js vm and handle errors
_, err := runtime.RunProgram(f.program)
+ f.reconcileProgress()
if err != nil {
ctx.LogError(err)
return errorutil.NewWithErr(err).Msgf("failed to execute flow\n%v\n", f.options.Flow)
@@ -256,6 +260,18 @@ func (f *FlowExecutor) ExecuteWithResults(ctx *scan.ScanContext) error {
return nil
}
+func (f *FlowExecutor) reconcileProgress() {
+ for proto, list := range f.allProtocols {
+ for idx, req := range list {
+ key := requestKey(proto, req, strconv.Itoa(idx+1))
+ if _, seen := f.executed.Get(key); !seen {
+ // never executed → pretend it finished so that stats match
+ f.options.Progress.SetRequests(uint64(req.Requests()))
+ }
+ }
+ }
+}
+
// GetRuntimeErrors returns all runtime errors (i.e errors from all protocol combined)
func (f *FlowExecutor) GetRuntimeErrors() error {
errs := []error{}
diff --git a/pkg/tmplexec/flow/flow_internal.go b/pkg/tmplexec/flow/flow_internal.go
index 92a852f9d..03cc29596 100644
--- a/pkg/tmplexec/flow/flow_internal.go
+++ b/pkg/tmplexec/flow/flow_internal.go
@@ -75,6 +75,8 @@ func (f *FlowExecutor) requestExecutor(runtime *goja.Runtime, reqMap mapsutil.Ma
}
}
err := req.ExecuteWithResults(inputItem, output.InternalEvent(f.options.GetTemplateCtx(f.ctx.Input.MetaInput).GetAll()), output.InternalEvent{}, f.protocolResultCallback(req, matcherStatus, opts))
+ // Mark the request as seen
+ _ = f.executed.Set(requestKey(opts.protoName, req, id), struct{}{})
if err != nil {
index := id
err = f.allErrs.Set(opts.protoName+":"+index, err)
@@ -86,6 +88,13 @@ func (f *FlowExecutor) requestExecutor(runtime *goja.Runtime, reqMap mapsutil.Ma
return matcherStatus.Load()
}
+func requestKey(proto string, req protocols.Request, id string) string {
+ if id == "" {
+ id = req.GetID()
+ }
+ return proto + ":" + id
+}
+
// protocolResultCallback returns a callback that is executed
// after execution of each protocol request
func (f *FlowExecutor) protocolResultCallback(req protocols.Request, matcherStatus *atomic.Bool, _ *ProtoOptions) func(result *output.InternalWrappedEvent) {
From 3bb44d588f7c3ca27d81bf117a0ee1363c8d8f0f Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 7 May 2025 18:04:33 +0530
Subject: [PATCH 005/135] chore(deps): bump the modules group with 4 updates
(#6207)
Bumps the modules group with 4 updates: [github.com/projectdiscovery/retryablehttp-go](https://github.com/projectdiscovery/retryablehttp-go), [github.com/projectdiscovery/gologger](https://github.com/projectdiscovery/gologger), [github.com/projectdiscovery/wappalyzergo](https://github.com/projectdiscovery/wappalyzergo) and [github.com/projectdiscovery/cdncheck](https://github.com/projectdiscovery/cdncheck).
Updates `github.com/projectdiscovery/retryablehttp-go` from 1.0.110 to 1.0.111
- [Release notes](https://github.com/projectdiscovery/retryablehttp-go/releases)
- [Commits](https://github.com/projectdiscovery/retryablehttp-go/compare/v1.0.110...v1.0.111)
Updates `github.com/projectdiscovery/gologger` from 1.1.53 to 1.1.54
- [Release notes](https://github.com/projectdiscovery/gologger/releases)
- [Commits](https://github.com/projectdiscovery/gologger/compare/v1.1.53...v1.1.54)
Updates `github.com/projectdiscovery/wappalyzergo` from 0.2.25 to 0.2.27
- [Release notes](https://github.com/projectdiscovery/wappalyzergo/releases)
- [Commits](https://github.com/projectdiscovery/wappalyzergo/compare/v0.2.25...v0.2.27)
Updates `github.com/projectdiscovery/cdncheck` from 1.1.15 to 1.1.17
- [Release notes](https://github.com/projectdiscovery/cdncheck/releases)
- [Changelog](https://github.com/projectdiscovery/cdncheck/blob/main/.goreleaser.yaml)
- [Commits](https://github.com/projectdiscovery/cdncheck/compare/v1.1.15...v1.1.17)
---
updated-dependencies:
- dependency-name: github.com/projectdiscovery/retryablehttp-go
dependency-version: 1.0.111
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: modules
- dependency-name: github.com/projectdiscovery/gologger
dependency-version: 1.1.54
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: modules
- dependency-name: github.com/projectdiscovery/wappalyzergo
dependency-version: 0.2.27
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: modules
- dependency-name: github.com/projectdiscovery/cdncheck
dependency-version: 1.1.17
dependency-type: indirect
update-type: version-update:semver-patch
dependency-group: modules
...
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
go.mod | 11 ++++-------
go.sum | 30 ++++++++----------------------
2 files changed, 12 insertions(+), 29 deletions(-)
diff --git a/go.mod b/go.mod
index 7f5efa7f5..820548938 100644
--- a/go.mod
+++ b/go.mod
@@ -27,7 +27,7 @@ require (
github.com/projectdiscovery/interactsh v1.2.4
github.com/projectdiscovery/rawhttp v0.1.90
github.com/projectdiscovery/retryabledns v1.0.99
- github.com/projectdiscovery/retryablehttp-go v1.0.110
+ github.com/projectdiscovery/retryablehttp-go v1.0.111
github.com/projectdiscovery/yamldoc-go v1.0.6
github.com/remeh/sizedwaitgroup v1.0.0
github.com/rs/xid v1.6.0
@@ -90,7 +90,7 @@ require (
github.com/projectdiscovery/fasttemplate v0.0.2
github.com/projectdiscovery/go-smb2 v0.0.0-20240129202741-052cc450c6cb
github.com/projectdiscovery/goflags v0.1.74
- github.com/projectdiscovery/gologger v1.1.53
+ github.com/projectdiscovery/gologger v1.1.54
github.com/projectdiscovery/gostruct v0.0.2
github.com/projectdiscovery/gozero v0.0.3
github.com/projectdiscovery/httpx v1.7.0
@@ -103,7 +103,7 @@ require (
github.com/projectdiscovery/uncover v1.0.10
github.com/projectdiscovery/useragent v0.0.100
github.com/projectdiscovery/utils v0.4.18
- github.com/projectdiscovery/wappalyzergo v0.2.25
+ github.com/projectdiscovery/wappalyzergo v0.2.27
github.com/redis/go-redis/v9 v9.1.0
github.com/seh-msft/burpxml v1.0.1
github.com/shurcooL/graphql v0.0.0-20230722043721-ed46e5a46466
@@ -202,7 +202,6 @@ require (
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/mackerelio/go-osstat v0.2.4 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
- github.com/mholt/archiver/v3 v3.5.1 // indirect
github.com/minio/selfupdate v0.6.1-0.20230907112617-f11e74f84ca7 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
@@ -221,7 +220,7 @@ require (
github.com/pjbgf/sha1cd v0.3.0 // indirect
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
github.com/projectdiscovery/asnmap v1.1.1 // indirect
- github.com/projectdiscovery/cdncheck v1.1.15 // indirect
+ github.com/projectdiscovery/cdncheck v1.1.17 // indirect
github.com/projectdiscovery/freeport v0.0.7 // indirect
github.com/projectdiscovery/ldapserver v1.0.2-0.20240219154113-dcc758ebc0cb // indirect
github.com/projectdiscovery/machineid v0.0.0-20240226150047-2e2c51e35983 // indirect
@@ -363,10 +362,8 @@ require (
github.com/kevinburke/ssh_config v1.2.0 // indirect
github.com/labstack/gommon v0.4.2 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
- github.com/nwaples/rardecode v1.1.3 // indirect
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
github.com/xanzy/ssh-agent v0.3.3 // indirect
- github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
)
diff --git a/go.sum b/go.sum
index 42493e717..64946396f 100644
--- a/go.sum
+++ b/go.sum
@@ -116,7 +116,6 @@ github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 h1:Kk6a4nehpJ3Uu
github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4=
github.com/alitto/pond v1.9.2 h1:9Qb75z/scEZVCoSU+osVmQ0I0JOeLfdTDafrbcJ8CLs=
github.com/alitto/pond v1.9.2/go.mod h1:xQn3P/sHTYcU/1BR3i86IGIrilcrGC2LiS+E2+CJWsI=
-github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA=
github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA=
github.com/andybalholm/cascadia v1.3.3 h1:AG2YHrzJIm4BZ19iwJ/DAua6Btl3IwJX+VI4kktS1LM=
@@ -319,7 +318,6 @@ github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA
github.com/dop251/goja_nodejs v0.0.0-20211022123610-8dd9abb0616d/go.mod h1:DngW8aVqWbuLRMHItjPUyqdj+HWPvnQe8V8y1nDpIbM=
github.com/dop251/goja_nodejs v0.0.0-20230821135201-94e508132562 h1:ObbB2tzHWWAxzsG5futqeq2Ual2zYlo/+eMkSc5sn8w=
github.com/dop251/goja_nodejs v0.0.0-20230821135201-94e508132562/go.mod h1:X2TOTJ+Uamd454RFp7ig2tmP3hQg0Z2Qk8gbVQmU0mk=
-github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s=
github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 h1:2tV76y6Q9BB+NEBasnqvs7e49aEBFI8ejC89PSnWH+4=
github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s=
github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY=
@@ -485,7 +483,6 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
-github.com/golang/snappy v0.0.2/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
@@ -665,7 +662,6 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o
github.com/kitabisa/go-ci v1.0.3 h1:JmIUIvcercRQc/9x/v02ydCCqU4MadSHaNaOF8T2pGA=
github.com/kitabisa/go-ci v1.0.3/go.mod h1:e3wBSzaJbcifXrr/Gw2ZBLn44MmeqP5WySwXyHlCK/U=
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
-github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
@@ -673,7 +669,6 @@ github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa02
github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg=
github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
-github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU=
github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
@@ -740,8 +735,6 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/mholt/acmez v1.2.0 h1:1hhLxSgY5FvH5HCnGUuwbKY2VQVo8IU7rxXKSnZ7F30=
github.com/mholt/acmez v1.2.0/go.mod h1:VT9YwH1xgNX1kmYY89gY8xPJC84BFAisjo8Egigt4kE=
-github.com/mholt/archiver/v3 v3.5.1 h1:rDjOBX9JSF5BvoJGvjqK479aL70qh9DIpZCl+k7Clwo=
-github.com/mholt/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4=
github.com/mholt/archives v0.1.0 h1:FacgJyrjiuyomTuNA92X5GyRBRZjE43Y/lrzKIlF35Q=
github.com/mholt/archives v0.1.0/go.mod h1:j/Ire/jm42GN7h90F5kzj6hf6ZFzEH66de+hmjEKu+I=
github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk=
@@ -795,9 +788,6 @@ github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzE
github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
-github.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
-github.com/nwaples/rardecode v1.1.3 h1:cWCaZwfM5H7nAD6PyEdcVnczzV8i/JtotnyW/dD9lEc=
-github.com/nwaples/rardecode v1.1.3/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
github.com/nwaples/rardecode/v2 v2.0.1 h1:3MN6/R+Y4c7e+21U3yhWuUcf72sYmcmr6jtiuAVSH1A=
github.com/nwaples/rardecode/v2 v2.0.1/go.mod h1:yntwv/HfMc/Hbvtq9I19D1n58te3h6KsqCf3GxyfBGY=
github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY=
@@ -842,7 +832,6 @@ github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX
github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw=
github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
-github.com/pierrec/lz4/v4 v4.1.2/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU=
github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
@@ -865,8 +854,8 @@ github.com/projectdiscovery/asnmap v1.1.1 h1:ImJiKIaACOT7HPx4Pabb5dksolzaFYsD1kI
github.com/projectdiscovery/asnmap v1.1.1/go.mod h1:QT7jt9nQanj+Ucjr9BqGr1Q2veCCKSAVyUzLXfEcQ60=
github.com/projectdiscovery/blackrock v0.0.1 h1:lHQqhaaEFjgf5WkuItbpeCZv2DUIE45k0VbGJyft6LQ=
github.com/projectdiscovery/blackrock v0.0.1/go.mod h1:ANUtjDfaVrqB453bzToU+YB4cUbvBRpLvEwoWIwlTss=
-github.com/projectdiscovery/cdncheck v1.1.15 h1:rRs3LW2MP7V8QeONVRYce6RhDcWp83O+AWmt+QQ4mBM=
-github.com/projectdiscovery/cdncheck v1.1.15/go.mod h1:dFEGsG0qAJY0AaRr2N1BY0OtZiTxS4kYeT5+OkF8t1U=
+github.com/projectdiscovery/cdncheck v1.1.17 h1:YSqKk05+UGSxmPIp7tlCvRegF63FUqO+mA2Wl/Je3gA=
+github.com/projectdiscovery/cdncheck v1.1.17/go.mod h1:dFEGsG0qAJY0AaRr2N1BY0OtZiTxS4kYeT5+OkF8t1U=
github.com/projectdiscovery/clistats v0.1.1 h1:8mwbdbwTU4aT88TJvwIzTpiNeow3XnAB72JIg66c8wE=
github.com/projectdiscovery/clistats v0.1.1/go.mod h1:4LtTC9Oy//RiuT1+76MfTg8Hqs7FQp1JIGBM3nHK6a0=
github.com/projectdiscovery/dsl v0.4.2 h1:9PnD6EyDAZFvpQmJ0700gkQ96Fqlzl+lnTdcVHAagXI=
@@ -881,8 +870,8 @@ github.com/projectdiscovery/go-smb2 v0.0.0-20240129202741-052cc450c6cb h1:rutG90
github.com/projectdiscovery/go-smb2 v0.0.0-20240129202741-052cc450c6cb/go.mod h1:FLjF1DmZ+POoGEiIQdWuYVwS++C/GwpX8YaCsTSm1RY=
github.com/projectdiscovery/goflags v0.1.74 h1:n85uTRj5qMosm0PFBfsvOL24I7TdWRcWq/1GynhXS7c=
github.com/projectdiscovery/goflags v0.1.74/go.mod h1:UMc9/7dFz2oln+10tv6cy+7WZKTHf9UGhaNkF95emh4=
-github.com/projectdiscovery/gologger v1.1.53 h1:Er5nty/kifUDSr9MLgi8pzr0bveC+jco76Ittlg/AlM=
-github.com/projectdiscovery/gologger v1.1.53/go.mod h1:PLaWBQIjfIaSAfAVAJ3MZctIyStGcI3CpaN7NLIejo8=
+github.com/projectdiscovery/gologger v1.1.54 h1:WMzvJ8j/4gGfPKpCttSTaYCVDU1MWQSJnk3wU8/U6Ws=
+github.com/projectdiscovery/gologger v1.1.54/go.mod h1:vza/8pe2OKOt+ujFWncngknad1XWr8EnLKlbcejOyUE=
github.com/projectdiscovery/gostruct v0.0.2 h1:s8gP8ApugGM4go1pA+sVlPDXaWqNP5BBDDSv7VEdG1M=
github.com/projectdiscovery/gostruct v0.0.2/go.mod h1:H86peL4HKwMXcQQtEa6lmC8FuD9XFt6gkNR0B/Mu5PE=
github.com/projectdiscovery/gozero v0.0.3 h1:tsYkrSvWw4WdIUJyisd4MB1vRiw1X57TuVVk3p8Z3G8=
@@ -911,8 +900,8 @@ github.com/projectdiscovery/rdap v0.9.1-0.20221108103045-9865884d1917 h1:m03X4gB
github.com/projectdiscovery/rdap v0.9.1-0.20221108103045-9865884d1917/go.mod h1:JxXtZC9e195awe7EynrcnBJmFoad/BNDzW9mzFkK8Sg=
github.com/projectdiscovery/retryabledns v1.0.99 h1:DJ6TewgkwqJozDOPXhoOy/cdtuzJzbIQ/BFfWNYzHpw=
github.com/projectdiscovery/retryabledns v1.0.99/go.mod h1:pkPYuqtxhX6z1pYL+O6s4Lg7ubINt2jg12gsaW9O3kY=
-github.com/projectdiscovery/retryablehttp-go v1.0.110 h1:qO3rkuoG4/N9KlxmfnpmdCAU2JDTq6EQzwUzvVaER/o=
-github.com/projectdiscovery/retryablehttp-go v1.0.110/go.mod h1:kM6zKIqV0uRly7aTImm+3v7avRR3L2zrmgAEMNfxlbo=
+github.com/projectdiscovery/retryablehttp-go v1.0.111 h1:HzkVN0IyC0RfVylBlgNoqaQgVvuUEvbDEVbpGyD/Y9M=
+github.com/projectdiscovery/retryablehttp-go v1.0.111/go.mod h1:Tl6noELU9RpjwywMDw722HB038QXohl90g2ZtKSqbCI=
github.com/projectdiscovery/sarif v0.0.1 h1:C2Tyj0SGOKbCLgHrx83vaE6YkzXEVrMXYRGLkKCr/us=
github.com/projectdiscovery/sarif v0.0.1/go.mod h1:cEYlDu8amcPf6b9dSakcz2nNnJsoz4aR6peERwV+wuQ=
github.com/projectdiscovery/stringsutil v0.0.2 h1:uzmw3IVLJSMW1kEg8eCStG/cGbYYZAja8BH3LqqJXMA=
@@ -925,8 +914,8 @@ github.com/projectdiscovery/useragent v0.0.100 h1:gDZSgPQCP8D0XUny41Ch4urP+FK5Oc
github.com/projectdiscovery/useragent v0.0.100/go.mod h1:8je9oUPzT5R+gjKQNEFurDSvX7fCnqW2iDGYdKMH6hY=
github.com/projectdiscovery/utils v0.4.18 h1:cSjMOLXI5gAajfA6KV+0iQG4dGx2IHWLQyND/Snvw7k=
github.com/projectdiscovery/utils v0.4.18/go.mod h1:y5gnpQn802iEWqf0djTRNskJlS62P5eqe1VS1+ah0tk=
-github.com/projectdiscovery/wappalyzergo v0.2.25 h1:K56XmuMrEBowlu2WqSFJDkUju8DBACRKDJ8JUQrqpDk=
-github.com/projectdiscovery/wappalyzergo v0.2.25/go.mod h1:F8X79ljvmvrG+EIxdxWS9VbdkVTsQupHYz+kXlp8O0o=
+github.com/projectdiscovery/wappalyzergo v0.2.27 h1:u5z/3YohzwtX3n4EGDGy4XOKAXZx4JorNzZlw9CzOK0=
+github.com/projectdiscovery/wappalyzergo v0.2.27/go.mod h1:F8X79ljvmvrG+EIxdxWS9VbdkVTsQupHYz+kXlp8O0o=
github.com/projectdiscovery/yamldoc-go v1.0.6 h1:GCEdIRlQjDux28xTXKszM7n3jlMf152d5nqVpVoetas=
github.com/projectdiscovery/yamldoc-go v1.0.6/go.mod h1:R5lWrNzP+7Oyn77NDVPnBsxx2/FyQZBBkIAaSaCQFxw=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
@@ -1094,7 +1083,6 @@ github.com/twmb/murmur3 v1.1.6/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
-github.com/ulikunitz/xz v0.5.9/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc=
github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
@@ -1130,8 +1118,6 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
github.com/xhit/go-str2duration v1.2.0/go.mod h1:3cPSlfZlUHVlneIVfePFWcJZsuwf+P1v2SRTV4cUmp4=
-github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo=
-github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
From 6d25a5c8cab2ae5c9c2b55d7caa6bb124c0e1347 Mon Sep 17 00:00:00 2001
From: sandeep <8293321+ehsandeep@users.noreply.github.com>
Date: Thu, 8 May 2025 19:02:47 +0530
Subject: [PATCH 006/135] version update
---
pkg/catalog/config/constants.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pkg/catalog/config/constants.go b/pkg/catalog/config/constants.go
index be40a5de2..3b4976586 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.2`
+ Version = `v3.4.3`
// Directory Names of custom templates
CustomS3TemplatesDirName = "s3"
CustomGitHubTemplatesDirName = "github"
From 36a3dab2646c98599ba839f7fe0ced318b7e22ba Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 12 May 2025 05:10:38 +0000
Subject: [PATCH 007/135] chore(deps): bump the modules group with 3 updates
Bumps the modules group with 3 updates: [github.com/projectdiscovery/utils](https://github.com/projectdiscovery/utils), [github.com/projectdiscovery/wappalyzergo](https://github.com/projectdiscovery/wappalyzergo) and [github.com/projectdiscovery/networkpolicy](https://github.com/projectdiscovery/networkpolicy).
Updates `github.com/projectdiscovery/utils` from 0.4.18 to 0.4.19
- [Release notes](https://github.com/projectdiscovery/utils/releases)
- [Changelog](https://github.com/projectdiscovery/utils/blob/main/CHANGELOG.md)
- [Commits](https://github.com/projectdiscovery/utils/compare/v0.4.18...v0.4.19)
Updates `github.com/projectdiscovery/wappalyzergo` from 0.2.27 to 0.2.28
- [Release notes](https://github.com/projectdiscovery/wappalyzergo/releases)
- [Commits](https://github.com/projectdiscovery/wappalyzergo/compare/v0.2.27...v0.2.28)
Updates `github.com/projectdiscovery/networkpolicy` from 0.1.13 to 0.1.14
- [Release notes](https://github.com/projectdiscovery/networkpolicy/releases)
- [Commits](https://github.com/projectdiscovery/networkpolicy/compare/v0.1.13...v0.1.14)
---
updated-dependencies:
- dependency-name: github.com/projectdiscovery/utils
dependency-version: 0.4.19
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: modules
- dependency-name: github.com/projectdiscovery/wappalyzergo
dependency-version: 0.2.28
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: modules
- dependency-name: github.com/projectdiscovery/networkpolicy
dependency-version: 0.1.14
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: modules
...
Signed-off-by: dependabot[bot]
---
go.mod | 6 +++---
go.sum | 12 ++++++------
2 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/go.mod b/go.mod
index 820548938..7ed4bc989 100644
--- a/go.mod
+++ b/go.mod
@@ -102,8 +102,8 @@ require (
github.com/projectdiscovery/tlsx v1.1.9
github.com/projectdiscovery/uncover v1.0.10
github.com/projectdiscovery/useragent v0.0.100
- github.com/projectdiscovery/utils v0.4.18
- github.com/projectdiscovery/wappalyzergo v0.2.27
+ github.com/projectdiscovery/utils v0.4.19
+ github.com/projectdiscovery/wappalyzergo v0.2.28
github.com/redis/go-redis/v9 v9.1.0
github.com/seh-msft/burpxml v1.0.1
github.com/shurcooL/graphql v0.0.0-20230722043721-ed46e5a46466
@@ -310,7 +310,7 @@ require (
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
github.com/projectdiscovery/blackrock v0.0.1 // indirect
- github.com/projectdiscovery/networkpolicy v0.1.13
+ github.com/projectdiscovery/networkpolicy v0.1.14
github.com/rivo/uniseg v0.4.7 // indirect
github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d // indirect
github.com/tklauser/go-sysconf v0.3.12 // indirect
diff --git a/go.sum b/go.sum
index 64946396f..964bb991d 100644
--- a/go.sum
+++ b/go.sum
@@ -890,8 +890,8 @@ github.com/projectdiscovery/mapcidr v1.1.34 h1:udr83vQ7oz3kEOwlsU6NC6o08leJzSDQt
github.com/projectdiscovery/mapcidr v1.1.34/go.mod h1:1+1R6OkKSAKtWDXE9RvxXtXPoajXTYX0eiEdkqlhQqQ=
github.com/projectdiscovery/n3iwf v0.0.0-20230523120440-b8cd232ff1f5 h1:L/e8z8yw1pfT6bg35NiN7yd1XKtJap5Nk6lMwQ0RNi8=
github.com/projectdiscovery/n3iwf v0.0.0-20230523120440-b8cd232ff1f5/go.mod h1:pGW2ncnTxTxHtP9wzcIJAB+3/NMp6IiuQWd2NK7K+oc=
-github.com/projectdiscovery/networkpolicy v0.1.13 h1:1QBMYdPlMCt71PUAZAQsZgJfEXIYiJa8sgJswLUBpb4=
-github.com/projectdiscovery/networkpolicy v0.1.13/go.mod h1:pat2rE4G7kbow8CQ/yOym0bdLPq8rj7ZZWn3/3OT4Rs=
+github.com/projectdiscovery/networkpolicy v0.1.14 h1:XnwpGjF+h9xgwEIgrFG3G+7cGRPwh6FkxgQaLuw4rv4=
+github.com/projectdiscovery/networkpolicy v0.1.14/go.mod h1:pat2rE4G7kbow8CQ/yOym0bdLPq8rj7ZZWn3/3OT4Rs=
github.com/projectdiscovery/ratelimit v0.0.80 h1:kDZ9Rgd/EiDR3fw8Ugtp4xVMaMZNzlEO8zCD4QholaE=
github.com/projectdiscovery/ratelimit v0.0.80/go.mod h1:UW6g3VZbX+wI6WLXsexWGpSYnaQ79Uv+VewRj2+pzXQ=
github.com/projectdiscovery/rawhttp v0.1.90 h1:LOSZ6PUH08tnKmWsIwvwv1Z/4zkiYKYOSZ6n+8RFKtw=
@@ -912,10 +912,10 @@ github.com/projectdiscovery/uncover v1.0.10 h1:FdnBYgynGUtjIsW5WPIIhadR1Smcghik9
github.com/projectdiscovery/uncover v1.0.10/go.mod h1:l7QQ+mBc7bLK4tqYqPyo9nrYdz1K8vaGZWKYihkHmAs=
github.com/projectdiscovery/useragent v0.0.100 h1:gDZSgPQCP8D0XUny41Ch4urP+FK5OcM5TB1btwCg4Gk=
github.com/projectdiscovery/useragent v0.0.100/go.mod h1:8je9oUPzT5R+gjKQNEFurDSvX7fCnqW2iDGYdKMH6hY=
-github.com/projectdiscovery/utils v0.4.18 h1:cSjMOLXI5gAajfA6KV+0iQG4dGx2IHWLQyND/Snvw7k=
-github.com/projectdiscovery/utils v0.4.18/go.mod h1:y5gnpQn802iEWqf0djTRNskJlS62P5eqe1VS1+ah0tk=
-github.com/projectdiscovery/wappalyzergo v0.2.27 h1:u5z/3YohzwtX3n4EGDGy4XOKAXZx4JorNzZlw9CzOK0=
-github.com/projectdiscovery/wappalyzergo v0.2.27/go.mod h1:F8X79ljvmvrG+EIxdxWS9VbdkVTsQupHYz+kXlp8O0o=
+github.com/projectdiscovery/utils v0.4.19 h1:rWOOTWUMQK9gvgH01rrw0qFi0hrh712hM1pCUzapCqA=
+github.com/projectdiscovery/utils v0.4.19/go.mod h1:y5gnpQn802iEWqf0djTRNskJlS62P5eqe1VS1+ah0tk=
+github.com/projectdiscovery/wappalyzergo v0.2.28 h1:fd4xne6ndxJFSqJfSDAXmR3G87SZQdOYFTapHk4Ksh4=
+github.com/projectdiscovery/wappalyzergo v0.2.28/go.mod h1:F8X79ljvmvrG+EIxdxWS9VbdkVTsQupHYz+kXlp8O0o=
github.com/projectdiscovery/yamldoc-go v1.0.6 h1:GCEdIRlQjDux28xTXKszM7n3jlMf152d5nqVpVoetas=
github.com/projectdiscovery/yamldoc-go v1.0.6/go.mod h1:R5lWrNzP+7Oyn77NDVPnBsxx2/FyQZBBkIAaSaCQFxw=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
From bc551fc3f1273103e1eec6a25ef7085378f72a6e Mon Sep 17 00:00:00 2001
From: Chris Grieger
Date: Wed, 14 May 2025 16:13:44 +0200
Subject: [PATCH 008/135] fix: improve headless engine startup and shutdown
Fixes #6221
Instead of enumerating all chrome processes to determine
which ones need to be killed on shutdown, use the launcher.Kill()
method to terminate the process that was launched for this
browser instance.
---
pkg/protocols/headless/engine/engine.go | 16 +++++++---------
1 file changed, 7 insertions(+), 9 deletions(-)
diff --git a/pkg/protocols/headless/engine/engine.go b/pkg/protocols/headless/engine/engine.go
index 20942c261..0a83eef98 100644
--- a/pkg/protocols/headless/engine/engine.go
+++ b/pkg/protocols/headless/engine/engine.go
@@ -15,16 +15,15 @@ import (
"github.com/projectdiscovery/nuclei/v3/pkg/types"
fileutil "github.com/projectdiscovery/utils/file"
osutils "github.com/projectdiscovery/utils/os"
- processutil "github.com/projectdiscovery/utils/process"
)
// Browser is a browser structure for nuclei headless module
type Browser struct {
- customAgent string
- tempDir string
- previousPIDs map[int32]struct{} // track already running PIDs
- engine *rod.Browser
- options *types.Options
+ customAgent string
+ tempDir string
+ engine *rod.Browser
+ options *types.Options
+ launcher *launcher.Launcher
// use getHTTPClient to get the http client
httpClient *http.Client
httpClientOnce *sync.Once
@@ -36,7 +35,6 @@ func New(options *types.Options) (*Browser, error) {
if err != nil {
return nil, errors.Wrap(err, "could not create temporary directory")
}
- previousPIDs := processutil.FindProcesses(processutil.IsChromeProcess)
chromeLauncher := launcher.New().
Leakless(false).
@@ -110,8 +108,8 @@ func New(options *types.Options) (*Browser, error) {
engine: browser,
options: options,
httpClientOnce: &sync.Once{},
+ launcher: chromeLauncher,
}
- engine.previousPIDs = previousPIDs
return engine, nil
}
@@ -143,6 +141,6 @@ func (b *Browser) getHTTPClient() (*http.Client, error) {
// Close closes the browser engine
func (b *Browser) Close() {
b.engine.Close()
+ b.launcher.Kill()
os.RemoveAll(b.tempDir)
- processutil.CloseProcesses(processutil.IsChromeProcess, b.previousPIDs)
}
From 44e58f1d3b088433d1014f71921896a2dabeebbc Mon Sep 17 00:00:00 2001
From: proabiral <22173232+proabiral@users.noreply.github.com>
Date: Thu, 15 May 2025 15:58:11 +0545
Subject: [PATCH 009/135] Update README.md with new required go version (#6223)
latest version of nuclei requires 1.23.
2.023 go: github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest: github.com/projectdiscovery/nuclei/v3@v3.4.3 requires go >= 1.23.0 (running go 1.22.2; GOTOOLCHAIN=local)
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index fa76e3695..1153b8e1c 100644
--- a/README.md
+++ b/README.md
@@ -111,7 +111,7 @@ Browse the full Nuclei [**`documentation here`**](https://docs.projectdiscovery.
### Installation
-`nuclei` requires **go1.22** to install successfully. Run the following command to get the repo:
+`nuclei` requires **go1.23** to install successfully. Run the following command to get the repo:
```sh
go install -v github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest
From b03c30418bafbe43685ba25125ecb1d124e97203 Mon Sep 17 00:00:00 2001
From: circleous <20841686+circleous@users.noreply.github.com>
Date: Thu, 15 May 2025 18:16:49 +0700
Subject: [PATCH 010/135] fix: fallback set SNI to host if not specified when
using socks proxy (#6218)
---
pkg/protocols/http/httpclientpool/clientpool.go | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/pkg/protocols/http/httpclientpool/clientpool.go b/pkg/protocols/http/httpclientpool/clientpool.go
index 3f10fcbab..5c1a91cb5 100644
--- a/pkg/protocols/http/httpclientpool/clientpool.go
+++ b/pkg/protocols/http/httpclientpool/clientpool.go
@@ -307,6 +307,14 @@ func wrappedGet(options *types.Options, configuration *Configuration) (*retryabl
if err != nil {
return nil, err
}
+ if tlsConfig.ServerName == "" {
+ // addr should be in form of host:port already set from canonicalAddr
+ host, _, err := net.SplitHostPort(addr)
+ if err != nil {
+ return nil, err
+ }
+ tlsConfig.ServerName = host
+ }
return tls.Client(conn, tlsConfig), nil
}
}
From 2c1cd27e2c52fee46925699c710986209bf10cf8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Do=C4=9Fan=20Can=20Bak=C4=B1r?=
Date: Thu, 15 May 2025 19:42:20 +0700
Subject: [PATCH 011/135] update version
---
pkg/catalog/config/constants.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pkg/catalog/config/constants.go b/pkg/catalog/config/constants.go
index 3b4976586..147cf23a2 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.3`
+ Version = `v3.4.4`
// Directory Names of custom templates
CustomS3TemplatesDirName = "s3"
CustomGitHubTemplatesDirName = "github"
From ef05aac4e506c4cb1aa7ec7a8e280f0e08f5c9c2 Mon Sep 17 00:00:00 2001
From: Spencer Heywood
Date: Thu, 15 May 2025 08:40:27 -0600
Subject: [PATCH 012/135] bump golang in dockerfile: 1.22 => 1.23
---
Dockerfile | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/Dockerfile b/Dockerfile
index 9d7a780c7..1c44e7056 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,5 +1,5 @@
# Build
-FROM golang:1.22-alpine AS builder
+FROM golang:1.23-alpine AS builder
RUN apk add build-base
WORKDIR /app
@@ -13,4 +13,4 @@ FROM alpine:latest
RUN apk add --no-cache bind-tools chromium ca-certificates
COPY --from=builder /app/bin/nuclei /usr/local/bin/
-ENTRYPOINT ["nuclei"]
\ No newline at end of file
+ENTRYPOINT ["nuclei"]
From 740a3732af27711873eac282fbaea7c0d98b9574 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Do=C4=9Fan=20Can=20Bak=C4=B1r?=
Date: Thu, 15 May 2025 21:46:06 +0700
Subject: [PATCH 013/135] update dockerfile golang version
---
Dockerfile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Dockerfile b/Dockerfile
index 9d7a780c7..c07c2fc57 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,5 +1,5 @@
# Build
-FROM golang:1.22-alpine AS builder
+FROM golang:1.23-alpine AS builder
RUN apk add build-base
WORKDIR /app
From ebab60f9cdaa47c8fd2711d332b07527add88382 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Do=C4=9Fan=20Can=20Bak=C4=B1r?=
Date: Thu, 15 May 2025 21:48:45 +0700
Subject: [PATCH 014/135] Revert "update dockerfile golang version"
This reverts commit 740a3732af27711873eac282fbaea7c0d98b9574.
---
Dockerfile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Dockerfile b/Dockerfile
index c07c2fc57..9d7a780c7 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,5 +1,5 @@
# Build
-FROM golang:1.23-alpine AS builder
+FROM golang:1.22-alpine AS builder
RUN apk add build-base
WORKDIR /app
From 39572371996f1502bf0813a41116db666e5c39b9 Mon Sep 17 00:00:00 2001
From: Dwi Siswanto <25837540+dwisiswant0@users.noreply.github.com>
Date: Sat, 17 May 2025 02:16:41 +0700
Subject: [PATCH 015/135] fix(openapi): handles nil schema & schema values
(#6228)
Signed-off-by: Dwi Siswanto
---
pkg/input/formats/openapi/examples.go | 30 ++++++++++++++++++++++++++
pkg/input/formats/openapi/generator.go | 28 +++++++++++++++---------
2 files changed, 48 insertions(+), 10 deletions(-)
diff --git a/pkg/input/formats/openapi/examples.go b/pkg/input/formats/openapi/examples.go
index 9e7224ab7..235f940c9 100644
--- a/pkg/input/formats/openapi/examples.go
+++ b/pkg/input/formats/openapi/examples.go
@@ -288,3 +288,33 @@ func openAPIExample(schema *openapi3.Schema, cache map[*openapi3.Schema]*cachedS
func generateExampleFromSchema(schema *openapi3.Schema) (interface{}, error) {
return openAPIExample(schema, make(map[*openapi3.Schema]*cachedSchema)) // TODO: Use caching
}
+
+func generateEmptySchemaValue(contentType string) *openapi3.Schema {
+ schema := &openapi3.Schema{}
+ objectType := &openapi3.Types{"object"}
+ stringType := &openapi3.Types{"string"}
+
+ switch contentType {
+ case "application/json":
+ schema.Type = objectType
+ schema.Properties = make(map[string]*openapi3.SchemaRef)
+ case "application/xml":
+ schema.Type = stringType
+ schema.Format = "xml"
+ schema.Example = ""
+ case "text/plain":
+ schema.Type = stringType
+ case "application/x-www-form-urlencoded":
+ schema.Type = objectType
+ schema.Properties = make(map[string]*openapi3.SchemaRef)
+ case "multipart/form-data":
+ schema.Type = objectType
+ schema.Properties = make(map[string]*openapi3.SchemaRef)
+ case "application/octet-stream":
+ default:
+ schema.Type = stringType
+ schema.Format = "binary"
+ }
+
+ return schema
+}
diff --git a/pkg/input/formats/openapi/generator.go b/pkg/input/formats/openapi/generator.go
index 9c44797dc..1906858cb 100644
--- a/pkg/input/formats/openapi/generator.go
+++ b/pkg/input/formats/openapi/generator.go
@@ -268,24 +268,32 @@ func generateRequestsFromOp(opts *generateReqOptions) error {
for content, value := range opts.op.RequestBody.Value.Content {
cloned := req.Clone(req.Context())
- example, err := generateExampleFromSchema(value.Schema.Value)
- if err != nil {
- continue
+ var val interface{}
+
+ if value.Schema == nil || value.Schema.Value == nil {
+ val = generateEmptySchemaValue(content)
+ } else {
+ var err error
+
+ val, err = generateExampleFromSchema(value.Schema.Value)
+ if err != nil {
+ continue
+ }
}
// var body string
switch content {
case "application/json":
- if marshalled, err := json.Marshal(example); err == nil {
+ if marshalled, err := json.Marshal(val); err == nil {
// body = string(marshalled)
cloned.Body = io.NopCloser(bytes.NewReader(marshalled))
cloned.ContentLength = int64(len(marshalled))
cloned.Header.Set("Content-Type", "application/json")
}
case "application/xml":
- exampleVal := mxj.Map(example.(map[string]interface{}))
+ values := mxj.Map(val.(map[string]interface{}))
- if marshalled, err := exampleVal.Xml(); err == nil {
+ if marshalled, err := values.Xml(); err == nil {
// body = string(marshalled)
cloned.Body = io.NopCloser(bytes.NewReader(marshalled))
cloned.ContentLength = int64(len(marshalled))
@@ -294,7 +302,7 @@ func generateRequestsFromOp(opts *generateReqOptions) error {
gologger.Warning().Msgf("openapi: could not encode xml")
}
case "application/x-www-form-urlencoded":
- if values, ok := example.(map[string]interface{}); ok {
+ if values, ok := val.(map[string]interface{}); ok {
cloned.Form = url.Values{}
for k, v := range values {
cloned.Form.Set(k, types.ToString(v))
@@ -306,7 +314,7 @@ func generateRequestsFromOp(opts *generateReqOptions) error {
cloned.Header.Set("Content-Type", "application/x-www-form-urlencoded")
}
case "multipart/form-data":
- if values, ok := example.(map[string]interface{}); ok {
+ if values, ok := val.(map[string]interface{}); ok {
buffer := &bytes.Buffer{}
multipartWriter := multipart.NewWriter(buffer)
for k, v := range values {
@@ -326,13 +334,13 @@ func generateRequestsFromOp(opts *generateReqOptions) error {
cloned.Header.Set("Content-Type", multipartWriter.FormDataContentType())
}
case "text/plain":
- str := types.ToString(example)
+ str := types.ToString(val)
// body = str
cloned.Body = io.NopCloser(strings.NewReader(str))
cloned.ContentLength = int64(len(str))
cloned.Header.Set("Content-Type", "text/plain")
case "application/octet-stream":
- str := types.ToString(example)
+ str := types.ToString(val)
if str == "" {
// use two strings
str = "string1\nstring2"
From 21d376f19478148bd3f1941db35e776a3d427294 Mon Sep 17 00:00:00 2001
From: Dwi Siswanto
Date: Sun, 18 May 2025 19:46:14 +0700
Subject: [PATCH 016/135] ci: adds stale workflow
Signed-off-by: Dwi Siswanto
---
.github/stale.yml | 27 ------------------------
.github/workflows/stale.yaml | 41 ++++++++++++++++++++++++++++++++++++
2 files changed, 41 insertions(+), 27 deletions(-)
delete mode 100644 .github/stale.yml
create mode 100644 .github/workflows/stale.yaml
diff --git a/.github/stale.yml b/.github/stale.yml
deleted file mode 100644
index 75d7ee029..000000000
--- a/.github/stale.yml
+++ /dev/null
@@ -1,27 +0,0 @@
-# Number of days of inactivity before an issue becomes stale
-daysUntilStale: 7
-
-# Number of days of inactivity before a stale issue is closed
-daysUntilClose: 7
-
-# Issues with these labels will never be considered stale
-# exemptLabels:
-# - pinned
-# - security
-
-# Only issues or pull requests with all of these labels are check if stale.
-onlyLabels:
- - "Status: Abandoned"
- - "Type: Question"
-
-# Label to use when marking as stale
-staleLabel: stale
-
-# Comment to post when marking an issue as stale. Set to `false` to disable
-markComment: >
- This issue has been automatically marked as stale because it has not had
- recent activity. It will be closed if no further activity occurs. Thank you
- for your contributions.
-
-# Comment to post when closing a stale issue. Set to `false` to disable
-closeComment: false
\ No newline at end of file
diff --git a/.github/workflows/stale.yaml b/.github/workflows/stale.yaml
new file mode 100644
index 000000000..2b336b671
--- /dev/null
+++ b/.github/workflows/stale.yaml
@@ -0,0 +1,41 @@
+name: 💤 Stale
+
+on:
+ schedule:
+ - cron: '0 0 * * 0' # Weekly
+
+jobs:
+ stale:
+ runs-on: ubuntu-latest
+ permissions:
+ actions: write
+ contents: write # only for delete-branch option
+ issues: write
+ pull-requests: write
+ steps:
+ - uses: actions/stale@v9
+ with:
+ days-before-stale: 90
+ days-before-close: 7
+ stale-issue-label: "Status: Stale"
+ stale-pr-label: "Status: Stale"
+ stale-issue-message: >
+ This issue has been automatically marked as stale because it has not
+ had recent activity. It will be closed in 7 days if no further
+ activity occurs. Thank you for your contributions!
+ stale-pr-message: >
+ This pull request has been automatically marked as stale due to
+ inactivity. It will be closed in 7 days if no further activity
+ occurs. Please update if you wish to keep it open.
+ close-issue-message: >
+ This issue has been automatically closed due to inactivity. If you
+ think this is a mistake or would like to continue the discussion,
+ please comment or feel free to reopen it.
+ close-pr-message: >
+ This pull request has been automatically closed due to inactivity.
+ If you think this is a mistake or would like to continue working on
+ it, please comment or feel free to reopen it.
+ close-issue-label: "Status: Abandoned"
+ close-pr-label: "Status: Abandoned"
+ exempt-issue-labels: "Status: Abandoned"
+ exempt-pr-labels: "Status: Abandoned"
From 242b1e1636ac80e2dc43ed071cb6ea6c6ee72a51 Mon Sep 17 00:00:00 2001
From: Nakul Bharti
Date: Sun, 18 May 2025 20:09:41 +0530
Subject: [PATCH 017/135] increase file descriptor limits (#6230)
* add missing file
* increase file descriptor limit
* removed debugging code
* fixed lower case
* test: tweaks on script
* uses CI runtime env vars (`RUNNER_OS` &
`RUNNER_DEBUG`)
* restores originial `ulimit`
Signed-off-by: Dwi Siswanto
---------
Signed-off-by: Dwi Siswanto
Co-authored-by: Dwi Siswanto
---
.github/workflows/tests.yaml | 2 +-
cmd/functional-test/main.go | 2 +-
cmd/functional-test/run.sh | 42 +++++++++++++++++++++++++-----------
3 files changed, 31 insertions(+), 15 deletions(-)
diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml
index af6ad9d7e..7cbfd2f12 100644
--- a/.github/workflows/tests.yaml
+++ b/.github/workflows/tests.yaml
@@ -94,7 +94,7 @@ jobs:
- uses: actions/checkout@v4
- uses: projectdiscovery/actions/setup/go@v1
- uses: projectdiscovery/actions/setup/python@v1
- - run: bash run.sh "${{ matrix.os }}"
+ - run: bash run.sh
env:
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
working-directory: cmd/functional-test/
diff --git a/cmd/functional-test/main.go b/cmd/functional-test/main.go
index 8a5cebc59..78114fdb3 100644
--- a/cmd/functional-test/main.go
+++ b/cmd/functional-test/main.go
@@ -27,7 +27,7 @@ var (
func main() {
flag.Parse()
- debug := os.Getenv("DEBUG") == "true"
+ debug := os.Getenv("DEBUG") == "true" || os.Getenv("RUNNER_DEBUG") == "1"
if err, errored := runFunctionalTests(debug); err != nil {
log.Fatalf("Could not run functional tests: %s\n", err)
diff --git a/cmd/functional-test/run.sh b/cmd/functional-test/run.sh
index a3caf7222..a955ad8a7 100755
--- a/cmd/functional-test/run.sh
+++ b/cmd/functional-test/run.sh
@@ -1,27 +1,43 @@
#!/bin/bash
-# reading os type from arguments
-CURRENT_OS=$1
+if [ "${RUNNER_OS}" == "Windows" ]; then
+ EXT=".exe"
+elif [ "${RUNNER_OS}" == "macOS" ]; then
+ if [ "${CI}" == "true" ]; then
+ sudo sysctl -w kern.maxfiles{,perproc}=524288
+ sudo launchctl limit maxfiles 65536 524288
+ fi
-if [ "${CURRENT_OS}" == "windows-latest" ];then
- extension=.exe
+ ORIGINAL_ULIMIT="$(ulimit -n)"
+ ulimit -n 65536 || true
fi
+mkdir -p .nuclei-config/nuclei/
+touch .nuclei-config/nuclei/.nuclei-ignore
+
echo "::group::Building functional-test binary"
-go build -o functional-test$extension
+go build -o "functional-test${EXT}"
echo "::endgroup::"
echo "::group::Building Nuclei binary from current branch"
-go build -o nuclei_dev$extension ../nuclei
-echo "::endgroup::"
-
-echo "::group::Installing nuclei templates"
-./nuclei_dev$extension -update-templates
+go build -o "nuclei-dev${EXT}" ../nuclei
echo "::endgroup::"
echo "::group::Building latest release of nuclei"
-go build -o nuclei$extension -v github.com/projectdiscovery/nuclei/v3/cmd/nuclei
+go build -o "nuclei${EXT}" -v github.com/projectdiscovery/nuclei/v3/cmd/nuclei
echo "::endgroup::"
-echo 'Starting Nuclei functional test'
-./functional-test$extension -main ./nuclei$extension -dev ./nuclei_dev$extension -testcases testcases.txt
+echo "::group::Installing nuclei templates"
+eval "./nuclei-dev${EXT} -update-templates"
+echo "::endgroup::"
+
+echo "::group::Validating templates"
+eval "./nuclei-dev${EXT} -validate"
+echo "::endgroup::"
+
+echo "Starting Nuclei functional test"
+eval "./functional-test${EXT} -main ./nuclei${EXT} -dev ./nuclei-dev${EXT} -testcases testcases.txt"
+
+if [ "${RUNNER_OS}" == "macOS" ]; then
+ ulimit -n "${ORIGINAL_ULIMIT}" || true
+fi
From 8a13639b624aa66e54e0cbe9a2e0be0a7303a1e2 Mon Sep 17 00:00:00 2001
From: Reynaldo Jarro
Date: Tue, 27 May 2025 02:02:25 -0700
Subject: [PATCH 018/135] fixing missing symbol (#6242)
---
README.md | 2 +-
README_CN.md | 2 +-
README_ES.md | 2 +-
README_ID.md | 2 +-
README_JP.md | 2 +-
README_KR.md | 2 +-
README_PT-BR.md | 2 +-
7 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/README.md b/README.md
index 1153b8e1c..741ceafc3 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,7 @@
`Korean` •
`Indonesia` •
`Spanish` •
- `日本語`
+ `日本語` •
`Portuguese`
diff --git a/README_CN.md b/README_CN.md
index f09622d65..99f150e6e 100644
--- a/README_CN.md
+++ b/README_CN.md
@@ -33,7 +33,7 @@
中文 •
Korean •
Indonesia •
- Spanish
+ Spanish •
Portuguese
diff --git a/README_ES.md b/README_ES.md
index 527ca7cdc..27f60ee8b 100644
--- a/README_ES.md
+++ b/README_ES.md
@@ -31,7 +31,7 @@
中文 •
Korean •
Indonesia •
- Spanish
+ Spanish •
Portuguese
diff --git a/README_ID.md b/README_ID.md
index 1180c2ee8..05c163c23 100644
--- a/README_ID.md
+++ b/README_ID.md
@@ -33,7 +33,7 @@
中文 •
Korean •
Indonesia •
- Spanish
+ Spanish •
Portuguese
diff --git a/README_JP.md b/README_JP.md
index a7fc7a0ac..d80fb4dfc 100644
--- a/README_JP.md
+++ b/README_JP.md
@@ -30,7 +30,7 @@
中国語 •
韓国語 •
インドネシア語 •
- スペイン語
+ スペイン語 •
ポルトガル語
diff --git a/README_KR.md b/README_KR.md
index f1a27f00e..c59825cdb 100644
--- a/README_KR.md
+++ b/README_KR.md
@@ -31,7 +31,7 @@
English •
中文 •
한국어 •
- 스페인어
+ 스페인어 •
포르투갈어
diff --git a/README_PT-BR.md b/README_PT-BR.md
index cff85180f..012f878f7 100644
--- a/README_PT-BR.md
+++ b/README_PT-BR.md
@@ -31,7 +31,7 @@
中文 •
Korean •
Indonesia •
- Spanish
+ Spanish •
Portuguese
From 3be29abfc96ad906fef679bf2f8c15688f081eac Mon Sep 17 00:00:00 2001
From: tongjicoder
Date: Tue, 27 May 2025 17:16:26 +0800
Subject: [PATCH 019/135] refactor: use slices.Contains to simplify code
Signed-off-by: tongjicoder
---
pkg/catalog/aws/catalog.go | 7 +++----
pkg/catalog/aws/catalog_test.go | 9 ++-------
pkg/catalog/config/nucleiconfig.go | 8 ++------
pkg/input/formats/openapi/examples.go | 9 ++-------
pkg/protocols/http/request_condition.go | 8 ++------
5 files changed, 11 insertions(+), 30 deletions(-)
diff --git a/pkg/catalog/aws/catalog.go b/pkg/catalog/aws/catalog.go
index 5dfa86a56..58d409360 100644
--- a/pkg/catalog/aws/catalog.go
+++ b/pkg/catalog/aws/catalog.go
@@ -7,6 +7,7 @@ import (
"fmt"
"io"
"path"
+ "slices"
"strings"
"github.com/aws/aws-sdk-go-v2/aws"
@@ -140,10 +141,8 @@ func (c Catalog) ResolvePath(templateName, second string) (string, error) {
}
// check if templateName is already an absolute path to c key
- for _, key := range keys {
- if key == templateName {
- return templateName, nil
- }
+ if slices.Contains(keys, templateName) {
+ return templateName, nil
}
return "", fmt.Errorf("no such path found: %s%s for keys: %v", second, templateName, keys)
diff --git a/pkg/catalog/aws/catalog_test.go b/pkg/catalog/aws/catalog_test.go
index 57dac391a..59095d635 100644
--- a/pkg/catalog/aws/catalog_test.go
+++ b/pkg/catalog/aws/catalog_test.go
@@ -3,6 +3,7 @@ package aws
import (
"io"
"reflect"
+ "slices"
"strings"
"testing"
@@ -250,13 +251,7 @@ func (m mocks3svc) getAllKeys() ([]string, error) {
}
func (m mocks3svc) downloadKey(name string) (io.ReadCloser, error) {
- found := false
- for _, key := range m.keys {
- if key == name {
- found = true
- break
- }
- }
+ found := slices.Contains(m.keys, name)
if !found {
return nil, errors.New("key not found")
}
diff --git a/pkg/catalog/config/nucleiconfig.go b/pkg/catalog/config/nucleiconfig.go
index a7bb0ba23..246870935 100644
--- a/pkg/catalog/config/nucleiconfig.go
+++ b/pkg/catalog/config/nucleiconfig.go
@@ -7,6 +7,7 @@ import (
"log"
"os"
"path/filepath"
+ "slices"
"strings"
"github.com/projectdiscovery/goflags"
@@ -334,12 +335,7 @@ func (c *Config) copyIgnoreFile() {
// this could be a feature specific to debugging like PPROF or printing stats
// of max host error etc
func (c *Config) IsDebugArgEnabled(arg string) bool {
- for _, v := range c.debugArgs {
- if v == arg {
- return true
- }
- }
- return false
+ return slices.Contains(c.debugArgs, arg)
}
// parseDebugArgs from string
diff --git a/pkg/input/formats/openapi/examples.go b/pkg/input/formats/openapi/examples.go
index 235f940c9..2c79d5c89 100644
--- a/pkg/input/formats/openapi/examples.go
+++ b/pkg/input/formats/openapi/examples.go
@@ -2,6 +2,7 @@ package openapi
import (
"fmt"
+ "slices"
"github.com/getkin/kin-openapi/openapi3"
"github.com/pkg/errors"
@@ -84,13 +85,7 @@ func excludeFromMode(schema *openapi3.Schema) bool {
// isRequired checks whether a key is actually required.
func isRequired(schema *openapi3.Schema, key string) bool {
- for _, req := range schema.Required {
- if req == key {
- return true
- }
- }
-
- return false
+ return slices.Contains(schema.Required, key)
}
type cachedSchema struct {
diff --git a/pkg/protocols/http/request_condition.go b/pkg/protocols/http/request_condition.go
index 50f881322..e92541443 100644
--- a/pkg/protocols/http/request_condition.go
+++ b/pkg/protocols/http/request_condition.go
@@ -2,6 +2,7 @@ package http
import (
"regexp"
+ "slices"
)
var (
@@ -32,10 +33,5 @@ func (request *Request) NeedsRequestCondition() bool {
}
func checkRequestConditionExpressions(expressions ...string) bool {
- for _, expression := range expressions {
- if reRequestCondition.MatchString(expression) {
- return true
- }
- }
- return false
+ return slices.ContainsFunc(expressions, reRequestCondition.MatchString)
}
From ec353f534cadaae7135951459f10c1d840d949ef Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Do=C4=9Fan=20Can=20Bak=C4=B1r?=
Date: Tue, 27 May 2025 21:42:33 +0900
Subject: [PATCH 020/135] bump dsl pkg
---
go.mod | 2 +-
go.sum | 2 ++
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/go.mod b/go.mod
index 7ed4bc989..23ff55738 100644
--- a/go.mod
+++ b/go.mod
@@ -86,7 +86,7 @@ require (
github.com/microsoft/go-mssqldb v1.6.0
github.com/ory/dockertest/v3 v3.10.0
github.com/praetorian-inc/fingerprintx v1.1.9
- github.com/projectdiscovery/dsl v0.4.2
+ github.com/projectdiscovery/dsl v0.4.3
github.com/projectdiscovery/fasttemplate v0.0.2
github.com/projectdiscovery/go-smb2 v0.0.0-20240129202741-052cc450c6cb
github.com/projectdiscovery/goflags v0.1.74
diff --git a/go.sum b/go.sum
index 964bb991d..3c80d1e5d 100644
--- a/go.sum
+++ b/go.sum
@@ -860,6 +860,8 @@ github.com/projectdiscovery/clistats v0.1.1 h1:8mwbdbwTU4aT88TJvwIzTpiNeow3XnAB7
github.com/projectdiscovery/clistats v0.1.1/go.mod h1:4LtTC9Oy//RiuT1+76MfTg8Hqs7FQp1JIGBM3nHK6a0=
github.com/projectdiscovery/dsl v0.4.2 h1:9PnD6EyDAZFvpQmJ0700gkQ96Fqlzl+lnTdcVHAagXI=
github.com/projectdiscovery/dsl v0.4.2/go.mod h1:J1RizRF6O3lvk2v8p/tLAYqaxWg6N52OWc+uS5ZmO2U=
+github.com/projectdiscovery/dsl v0.4.3 h1:ZrbRkyK38hRiYMX7s6ohaTorDpq321ErqJuBUDmh49g=
+github.com/projectdiscovery/dsl v0.4.3/go.mod h1:cyt2IaYhS5SlyZ1D2BdK0QwIBXQW/u9zaBmRAKYKAmk=
github.com/projectdiscovery/fastdialer v0.4.0 h1:licZKyq+Shd5lLDb8uPd60Jp43K4NFE8cr67XD2eg7w=
github.com/projectdiscovery/fastdialer v0.4.0/go.mod h1:Q0YLArvpx9GAfY/NcTPMCA9qZuVOGnuVoNYWzKBwxdQ=
github.com/projectdiscovery/fasttemplate v0.0.2 h1:h2cISk5xDhlJEinlBQS6RRx0vOlOirB2y3Yu4PJzpiA=
From a0bd3b854ef8f3246b31384aa0d600be73320622 Mon Sep 17 00:00:00 2001
From: Alban Stourbe
Date: Thu, 12 Jun 2025 15:03:33 +0200
Subject: [PATCH 021/135] feat(templating): add vars templating into yaml
inputs
---
cmd/nuclei/main.go | 1 +
go.mod | 8 ++-
go.sum | 7 ++
pkg/input/formats/formats.go | 4 ++
.../formats/testdata/ginandjuice.ytt.yaml | 26 +++++++
pkg/input/formats/yaml/multidoc.go | 44 +++++++++---
pkg/input/formats/yaml/multidoc_test.go | 43 ++++++++++++
pkg/input/formats/yaml/ytt.go | 69 +++++++++++++++++++
pkg/input/provider/interface.go | 1 +
pkg/types/types.go | 2 +
10 files changed, 192 insertions(+), 13 deletions(-)
create mode 100644 pkg/input/formats/testdata/ginandjuice.ytt.yaml
create mode 100644 pkg/input/formats/yaml/ytt.go
diff --git a/cmd/nuclei/main.go b/cmd/nuclei/main.go
index 8cc2b53f1..e1a3bfb1c 100644
--- a/cmd/nuclei/main.go
+++ b/cmd/nuclei/main.go
@@ -260,6 +260,7 @@ on extensive configurability, massive extensibility and ease of use.`)
flagSet.StringVarP(&options.InputFileMode, "input-mode", "im", "list", fmt.Sprintf("mode of input file (%v)", provider.SupportedInputFormats())),
flagSet.BoolVarP(&options.FormatUseRequiredOnly, "required-only", "ro", false, "use only required fields in input format when generating requests"),
flagSet.BoolVarP(&options.SkipFormatValidation, "skip-format-validation", "sfv", false, "skip format validation (like missing vars) when parsing input file"),
+ flagSet.BoolVarP(&options.VarsTextTemplating, "vars-text-templating", "vtt", false, "enable text templating for vars in input file (only for yaml input mode)"),
)
flagSet.CreateGroup("templates", "Templates",
diff --git a/go.mod b/go.mod
index 23ff55738..80b35383f 100644
--- a/go.mod
+++ b/go.mod
@@ -1,8 +1,8 @@
module github.com/projectdiscovery/nuclei/v3
-go 1.23.0
+go 1.24.2
-toolchain go1.24.1
+toolchain go1.24.3
require (
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible
@@ -119,6 +119,7 @@ require (
require (
aead.dev/minisign v0.2.0 // indirect
+ carvel.dev/ytt v0.52.0 // indirect
dario.cat/mergo v1.0.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.8.0 // indirect
@@ -184,7 +185,7 @@ require (
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/go-uuid v1.0.3 // indirect
- github.com/hashicorp/go-version v1.6.0 // indirect
+ github.com/hashicorp/go-version v1.7.0 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
github.com/hbakhtiyor/strsim v0.0.0-20190107154042-4d2bbb273edf // indirect
github.com/jcmturner/aescts/v2 v2.0.0 // indirect
@@ -194,6 +195,7 @@ require (
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
+ github.com/k14s/starlark-go v0.0.0-20200720175618-3a5c849cc368 // indirect
github.com/kataras/jwt v0.1.10 // indirect
github.com/klauspost/compress v1.17.11 // indirect
github.com/klauspost/pgzip v1.2.6 // indirect
diff --git a/go.sum b/go.sum
index 3c80d1e5d..222127cdf 100644
--- a/go.sum
+++ b/go.sum
@@ -1,5 +1,7 @@
aead.dev/minisign v0.2.0 h1:kAWrq/hBRu4AARY6AlciO83xhNnW9UaC8YipS2uhLPk=
aead.dev/minisign v0.2.0/go.mod h1:zdq6LdSd9TbuSxchxwhpA9zEb9YXcVGoE8JakuiGaIQ=
+carvel.dev/ytt v0.52.0 h1:tkJPL8Gun5snVfypNXbmMKwnbwMyspcTi3Ypyso3nRY=
+carvel.dev/ytt v0.52.0/go.mod h1:QgmuU7E15EXW1r2wxTt7zExVz14IHwEG4WNMmaFBkJo=
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
@@ -577,6 +579,8 @@ github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09
github.com/hashicorp/go-version v1.5.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek=
github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
+github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY=
+github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
@@ -652,6 +656,8 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
+github.com/k14s/starlark-go v0.0.0-20200720175618-3a5c849cc368 h1:4bcRTTSx+LKSxMWibIwzHnDNmaN1x52oEpvnjCy+8vk=
+github.com/k14s/starlark-go v0.0.0-20200720175618-3a5c849cc368/go.mod h1:lKGj1op99m4GtQISxoD2t+K+WO/q2NzEPKvfXFQfbCA=
github.com/kataras/jwt v0.1.10 h1:GBXOF9RVInDPhCFBiDumRG9Tt27l7ugLeLo8HL5SeKQ=
github.com/kataras/jwt v0.1.10/go.mod h1:xkimAtDhU/aGlQqjwvgtg+VyuPwMiyZHaY8LJRh0mYo=
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
@@ -1386,6 +1392,7 @@ golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191002063906-3421d5a6bb1c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
diff --git a/pkg/input/formats/formats.go b/pkg/input/formats/formats.go
index 03c65d3fe..a23ff5d06 100644
--- a/pkg/input/formats/formats.go
+++ b/pkg/input/formats/formats.go
@@ -28,6 +28,10 @@ type InputFormatOptions struct {
// RequiredOnly only uses required fields when generating requests
// instead of all fields
RequiredOnly bool
+ // VarsTextTemplating uses Variables and inject it into the input
+ // this is used for text templating of variables based on carvel ytt
+ // Only available for Yaml formats
+ VarsTextTemplating bool
}
// Format is an interface implemented by all input formats
diff --git a/pkg/input/formats/testdata/ginandjuice.ytt.yaml b/pkg/input/formats/testdata/ginandjuice.ytt.yaml
new file mode 100644
index 000000000..f1889a67f
--- /dev/null
+++ b/pkg/input/formats/testdata/ginandjuice.ytt.yaml
@@ -0,0 +1,26 @@
+#@ load("@ytt:data", "data")
+#@ load("@ytt:assert", "assert")
+
+#@ def get_value(key, default=""):
+#@ if hasattr(data.values, key):
+#@ value = getattr(data.values, key)
+#@ return str(value)
+#@ else:
+#@ return default
+#@ end
+#@ end
+
+timestamp: 2024-02-20T19:24:13+05:32
+url: https://ginandjuice.shop/users/3
+request:
+ #@yaml/text-templated-strings
+ raw: |+
+ POST /users/3 HTTP/1.1
+ Host: ginandjuice.shop
+ Authorization: Bearer 3x4mpl3t0k3n
+ Accept-Encoding: gzip
+ Content-Type: application/x-www-form-urlencoded
+ Connection: close
+ User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
+
+ foo=(@= get_value("foo") @)&bar=(@= get_value("bar") @)
\ No newline at end of file
diff --git a/pkg/input/formats/yaml/multidoc.go b/pkg/input/formats/yaml/multidoc.go
index 6d75e0334..a6ae8067a 100644
--- a/pkg/input/formats/yaml/multidoc.go
+++ b/pkg/input/formats/yaml/multidoc.go
@@ -46,23 +46,47 @@ func (j *YamlMultiDocFormat) SetOptions(options formats.InputFormatOptions) {
// Parse parses the input and calls the provided callback
// function for each RawRequest it discovers.
func (j *YamlMultiDocFormat) Parse(input io.Reader, resultsCb formats.ParseReqRespCallback, filePath string) error {
- decoder := YamlUtil.NewDecoder(input)
+ finalInput := input
+
+ // Apply text templating if enabled
+ if j.opts.VarsTextTemplating {
+ data, err := io.ReadAll(input)
+ if err != nil {
+ return errors.Wrap(err, "could not read input")
+ }
+ tpl := []string{string(data)}
+ dvs := mapToKeyValueSlice(j.opts.Variables)
+ finalInput, err = ytt(tpl, dvs)
+ if err != nil {
+ return errors.Wrap(err, "could not apply ytt templating")
+ }
+ finalData, err := io.ReadAll(finalInput)
+ if err != nil {
+ return errors.Wrap(err, "could not read templated input")
+ }
+ gologger.Debug().Msgf("Templated YAML content: %s", string(finalData))
+ finalInput = strings.NewReader(string(finalData))
+
+ }
+
+ decoder := YamlUtil.NewDecoder(finalInput)
for {
var request proxifyRequest
- err := decoder.Decode(&request)
- if err == io.EOF {
- break
+ if err := decoder.Decode(&request); err != nil {
+ if err == io.EOF {
+ break
+ }
+ return errors.Wrap(err, "could not decode yaml file")
}
- if err != nil {
- return errors.Wrap(err, "could not decode json file")
- }
- if strings.TrimSpace(request.Request.Raw) == "" {
+
+ raw := strings.TrimSpace(request.Request.Raw)
+ if raw == "" {
continue
}
- rawRequest, err := types.ParseRawRequestWithURL(request.Request.Raw, request.URL)
+ rawRequest, err := types.ParseRawRequestWithURL(raw, request.URL)
if err != nil {
- gologger.Warning().Msgf("multidoc-yaml: Could not parse raw request %s: %s\n", request.URL, err)
+ gologger.Warning().Msgf("multidoc-yaml: Could not parse raw request %s: %s", request.URL, err)
continue
}
resultsCb(rawRequest)
diff --git a/pkg/input/formats/yaml/multidoc_test.go b/pkg/input/formats/yaml/multidoc_test.go
index 0b91e774a..063d0f13c 100644
--- a/pkg/input/formats/yaml/multidoc_test.go
+++ b/pkg/input/formats/yaml/multidoc_test.go
@@ -4,6 +4,7 @@ import (
"os"
"testing"
+ "github.com/projectdiscovery/nuclei/v3/pkg/input/formats"
"github.com/projectdiscovery/nuclei/v3/pkg/input/types"
"github.com/stretchr/testify/require"
)
@@ -31,3 +32,45 @@ func TestYamlFormatterParse(t *testing.T) {
require.Len(t, urls, len(expectedUrls), "invalid number of urls")
require.ElementsMatch(t, urls, expectedUrls, "invalid urls")
}
+
+func TestYamlFormatterParseWithVariables(t *testing.T) {
+ format := New()
+ proxifyYttFile := "../testdata/ginandjuice.ytt.yaml"
+
+ expectedUrls := []string{
+ "https://ginandjuice.shop/users/3",
+ }
+
+ format.SetOptions(formats.InputFormatOptions{
+ VarsTextTemplating: true,
+ Variables: map[string]interface{}{
+ "foo": "catalog",
+ "bar": "product",
+ },
+ })
+ file, err := os.Open(proxifyYttFile)
+ require.Nilf(t, err, "error opening proxify ytt input file: %v", err)
+ defer file.Close()
+
+ var urls []string
+ err = format.Parse(file, func(request *types.RequestResponse) bool {
+ urls = append(urls, request.URL.String())
+ expectedRaw := `POST /users/3 HTTP/1.1
+Host: ginandjuice.shop
+Authorization: Bearer 3x4mpl3t0k3n
+Accept-Encoding: gzip
+Content-Type: application/x-www-form-urlencoded
+Connection: close
+User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
+
+foo=catalog&bar=product`
+ require.Equal(t, expectedRaw, request.Request.Raw, "request raw does not match expected value")
+
+ return false
+ }, proxifyYttFile)
+
+ require.Nilf(t, err, "error parsing yaml file: %v", err)
+ require.Len(t, urls, len(expectedUrls), "invalid number of urls")
+ require.ElementsMatch(t, urls, expectedUrls, "invalid urls")
+
+}
diff --git a/pkg/input/formats/yaml/ytt.go b/pkg/input/formats/yaml/ytt.go
new file mode 100644
index 000000000..8bbaea752
--- /dev/null
+++ b/pkg/input/formats/yaml/ytt.go
@@ -0,0 +1,69 @@
+package yaml
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+
+ yttcmd "carvel.dev/ytt/pkg/cmd/template"
+ yttui "carvel.dev/ytt/pkg/cmd/ui"
+ yttfiles "carvel.dev/ytt/pkg/files"
+)
+
+func ytt(tpl, dvs []string) (io.Reader, error) {
+ // create and invoke ytt "template" command
+ templatingOptions := yttcmd.NewOptions()
+
+ input, err := templatesAsInput(tpl...)
+ if err != nil {
+ return nil, err
+ }
+
+ // equivalent to `--data-value-yaml`
+ templatingOptions.DataValuesFlags.KVsFromYAML = dvs
+
+ // for in-memory use, pipe output to "/dev/null"
+ noopUI := yttui.NewCustomWriterTTY(false, noopWriter{}, noopWriter{})
+
+ // Evaluate the template given the configured data values...
+ output := templatingOptions.RunWithFiles(input, noopUI)
+ if output.Err != nil {
+ return nil, output.Err
+ }
+
+ // output.DocSet contains the full set of resulting YAML documents, in order.
+ bs, err := output.DocSet.AsBytes()
+ if err != nil {
+ return nil, err
+ }
+ return bytes.NewReader(bs), nil
+}
+
+// templatesAsInput conveniently wraps one or more strings, each in a files.File, into a template.Input.
+func templatesAsInput(tpl ...string) (yttcmd.Input, error) {
+ var files []*yttfiles.File
+ for i, t := range tpl {
+ // to make this less brittle, you'll probably want to use well-defined names for `path`, here, for each input.
+ // this matters when you're processing errors which report based on these paths.
+ file, err := yttfiles.NewFileFromSource(yttfiles.NewBytesSource(fmt.Sprintf("tpl%d.yml", i), []byte(t)))
+ if err != nil {
+ return yttcmd.Input{}, err
+ }
+
+ files = append(files, file)
+ }
+
+ return yttcmd.Input{Files: files}, nil
+}
+
+func mapToKeyValueSlice(m map[string]interface{}) []string {
+ var result []string
+ for k, v := range m {
+ result = append(result, fmt.Sprintf("%s=%v", k, v))
+ }
+ return result
+}
+
+type noopWriter struct{}
+
+func (w noopWriter) Write(data []byte) (int, error) { return len(data), nil }
diff --git a/pkg/input/provider/interface.go b/pkg/input/provider/interface.go
index e6d5da14a..769af60fb 100644
--- a/pkg/input/provider/interface.go
+++ b/pkg/input/provider/interface.go
@@ -116,6 +116,7 @@ func NewInputProvider(opts InputOptions) (InputProvider, error) {
Variables: generators.MergeMaps(extraVars, opts.Options.Vars.AsMap()),
SkipFormatValidation: opts.Options.SkipFormatValidation,
RequiredOnly: opts.Options.FormatUseRequiredOnly,
+ VarsTextTemplating: opts.Options.VarsTextTemplating,
},
})
}
diff --git a/pkg/types/types.go b/pkg/types/types.go
index 41c95ef68..5b71225cb 100644
--- a/pkg/types/types.go
+++ b/pkg/types/types.go
@@ -419,6 +419,8 @@ type Options struct {
FormatUseRequiredOnly bool
// SkipFormatValidation is used to skip format validation
SkipFormatValidation bool
+ // VarsTextTemplating is used to inject variables into yaml input files
+ VarsTextTemplating bool
// PayloadConcurrency is the number of concurrent payloads to run per template
PayloadConcurrency int
// ProbeConcurrency is the number of concurrent http probes to run with httpx
From 5f501da06365934023e1cba5d9fd2db1d9162aef Mon Sep 17 00:00:00 2001
From: Alban Stourbe
Date: Thu, 12 Jun 2025 15:44:11 +0200
Subject: [PATCH 022/135] fix: enhance code rabbit
---
go.mod | 2 +-
go.sum | 10 ++++++----
pkg/input/formats/yaml/multidoc.go | 1 -
pkg/input/formats/yaml/multidoc_test.go | 4 +++-
pkg/input/formats/yaml/ytt.go | 5 ++++-
5 files changed, 14 insertions(+), 8 deletions(-)
diff --git a/go.mod b/go.mod
index 80b35383f..3d60b4efe 100644
--- a/go.mod
+++ b/go.mod
@@ -47,6 +47,7 @@ require (
)
require (
+ carvel.dev/ytt v0.52.0
code.gitea.io/sdk/gitea v0.17.0
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.6.0
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.1.0
@@ -119,7 +120,6 @@ require (
require (
aead.dev/minisign v0.2.0 // indirect
- carvel.dev/ytt v0.52.0 // indirect
dario.cat/mergo v1.0.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.8.0 // indirect
diff --git a/go.sum b/go.sum
index 222127cdf..4dcdb0f46 100644
--- a/go.sum
+++ b/go.sum
@@ -63,6 +63,8 @@ github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzS
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 h1:XHOnouVk1mxXfQidrMEnLlPk9UMeRtyBTnEFtxkV0kU=
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak=
+github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/DataDog/gostackparse v0.6.0 h1:egCGQviIabPwsyoWpGvIBGrEnNWez35aEO7OJ1vBI4o=
github.com/DataDog/gostackparse v0.6.0/go.mod h1:lTfqcJKqS9KnXQGnyQMCugq3u1FP6UZMfWR0aitKFMM=
@@ -515,6 +517,8 @@ github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
+github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
@@ -577,8 +581,6 @@ github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/C
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go-version v1.5.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
-github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek=
-github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY=
github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
@@ -656,6 +658,8 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
+github.com/k14s/difflib v0.0.0-20201117154628-0c031775bf57 h1:CwBRArr+BWBopnUJhDjJw86rPL/jGbEjfHWKzTasSqE=
+github.com/k14s/difflib v0.0.0-20201117154628-0c031775bf57/go.mod h1:B0xN2MiNBGWOWi9CcfAo9LBI8IU4J1utlbOIJCsmKr4=
github.com/k14s/starlark-go v0.0.0-20200720175618-3a5c849cc368 h1:4bcRTTSx+LKSxMWibIwzHnDNmaN1x52oEpvnjCy+8vk=
github.com/k14s/starlark-go v0.0.0-20200720175618-3a5c849cc368/go.mod h1:lKGj1op99m4GtQISxoD2t+K+WO/q2NzEPKvfXFQfbCA=
github.com/kataras/jwt v0.1.10 h1:GBXOF9RVInDPhCFBiDumRG9Tt27l7ugLeLo8HL5SeKQ=
@@ -864,8 +868,6 @@ github.com/projectdiscovery/cdncheck v1.1.17 h1:YSqKk05+UGSxmPIp7tlCvRegF63FUqO+
github.com/projectdiscovery/cdncheck v1.1.17/go.mod h1:dFEGsG0qAJY0AaRr2N1BY0OtZiTxS4kYeT5+OkF8t1U=
github.com/projectdiscovery/clistats v0.1.1 h1:8mwbdbwTU4aT88TJvwIzTpiNeow3XnAB72JIg66c8wE=
github.com/projectdiscovery/clistats v0.1.1/go.mod h1:4LtTC9Oy//RiuT1+76MfTg8Hqs7FQp1JIGBM3nHK6a0=
-github.com/projectdiscovery/dsl v0.4.2 h1:9PnD6EyDAZFvpQmJ0700gkQ96Fqlzl+lnTdcVHAagXI=
-github.com/projectdiscovery/dsl v0.4.2/go.mod h1:J1RizRF6O3lvk2v8p/tLAYqaxWg6N52OWc+uS5ZmO2U=
github.com/projectdiscovery/dsl v0.4.3 h1:ZrbRkyK38hRiYMX7s6ohaTorDpq321ErqJuBUDmh49g=
github.com/projectdiscovery/dsl v0.4.3/go.mod h1:cyt2IaYhS5SlyZ1D2BdK0QwIBXQW/u9zaBmRAKYKAmk=
github.com/projectdiscovery/fastdialer v0.4.0 h1:licZKyq+Shd5lLDb8uPd60Jp43K4NFE8cr67XD2eg7w=
diff --git a/pkg/input/formats/yaml/multidoc.go b/pkg/input/formats/yaml/multidoc.go
index a6ae8067a..679707672 100644
--- a/pkg/input/formats/yaml/multidoc.go
+++ b/pkg/input/formats/yaml/multidoc.go
@@ -64,7 +64,6 @@ func (j *YamlMultiDocFormat) Parse(input io.Reader, resultsCb formats.ParseReqRe
if err != nil {
return errors.Wrap(err, "could not read templated input")
}
- gologger.Debug().Msgf("Templated YAML content: %s", string(finalData))
finalInput = strings.NewReader(string(finalData))
}
diff --git a/pkg/input/formats/yaml/multidoc_test.go b/pkg/input/formats/yaml/multidoc_test.go
index 063d0f13c..3064e8a7d 100644
--- a/pkg/input/formats/yaml/multidoc_test.go
+++ b/pkg/input/formats/yaml/multidoc_test.go
@@ -2,6 +2,7 @@ package yaml
import (
"os"
+ "strings"
"testing"
"github.com/projectdiscovery/nuclei/v3/pkg/input/formats"
@@ -64,7 +65,8 @@ Connection: close
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
foo=catalog&bar=product`
- require.Equal(t, expectedRaw, request.Request.Raw, "request raw does not match expected value")
+ normalised := strings.ReplaceAll(request.Request.Raw, "\r\n", "\n")
+ require.Equal(t, expectedRaw, strings.TrimSuffix(normalised, "\n"), "request raw does not match expected value")
return false
}, proxifyYttFile)
diff --git a/pkg/input/formats/yaml/ytt.go b/pkg/input/formats/yaml/ytt.go
index 8bbaea752..c075119ca 100644
--- a/pkg/input/formats/yaml/ytt.go
+++ b/pkg/input/formats/yaml/ytt.go
@@ -4,10 +4,12 @@ import (
"bytes"
"fmt"
"io"
+ "strings"
yttcmd "carvel.dev/ytt/pkg/cmd/template"
yttui "carvel.dev/ytt/pkg/cmd/ui"
yttfiles "carvel.dev/ytt/pkg/files"
+ "gopkg.in/yaml.v2"
)
func ytt(tpl, dvs []string) (io.Reader, error) {
@@ -59,7 +61,8 @@ func templatesAsInput(tpl ...string) (yttcmd.Input, error) {
func mapToKeyValueSlice(m map[string]interface{}) []string {
var result []string
for k, v := range m {
- result = append(result, fmt.Sprintf("%s=%v", k, v))
+ y, _ := yaml.Marshal(v)
+ result = append(result, fmt.Sprintf("%s=%s", k, strings.TrimSpace(string(y))))
}
return result
}
From 3eb3f668971b2732f0714befe12abb2ba6690840 Mon Sep 17 00:00:00 2001
From: Alban Stourbe
Date: Fri, 13 Jun 2025 13:59:24 +0200
Subject: [PATCH 023/135] fix: change gologger runner version
---
internal/runner/runner.go | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/internal/runner/runner.go b/internal/runner/runner.go
index 424d27116..365e708db 100644
--- a/internal/runner/runner.go
+++ b/internal/runner/runner.go
@@ -863,8 +863,8 @@ func (r *Runner) displayExecutionInfo(store *loader.Store) {
return fmt.Sprintf("Current %s version: %v %v", versionType, version, updateutils.GetVersionDescription(version, latestVersion))
}
- gologger.Info().Msgf(versionInfo(config.Version, cfg.LatestNucleiVersion, "nuclei"))
- gologger.Info().Msgf(versionInfo(cfg.TemplateVersion, cfg.LatestNucleiTemplatesVersion, "nuclei-templates"))
+ gologger.Info().Msg(versionInfo(config.Version, cfg.LatestNucleiVersion, "nuclei"))
+ gologger.Info().Msg(versionInfo(cfg.TemplateVersion, cfg.LatestNucleiTemplatesVersion, "nuclei-templates"))
if !HideAutoSaveMsg {
if r.pdcpUploadErrMsg != "" {
gologger.Print().Msgf("%s", r.pdcpUploadErrMsg)
From fc6d5a7773e0d35263472f7c1d582ce1de7ad572 Mon Sep 17 00:00:00 2001
From: sandeep <8293321+ehsandeep@users.noreply.github.com>
Date: Mon, 16 Jun 2025 20:06:17 +0530
Subject: [PATCH 024/135] improved logging
---
pkg/core/executors.go | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/pkg/core/executors.go b/pkg/core/executors.go
index 2e8c4d18d..05430233b 100644
--- a/pkg/core/executors.go
+++ b/pkg/core/executors.go
@@ -38,7 +38,7 @@ func (e *Engine) executeAllSelfContained(ctx context.Context, alltemplates []*te
match, err = template.Executer.Execute(ctx)
}
if err != nil {
- gologger.Warning().Msgf("[%s] Could not execute step: %s\n", e.executerOpts.Colorizer.BrightBlue(template.ID), err)
+ gologger.Warning().Msgf("[%s] Could not execute step (self-contained): %s\n", e.executerOpts.Colorizer.BrightBlue(template.ID), err)
}
results.CompareAndSwap(false, match)
}(v)
@@ -140,7 +140,7 @@ func (e *Engine) executeTemplateWithTargets(ctx context.Context, template *templ
}
}
if err != nil {
- gologger.Warning().Msgf("[%s] Could not execute step: %s\n", e.executerOpts.Colorizer.BrightBlue(template.ID), err)
+ gologger.Warning().Msgf("[%s] Could not execute step on %s: %s\n", e.executerOpts.Colorizer.BrightBlue(template.ID), value.Input, err)
}
results.CompareAndSwap(false, match)
}(index, skip, scannedValue)
@@ -206,7 +206,7 @@ func (e *Engine) executeTemplatesOnTarget(ctx context.Context, alltemplates []*t
}
}
if err != nil {
- gologger.Warning().Msgf("[%s] Could not execute step: %s\n", e.executerOpts.Colorizer.BrightBlue(template.ID), err)
+ gologger.Warning().Msgf("[%s] Could not execute step on %s: %s\n", e.executerOpts.Colorizer.BrightBlue(template.ID), value.Input, err)
}
results.CompareAndSwap(false, match)
}(tpl, target, sg)
From f89a6d33e97c07220a0f3121cdb57cd88b0b97ef Mon Sep 17 00:00:00 2001
From: Shubham Rasal
Date: Mon, 16 Jun 2025 22:24:52 +0530
Subject: [PATCH 025/135] Use proxy for dns and ssl templates (#6255)
* Use proxy for dns and ssl templates
- while using template execute level function we need to override custom dialer
* rename overridedialer to customdialer
* Add proxy into hash
- proxy client is shared between non proxy requests
* add dialer into request object
- use request.dialer instead of global variable
* resolve comments
* rename dialer
---
pkg/protocols/dns/dns.go | 1 +
pkg/protocols/dns/dnsclientpool/clientpool.go | 10 +++++++++-
pkg/protocols/http/http.go | 12 ++++++++++++
pkg/protocols/http/request.go | 6 +++---
pkg/protocols/network/network.go | 8 +++-----
.../network/networkclientpool/clientpool.go | 9 ++++++++-
pkg/protocols/network/request.go | 8 ++++++--
pkg/protocols/protocols.go | 3 +++
pkg/protocols/ssl/ssl.go | 4 +++-
pkg/protocols/websocket/websocket.go | 4 +++-
10 files changed, 51 insertions(+), 14 deletions(-)
diff --git a/pkg/protocols/dns/dns.go b/pkg/protocols/dns/dns.go
index d6f462c44..198bb87bd 100644
--- a/pkg/protocols/dns/dns.go
+++ b/pkg/protocols/dns/dns.go
@@ -185,6 +185,7 @@ func (request *Request) Compile(options *protocols.ExecutorOptions) error {
func (request *Request) getDnsClient(options *protocols.ExecutorOptions, metadata map[string]interface{}) (*retryabledns.Client, error) {
dnsClientOptions := &dnsclientpool.Configuration{
Retries: request.Retries,
+ Proxy: options.Options.AliveSocksProxy,
}
if len(request.Resolvers) > 0 {
if len(request.Resolvers) > 0 {
diff --git a/pkg/protocols/dns/dnsclientpool/clientpool.go b/pkg/protocols/dns/dnsclientpool/clientpool.go
index 4f019808f..8eb19b8ba 100644
--- a/pkg/protocols/dns/dnsclientpool/clientpool.go
+++ b/pkg/protocols/dns/dnsclientpool/clientpool.go
@@ -51,6 +51,8 @@ type Configuration struct {
Retries int
// Resolvers contains the specific per request resolvers
Resolvers []string
+ // Proxy contains the proxy to use for the dns client
+ Proxy string
}
// Hash returns the hash of the configuration to allow client pooling
@@ -60,6 +62,8 @@ func (c *Configuration) Hash() string {
builder.WriteString(strconv.Itoa(c.Retries))
builder.WriteString("l")
builder.WriteString(strings.Join(c.Resolvers, ""))
+ builder.WriteString("p")
+ builder.WriteString(c.Proxy)
hash := builder.String()
return hash
}
@@ -83,7 +87,11 @@ func Get(options *types.Options, configuration *Configuration) (*retryabledns.Cl
} else if len(configuration.Resolvers) > 0 {
resolvers = configuration.Resolvers
}
- client, err := retryabledns.New(resolvers, configuration.Retries)
+ client, err := retryabledns.NewWithOptions(retryabledns.Options{
+ BaseResolvers: resolvers,
+ MaxRetries: configuration.Retries,
+ Proxy: options.AliveSocksProxy,
+ })
if err != nil {
return nil, errors.Wrap(err, "could not create dns client")
}
diff --git a/pkg/protocols/http/http.go b/pkg/protocols/http/http.go
index 0b30a7408..7a45fcd0d 100644
--- a/pkg/protocols/http/http.go
+++ b/pkg/protocols/http/http.go
@@ -11,6 +11,7 @@ import (
json "github.com/json-iterator/go"
"github.com/pkg/errors"
+ "github.com/projectdiscovery/fastdialer/fastdialer"
_ "github.com/projectdiscovery/nuclei/v3/pkg/fuzz/analyzers/time"
"github.com/projectdiscovery/nuclei/v3/pkg/fuzz"
@@ -22,6 +23,7 @@ import (
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/generators"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/protocolstate"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/http/httpclientpool"
+ "github.com/projectdiscovery/nuclei/v3/pkg/protocols/network/networkclientpool"
httputil "github.com/projectdiscovery/nuclei/v3/pkg/protocols/utils/http"
"github.com/projectdiscovery/nuclei/v3/pkg/utils/stats"
"github.com/projectdiscovery/rawhttp"
@@ -144,6 +146,7 @@ type Request struct {
generator *generators.PayloadGenerator // optional, only enabled when using payloads
httpClient *retryablehttp.Client
rawhttpClient *rawhttp.Client
+ dialer *fastdialer.Dialer
// description: |
// SelfContained specifies if the request is self-contained.
@@ -348,6 +351,15 @@ func (request *Request) Compile(options *protocols.ExecutorOptions) error {
}
request.customHeaders = make(map[string]string)
request.httpClient = client
+
+ dialer, err := networkclientpool.Get(options.Options, &networkclientpool.Configuration{
+ CustomDialer: options.CustomFastdialer,
+ })
+ if err != nil {
+ return errors.Wrap(err, "could not get dialer")
+ }
+ request.dialer = dialer
+
request.options = options
for _, option := range request.options.Options.CustomHeaders {
parts := strings.SplitN(option, ":", 2)
diff --git a/pkg/protocols/http/request.go b/pkg/protocols/http/request.go
index 6d8ad3e1d..090de2ed6 100644
--- a/pkg/protocols/http/request.go
+++ b/pkg/protocols/http/request.go
@@ -841,7 +841,7 @@ func (request *Request) executeRequest(input *contextargs.Context, generatedRequ
if input.MetaInput.CustomIP != "" {
outputEvent["ip"] = input.MetaInput.CustomIP
} else {
- outputEvent["ip"] = protocolstate.Dialer.GetDialedIP(hostname)
+ outputEvent["ip"] = request.dialer.GetDialedIP(hostname)
// try getting cname
request.addCNameIfAvailable(hostname, outputEvent)
}
@@ -1085,11 +1085,11 @@ func (request *Request) validateNFixEvent(input *contextargs.Context, gr *genera
// addCNameIfAvailable adds the cname to the event if available
func (request *Request) addCNameIfAvailable(hostname string, outputEvent map[string]interface{}) {
- if protocolstate.Dialer == nil {
+ if request.dialer == nil {
return
}
- data, err := protocolstate.Dialer.GetDNSData(hostname)
+ data, err := request.dialer.GetDNSData(hostname)
if err == nil {
switch len(data.CNAME) {
case 0:
diff --git a/pkg/protocols/network/network.go b/pkg/protocols/network/network.go
index 5c072affc..7aba6244a 100644
--- a/pkg/protocols/network/network.go
+++ b/pkg/protocols/network/network.go
@@ -237,7 +237,9 @@ func (request *Request) Compile(options *protocols.ExecutorOptions) error {
}
// Create a client for the class
- client, err := networkclientpool.Get(options.Options, &networkclientpool.Configuration{})
+ client, err := networkclientpool.Get(options.Options, &networkclientpool.Configuration{
+ CustomDialer: options.CustomFastdialer,
+ })
if err != nil {
return errors.Wrap(err, "could not get network client")
}
@@ -259,7 +261,3 @@ func (request *Request) Compile(options *protocols.ExecutorOptions) error {
func (request *Request) Requests() int {
return len(request.Address)
}
-
-func (request *Request) SetDialer(dialer *fastdialer.Dialer) {
- request.dialer = dialer
-}
diff --git a/pkg/protocols/network/networkclientpool/clientpool.go b/pkg/protocols/network/networkclientpool/clientpool.go
index a67cee296..6293a931e 100644
--- a/pkg/protocols/network/networkclientpool/clientpool.go
+++ b/pkg/protocols/network/networkclientpool/clientpool.go
@@ -21,7 +21,9 @@ func Init(options *types.Options) error {
}
// Configuration contains the custom configuration options for a client
-type Configuration struct{}
+type Configuration struct {
+ CustomDialer *fastdialer.Dialer
+}
// Hash returns the hash of the configuration to allow client pooling
func (c *Configuration) Hash() string {
@@ -30,5 +32,10 @@ func (c *Configuration) Hash() string {
// Get creates or gets a client for the protocol based on custom configuration
func Get(options *types.Options, configuration *Configuration /*TODO review unused parameters*/) (*fastdialer.Dialer, error) {
+
+ if configuration != nil && configuration.CustomDialer != nil {
+ return configuration.CustomDialer, nil
+ }
+
return normalClient, nil
}
diff --git a/pkg/protocols/network/request.go b/pkg/protocols/network/request.go
index f7b11fbb5..197ef5332 100644
--- a/pkg/protocols/network/request.go
+++ b/pkg/protocols/network/request.go
@@ -25,9 +25,9 @@ import (
"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/interactsh"
- "github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/protocolstate"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/replacer"
"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"
templateTypes "github.com/projectdiscovery/nuclei/v3/pkg/templates/types"
errorutil "github.com/projectdiscovery/utils/errors"
@@ -64,7 +64,11 @@ func (request *Request) getOpenPorts(target *contextargs.Context) ([]string, err
errs = append(errs, err)
continue
}
- conn, err := protocolstate.Dialer.Dial(target.Context(), "tcp", addr)
+ if request.dialer == nil {
+ request.dialer, _ = networkclientpool.Get(request.options.Options, &networkclientpool.Configuration{})
+ }
+
+ conn, err := request.dialer.Dial(target.Context(), "tcp", addr)
if err != nil {
errs = append(errs, err)
continue
diff --git a/pkg/protocols/protocols.go b/pkg/protocols/protocols.go
index 7b7f71d48..6b5c089be 100644
--- a/pkg/protocols/protocols.go
+++ b/pkg/protocols/protocols.go
@@ -5,6 +5,7 @@ import (
"encoding/base64"
"sync/atomic"
+ "github.com/projectdiscovery/fastdialer/fastdialer"
"github.com/projectdiscovery/ratelimit"
mapsutil "github.com/projectdiscovery/utils/maps"
stringsutil "github.com/projectdiscovery/utils/strings"
@@ -132,6 +133,8 @@ type ExecutorOptions struct {
ExportReqURLPattern bool
// GlobalMatchers is the storage for global matchers with http passive templates
GlobalMatchers *globalmatchers.Storage
+ // CustomFastdialer is a fastdialer dialer instance
+ CustomFastdialer *fastdialer.Dialer
}
// todo: centralizing components is not feasible with current clogged architecture
diff --git a/pkg/protocols/ssl/ssl.go b/pkg/protocols/ssl/ssl.go
index fd0dae83d..8943d597d 100644
--- a/pkg/protocols/ssl/ssl.go
+++ b/pkg/protocols/ssl/ssl.go
@@ -115,7 +115,9 @@ func (request *Request) IsClusterable() bool {
func (request *Request) Compile(options *protocols.ExecutorOptions) error {
request.options = options
- client, err := networkclientpool.Get(options.Options, &networkclientpool.Configuration{})
+ client, err := networkclientpool.Get(options.Options, &networkclientpool.Configuration{
+ CustomDialer: options.CustomFastdialer,
+ })
if err != nil {
return errorutil.NewWithTag("ssl", "could not get network client").Wrap(err)
}
diff --git a/pkg/protocols/websocket/websocket.go b/pkg/protocols/websocket/websocket.go
index 8eeeedf21..02cf75190 100644
--- a/pkg/protocols/websocket/websocket.go
+++ b/pkg/protocols/websocket/websocket.go
@@ -100,7 +100,9 @@ const (
func (request *Request) Compile(options *protocols.ExecutorOptions) error {
request.options = options
- client, err := networkclientpool.Get(options.Options, &networkclientpool.Configuration{})
+ client, err := networkclientpool.Get(options.Options, &networkclientpool.Configuration{
+ CustomDialer: options.CustomFastdialer,
+ })
if err != nil {
return errors.Wrap(err, "could not get network client")
}
From 797ceb57dbc1600acf6f90bcc5becee99b5cd377 Mon Sep 17 00:00:00 2001
From: Dwi Siswanto <25837540+dwisiswant0@users.noreply.github.com>
Date: Tue, 17 Jun 2025 06:18:05 +0700
Subject: [PATCH 026/135] fix(authx): JSON unmarshalling for Dynamic auth type
(#6268)
* fix(authx): JSON unmarshalling for Dynamic auth type
Correcting the `UnmarshalJSON` method to properly
unmarshal JSON, particularlyaddressing the
population of the embedded `Secret` field. This
was achieved by using a type alias to avoid
recursive calls and rely on default unmarshalling
behavior.
Signed-off-by: Dwi Siswanto
* feat(authx): adds nil Dynamic struct check
Signed-off-by: Dwi Siswanto
---------
Signed-off-by: Dwi Siswanto
---
pkg/authprovider/authx/dynamic.go | 17 ++--
pkg/authprovider/authx/dynamic_test.go | 125 +++++++++++++++++++++++++
2 files changed, 136 insertions(+), 6 deletions(-)
create mode 100644 pkg/authprovider/authx/dynamic_test.go
diff --git a/pkg/authprovider/authx/dynamic.go b/pkg/authprovider/authx/dynamic.go
index 0efee1ea6..f3e361e41 100644
--- a/pkg/authprovider/authx/dynamic.go
+++ b/pkg/authprovider/authx/dynamic.go
@@ -52,14 +52,19 @@ func (d *Dynamic) GetDomainAndDomainRegex() ([]string, []string) {
}
func (d *Dynamic) UnmarshalJSON(data []byte) error {
- if err := json.Unmarshal(data, &d); err != nil {
+ if d == nil {
+ return errorutil.New("cannot unmarshal into nil Dynamic struct")
+ }
+
+ // Use an alias type (auxiliary) to avoid a recursive call in this method.
+ type Alias Dynamic
+
+ // If d.Secret was nil, json.Unmarshal will allocate a new Secret object
+ // and populate it from the top level JSON fields.
+ if err := json.Unmarshal(data, (*Alias)(d)); err != nil {
return err
}
- var s Secret
- if err := json.Unmarshal(data, &s); err != nil {
- return err
- }
- d.Secret = &s
+
return nil
}
diff --git a/pkg/authprovider/authx/dynamic_test.go b/pkg/authprovider/authx/dynamic_test.go
new file mode 100644
index 000000000..05bf9c134
--- /dev/null
+++ b/pkg/authprovider/authx/dynamic_test.go
@@ -0,0 +1,125 @@
+package authx
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/require"
+)
+
+func TestDynamicUnmarshalJSON(t *testing.T) {
+ t.Run("basic-unmarshal", func(t *testing.T) {
+ data := []byte(`{
+ "template": "test-template.yaml",
+ "variables": [
+ {
+ "key": "username",
+ "value": "testuser"
+ }
+ ],
+ "secrets": [
+ {
+ "type": "BasicAuth",
+ "domains": ["example.com"],
+ "username": "user1",
+ "password": "pass1"
+ }
+ ],
+ "type": "BasicAuth",
+ "domains": ["test.com"],
+ "username": "testuser",
+ "password": "testpass"
+ }`)
+
+ var d Dynamic
+ err := d.UnmarshalJSON(data)
+ require.NoError(t, err)
+
+ // Secret
+ require.NotNil(t, d.Secret)
+ require.Equal(t, "BasicAuth", d.Secret.Type)
+ require.Equal(t, []string{"test.com"}, d.Secret.Domains)
+ require.Equal(t, "testuser", d.Secret.Username)
+ require.Equal(t, "testpass", d.Secret.Password)
+
+ // Dynamic fields
+ require.Equal(t, "test-template.yaml", d.TemplatePath)
+ require.Len(t, d.Variables, 1)
+ require.Equal(t, "username", d.Variables[0].Key)
+ require.Equal(t, "testuser", d.Variables[0].Value)
+ require.Len(t, d.Secrets, 1)
+ require.Equal(t, "BasicAuth", d.Secrets[0].Type)
+ require.Equal(t, []string{"example.com"}, d.Secrets[0].Domains)
+ require.Equal(t, "user1", d.Secrets[0].Username)
+ require.Equal(t, "pass1", d.Secrets[0].Password)
+ })
+
+ t.Run("complex-unmarshal", func(t *testing.T) {
+ data := []byte(`{
+ "template": "test-template.yaml",
+ "variables": [
+ {
+ "key": "token",
+ "value": "Bearer xyz"
+ }
+ ],
+ "secrets": [
+ {
+ "type": "CookiesAuth",
+ "domains": ["example.com"],
+ "cookies": [
+ {
+ "key": "session",
+ "value": "abc123"
+ }
+ ]
+ }
+ ],
+ "type": "HeadersAuth",
+ "domains": ["api.test.com"],
+ "headers": [
+ {
+ "key": "X-API-Key",
+ "value": "secret-key"
+ }
+ ]
+ }`)
+
+ var d Dynamic
+ err := d.UnmarshalJSON(data)
+ require.NoError(t, err)
+
+ // Secret
+ require.NotNil(t, d.Secret)
+ require.Equal(t, "HeadersAuth", d.Secret.Type)
+ require.Equal(t, []string{"api.test.com"}, d.Secret.Domains)
+ require.Len(t, d.Secret.Headers, 1)
+ require.Equal(t, "X-API-Key", d.Secret.Headers[0].Key)
+ require.Equal(t, "secret-key", d.Secret.Headers[0].Value)
+
+ // Dynamic fields
+ require.Equal(t, "test-template.yaml", d.TemplatePath)
+ require.Len(t, d.Variables, 1)
+ require.Equal(t, "token", d.Variables[0].Key)
+ require.Equal(t, "Bearer xyz", d.Variables[0].Value)
+ require.Len(t, d.Secrets, 1)
+ require.Equal(t, "CookiesAuth", d.Secrets[0].Type)
+ require.Equal(t, []string{"example.com"}, d.Secrets[0].Domains)
+ require.Len(t, d.Secrets[0].Cookies, 1)
+ require.Equal(t, "session", d.Secrets[0].Cookies[0].Key)
+ require.Equal(t, "abc123", d.Secrets[0].Cookies[0].Value)
+ })
+
+ t.Run("invalid-json", func(t *testing.T) {
+ data := []byte(`{invalid json}`)
+ var d Dynamic
+ err := d.UnmarshalJSON(data)
+ require.Error(t, err)
+ })
+
+ t.Run("empty-json", func(t *testing.T) {
+ data := []byte(`{}`)
+ var d Dynamic
+ err := d.UnmarshalJSON(data)
+ require.NoError(t, err)
+ })
+}
From a326f3925c5a00c8d8c214cdf839bf8075fe0cbe Mon Sep 17 00:00:00 2001
From: Dwi Siswanto <25837540+dwisiswant0@users.noreply.github.com>
Date: Tue, 17 Jun 2025 06:23:32 +0700
Subject: [PATCH 027/135] fix(tmplexec): memory blowup in multiproto (#6258)
* bugfix: fix memory blowup using previousEvent for multi-proto execution
* refactor(tmplexec): uses supported protocol types
Signed-off-by: Dwi Siswanto
* add co-author
Co-authored-by: Nakul Bharti
Signed-off-by: Dwi Siswanto
* refactor(tmplexec): mv builder inside loop scope
Signed-off-by: Dwi Siswanto
* refactor(tmplexec): skip existing keys in `FillPreviousEvent`
The `FillPreviousEvent` func was modified to
prevent overwriting/duplicating entries in the
previous map.
It now checks if a key `k` from
`event.InternalEvent` already exists in the
previous map. If it does, the key is skipped. This
ensures that if `k` was already set (potentially
w/o a prefix), it's not re-added with an `ID_`
prefix.
Additionally, keys in `event.InternalEvent` that
already start with the current `ID_` prefix are
also skipped to avoid redundant prefixing.
This change simplifies the logic by removing the
`reqTypeWithIndexRegex` and directly addresses the
potential for duplicate / incorrectly prefixed
keys when `event.InternalEvent` grows during
protocol request execution.
Signed-off-by: Dwi Siswanto
* chore(tmplexec): naming convention, `ID` => `protoID`
Signed-off-by: Dwi Siswanto
* chore(tmplexec): it's request ID lol sorry
Signed-off-by: Dwi Siswanto
---------
Signed-off-by: Dwi Siswanto
Co-authored-by: Ice3man
Co-authored-by: Nakul Bharti
---
pkg/tmplexec/generic/exec.go | 16 ++++-----------
pkg/tmplexec/multiproto/multi.go | 14 ++-----------
pkg/tmplexec/utils/utils.go | 34 ++++++++++++++++++++++++++++++++
3 files changed, 40 insertions(+), 24 deletions(-)
create mode 100644 pkg/tmplexec/utils/utils.go
diff --git a/pkg/tmplexec/generic/exec.go b/pkg/tmplexec/generic/exec.go
index c017810e7..25f88262e 100644
--- a/pkg/tmplexec/generic/exec.go
+++ b/pkg/tmplexec/generic/exec.go
@@ -1,13 +1,13 @@
package generic
import (
- "strings"
"sync/atomic"
"github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/nuclei/v3/pkg/output"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols"
"github.com/projectdiscovery/nuclei/v3/pkg/scan"
+ "github.com/projectdiscovery/nuclei/v3/pkg/tmplexec/utils"
mapsutil "github.com/projectdiscovery/utils/maps"
)
@@ -64,17 +64,9 @@ func (g *Generic) ExecuteWithResults(ctx *scan.ScanContext) error {
// ideally this should never happen since protocol exits on error and callback is not called
return
}
- ID := req.GetID()
- if ID != "" {
- builder := &strings.Builder{}
- for k, v := range event.InternalEvent {
- builder.WriteString(ID)
- builder.WriteString("_")
- builder.WriteString(k)
- _ = previous.Set(builder.String(), v)
- builder.Reset()
- }
- }
+
+ utils.FillPreviousEvent(req.GetID(), event, previous)
+
if event.HasOperatorResult() {
g.results.CompareAndSwap(false, true)
}
diff --git a/pkg/tmplexec/multiproto/multi.go b/pkg/tmplexec/multiproto/multi.go
index d50e168ac..ef029861a 100644
--- a/pkg/tmplexec/multiproto/multi.go
+++ b/pkg/tmplexec/multiproto/multi.go
@@ -2,7 +2,6 @@ package multiproto
import (
"strconv"
- "strings"
"sync/atomic"
"github.com/projectdiscovery/nuclei/v3/pkg/output"
@@ -10,6 +9,7 @@ import (
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/generators"
"github.com/projectdiscovery/nuclei/v3/pkg/scan"
"github.com/projectdiscovery/nuclei/v3/pkg/templates/types"
+ "github.com/projectdiscovery/nuclei/v3/pkg/tmplexec/utils"
mapsutil "github.com/projectdiscovery/utils/maps"
stringsutil "github.com/projectdiscovery/utils/strings"
)
@@ -90,17 +90,7 @@ func (m *MultiProtocol) ExecuteWithResults(ctx *scan.ScanContext) error {
return
}
- ID := req.GetID()
- if ID != "" {
- builder := &strings.Builder{}
- for k, v := range event.InternalEvent {
- builder.WriteString(ID)
- builder.WriteString("_")
- builder.WriteString(k)
- _ = previous.Set(builder.String(), v)
- builder.Reset()
- }
- }
+ utils.FillPreviousEvent(req.GetID(), event, previous)
// log event and generate result for the event
ctx.LogEvent(event)
diff --git a/pkg/tmplexec/utils/utils.go b/pkg/tmplexec/utils/utils.go
new file mode 100644
index 000000000..41d717769
--- /dev/null
+++ b/pkg/tmplexec/utils/utils.go
@@ -0,0 +1,34 @@
+package utils
+
+import (
+ "strings"
+
+ "github.com/projectdiscovery/nuclei/v3/pkg/output"
+ mapsutil "github.com/projectdiscovery/utils/maps"
+)
+
+// FillPreviousEvent is a helper function to get the previous event from the event
+// without leading to duplicate prefixes
+func FillPreviousEvent(reqID string, event *output.InternalWrappedEvent, previous *mapsutil.SyncLockMap[string, any]) {
+ if reqID == "" {
+ return
+ }
+
+ for k, v := range event.InternalEvent {
+ if _, ok := previous.Get(k); ok {
+ continue
+ }
+
+ if strings.HasPrefix(k, reqID+"_") {
+ continue
+ }
+
+ var builder strings.Builder
+
+ builder.WriteString(reqID)
+ builder.WriteString("_")
+ builder.WriteString(k)
+
+ _ = previous.Set(builder.String(), v)
+ }
+}
From 61bcf0f10ec8296b9aacc2165e91040ba1b3066f Mon Sep 17 00:00:00 2001
From: Dwi Siswanto <25837540+dwisiswant0@users.noreply.github.com>
Date: Tue, 17 Jun 2025 06:30:31 +0700
Subject: [PATCH 028/135] feat(headless): store responses (#6247)
Signed-off-by: Dwi Siswanto
---
pkg/protocols/headless/request.go | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/pkg/protocols/headless/request.go b/pkg/protocols/headless/request.go
index af65c4b2f..22a33bf7f 100644
--- a/pkg/protocols/headless/request.go
+++ b/pkg/protocols/headless/request.go
@@ -223,10 +223,15 @@ func (request *Request) executeRequestWithPayloads(input *contextargs.Context, p
}
func dumpResponse(event *output.InternalWrappedEvent, requestOptions *protocols.ExecutorOptions, responseBody string, input string) {
- cliOptions := requestOptions.Options
- if cliOptions.Debug || cliOptions.DebugResponse {
- highlightedResponse := responsehighlighter.Highlight(event.OperatorsResult, responseBody, cliOptions.NoColor, false)
- gologger.Debug().Msgf("[%s] Dumped Headless response for %s\n\n%s", requestOptions.TemplateID, input, highlightedResponse)
+ if requestOptions.Options.Debug || requestOptions.Options.DebugResponse || requestOptions.Options.StoreResponse {
+ msg := fmt.Sprintf("[%s] Dumped Headless response for %s\n\n", requestOptions.TemplateID, input)
+ if requestOptions.Options.Debug || requestOptions.Options.DebugResponse {
+ resp := responsehighlighter.Highlight(event.OperatorsResult, responseBody, requestOptions.Options.NoColor, false)
+ gologger.Debug().Msgf("%s%s", msg, resp)
+ }
+ if requestOptions.Options.StoreResponse {
+ requestOptions.Output.WriteStoreDebugData(input, requestOptions.TemplateID, "headless", fmt.Sprintf("%s%s", msg, responseBody))
+ }
}
}
From b95b04fc4dc300a6340d5d360437217f188ff594 Mon Sep 17 00:00:00 2001
From: Eric Gruber
Date: Mon, 16 Jun 2025 18:38:01 -0500
Subject: [PATCH 029/135] feat: add EnableMatcherStatus function to configure
matcher status in NucleiEngine (#6191)
---
lib/config.go | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/lib/config.go b/lib/config.go
index 46df00aa2..f570a0729 100644
--- a/lib/config.go
+++ b/lib/config.go
@@ -463,6 +463,14 @@ func EnablePassiveMode() NucleiSDKOptions {
}
}
+// EnableMatcherStatus allows enabling matcher status
+func EnableMatcherStatus() NucleiSDKOptions {
+ return func(e *NucleiEngine) error {
+ e.opts.MatcherStatus = true
+ return nil
+ }
+}
+
// WithAuthProvider allows setting a custom authprovider implementation
func WithAuthProvider(provider authprovider.AuthProvider) NucleiSDKOptions {
return func(e *NucleiEngine) error {
From 5af6feb88958f1433dbc22bed5e6c7fa5daf3a14 Mon Sep 17 00:00:00 2001
From: sandeep <8293321+ehsandeep@users.noreply.github.com>
Date: Tue, 17 Jun 2025 05:12:02 +0530
Subject: [PATCH 030/135] version update
---
pkg/catalog/config/constants.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pkg/catalog/config/constants.go b/pkg/catalog/config/constants.go
index 147cf23a2..f7036431a 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.4`
+ Version = `v3.4.5`
// Directory Names of custom templates
CustomS3TemplatesDirName = "s3"
CustomGitHubTemplatesDirName = "github"
From aba8c47e10d165e33a966ecb6f270b334834b9fe Mon Sep 17 00:00:00 2001
From: knakul853
Date: Tue, 17 Jun 2025 17:02:57 +0530
Subject: [PATCH 031/135] fixed log level mismatch
---
pkg/operators/common/dsl/dsl.go | 2 +-
pkg/output/output.go | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/pkg/operators/common/dsl/dsl.go b/pkg/operators/common/dsl/dsl.go
index 1b3a02bed..56ac06509 100644
--- a/pkg/operators/common/dsl/dsl.go
+++ b/pkg/operators/common/dsl/dsl.go
@@ -114,7 +114,7 @@ func init() {
}))
dsl.PrintDebugCallback = func(args ...interface{}) error {
- gologger.Info().Msgf("print_debug value: %s", fmt.Sprint(args))
+ gologger.Debug().Msgf("print_debug value: %s", fmt.Sprint(args))
return nil
}
diff --git a/pkg/output/output.go b/pkg/output/output.go
index e85774b83..02b62f6e1 100644
--- a/pkg/output/output.go
+++ b/pkg/output/output.go
@@ -560,7 +560,7 @@ func (w *StandardWriter) WriteStoreDebugData(host, templateID, eventType string,
filename = filepath.Join(subFolder, fmt.Sprintf("%s.txt", filename))
f, err := os.OpenFile(filename, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644)
if err != nil {
- fmt.Print(err)
+ gologger.Error().Msgf("Could not open debug output file: %s", err)
return
}
_, _ = f.WriteString(fmt.Sprintln(data))
From c242b112ccef37321144cb1d4a795a5d71255a15 Mon Sep 17 00:00:00 2001
From: Nakul Bharti
Date: Thu, 19 Jun 2025 20:07:59 +0530
Subject: [PATCH 032/135] fixed hex dump issue (#6273)
---
pkg/protocols/http/request.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pkg/protocols/http/request.go b/pkg/protocols/http/request.go
index 090de2ed6..14599f690 100644
--- a/pkg/protocols/http/request.go
+++ b/pkg/protocols/http/request.go
@@ -1156,7 +1156,7 @@ func dumpResponse(event *output.InternalWrappedEvent, request *Request, redirect
response := string(redirectedResponse)
var highlightedResult string
- if responseContentType == "application/octet-stream" || ((responseContentType == "" || responseContentType == "application/x-www-form-urlencoded") && responsehighlighter.HasBinaryContent(response)) {
+ if (responseContentType == "application/octet-stream" || responseContentType == "application/x-www-form-urlencoded") && responsehighlighter.HasBinaryContent(response) {
highlightedResult = createResponseHexDump(event, response, cliOptions.NoColor)
} else {
highlightedResult = responsehighlighter.Highlight(event.OperatorsResult, response, cliOptions.NoColor, false)
From 695a7520b976191bd814b48a4789265d7cbad3fa Mon Sep 17 00:00:00 2001
From: Dwi Siswanto <25837540+dwisiswant0@users.noreply.github.com>
Date: Tue, 24 Jun 2025 07:02:18 +0700
Subject: [PATCH 033/135] fix(headless): incorrect last navigated URL (#6278)
* chore(headless): uses `maps.Copy`
Signed-off-by: Dwi Siswanto
* feat(headless): implements update last navigated URL
for `ActionNavigate`, `WaitPageLifecycleEvent`, and
`WaitStable` based on latest navigation URL.
Signed-off-by: Dwi Siswanto
* Update pkg/protocols/headless/engine/page.go
---------
Signed-off-by: Dwi Siswanto
---
pkg/protocols/headless/engine/page.go | 38 ++++++++++++-------
pkg/protocols/headless/engine/page_actions.go | 21 ++++++++--
pkg/protocols/headless/request.go | 11 ++----
3 files changed, 46 insertions(+), 24 deletions(-)
diff --git a/pkg/protocols/headless/engine/page.go b/pkg/protocols/headless/engine/page.go
index fd8687e14..4dca72a6a 100644
--- a/pkg/protocols/headless/engine/page.go
+++ b/pkg/protocols/headless/engine/page.go
@@ -24,19 +24,20 @@ import (
// Page is a single page in an isolated browser instance
type Page struct {
- ctx *contextargs.Context
- inputURL *urlutil.URL
- options *Options
- page *rod.Page
- rules []rule
- instance *Instance
- hijackRouter *rod.HijackRouter
- hijackNative *Hijack
- mutex *sync.RWMutex
- History []HistoryData
- InteractshURLs []string
- payloads map[string]interface{}
- variables map[string]interface{}
+ ctx *contextargs.Context
+ inputURL *urlutil.URL
+ options *Options
+ page *rod.Page
+ rules []rule
+ instance *Instance
+ hijackRouter *rod.HijackRouter
+ hijackNative *Hijack
+ mutex *sync.RWMutex
+ History []HistoryData
+ InteractshURLs []string
+ payloads map[string]interface{}
+ variables map[string]interface{}
+ lastActionNavigate *Action
}
// HistoryData contains the page request/response pairs
@@ -274,6 +275,17 @@ func (p *Page) hasModificationRules() bool {
return false
}
+// updateLastNavigatedURL updates the last navigated URL in the instance's
+// request log.
+func (p *Page) updateLastNavigatedURL() {
+ if p.lastActionNavigate == nil {
+ return
+ }
+
+ templateURL := p.lastActionNavigate.GetArg("url")
+ p.instance.requestLog[templateURL] = p.URL()
+}
+
func containsModificationActions(actions ...*Action) bool {
for _, action := range actions {
if containsAnyModificationActionType(action.ActionType.ActionType) {
diff --git a/pkg/protocols/headless/engine/page_actions.go b/pkg/protocols/headless/engine/page_actions.go
index a0b001daf..204ce8eea 100644
--- a/pkg/protocols/headless/engine/page_actions.go
+++ b/pkg/protocols/headless/engine/page_actions.go
@@ -47,6 +47,7 @@ const (
// ExecuteActions executes a list of actions on a page.
func (p *Page) ExecuteActions(input *contextargs.Context, actions []*Action) (outData ActionData, err error) {
outData = make(ActionData)
+
// waitFuncs are function that needs to be executed after navigation
// typically used for waitEvent
waitFuncs := make([]func() error, 0)
@@ -76,6 +77,8 @@ func (p *Page) ExecuteActions(input *contextargs.Context, actions []*Action) (ou
}
}
}
+
+ p.lastActionNavigate = act
}
case ActionScript:
err = p.RunScript(act, outData)
@@ -407,12 +410,12 @@ func (p *Page) NavigateURL(action *Action, out ActionData) error {
finalparams.Merge(p.inputURL.Params.Encode())
parsedURL.Params = finalparams
- // log all navigated requests
- p.instance.requestLog[action.GetArg("url")] = parsedURL.String()
-
if err := p.page.Navigate(parsedURL.String()); err != nil {
return errorutil.NewWithErr(err).Msgf("could not navigate to url %s", parsedURL.String())
}
+
+ p.updateLastNavigatedURL()
+
return nil
}
@@ -667,6 +670,9 @@ func (p *Page) WaitPageLifecycleEvent(act *Action, out ActionData, event proto.P
fn()
+ // log the navigated request (even if it is a redirect)
+ p.updateLastNavigatedURL()
+
return nil
}
@@ -687,7 +693,14 @@ func (p *Page) WaitStable(act *Action, out ActionData) error {
}
}
- return p.page.Timeout(timeout).WaitStable(dur)
+ if err := p.page.Timeout(timeout).WaitStable(dur); err != nil {
+ return err
+ }
+
+ // log the navigated request (even if it is a redirect)
+ p.updateLastNavigatedURL()
+
+ return nil
}
// GetResource gets a resource from an element from page.
diff --git a/pkg/protocols/headless/request.go b/pkg/protocols/headless/request.go
index 22a33bf7f..83280ee63 100644
--- a/pkg/protocols/headless/request.go
+++ b/pkg/protocols/headless/request.go
@@ -2,6 +2,7 @@ package headless
import (
"fmt"
+ "maps"
"net/url"
"strings"
"time"
@@ -9,7 +10,6 @@ import (
"github.com/projectdiscovery/retryablehttp-go"
"github.com/pkg/errors"
- "golang.org/x/exp/maps"
"github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/nuclei/v3/pkg/fuzz"
@@ -189,12 +189,9 @@ func (request *Request) executeRequestWithPayloads(input *contextargs.Context, p
if request.options.HasTemplateCtx(input.MetaInput) {
outputEvent = generators.MergeMaps(outputEvent, request.options.GetTemplateCtx(input.MetaInput).GetAll())
}
- for k, v := range out {
- outputEvent[k] = v
- }
- for k, v := range payloads {
- outputEvent[k] = v
- }
+
+ maps.Copy(outputEvent, out)
+ maps.Copy(outputEvent, payloads)
var event *output.InternalWrappedEvent
if len(page.InteractshURLs) == 0 {
From 4ff80784aed47212cb27c474eaad45f9ceed05ab Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9B=B9=E5=AE=B6=E5=B7=A7?=
Date: Tue, 24 Jun 2025 08:19:06 +0800
Subject: [PATCH 034/135] refactor: use the built-in max/min to simplify the
code (#6272)
Signed-off-by: xiaoxiangirl
---
cmd/integration-test/http.go | 5 +----
pkg/protocols/http/request.go | 5 +----
2 files changed, 2 insertions(+), 8 deletions(-)
diff --git a/cmd/integration-test/http.go b/cmd/integration-test/http.go
index be75506cb..f0e5d1ae2 100644
--- a/cmd/integration-test/http.go
+++ b/cmd/integration-test/http.go
@@ -829,10 +829,7 @@ func (h *httpPaths) Execute(filepath string) error {
}
if len(expected) > len(actual) {
- actualValuesIndex := len(actual) - 1
- if actualValuesIndex < 0 {
- actualValuesIndex = 0
- }
+ actualValuesIndex := max(len(actual)-1, 0)
return fmt.Errorf("missing values : %v", expected[actualValuesIndex:])
} else if len(expected) < len(actual) {
return fmt.Errorf("unexpected values : %v", actual[len(expected)-1:])
diff --git a/pkg/protocols/http/request.go b/pkg/protocols/http/request.go
index 14599f690..f401fe4cf 100644
--- a/pkg/protocols/http/request.go
+++ b/pkg/protocols/http/request.go
@@ -336,11 +336,8 @@ func (request *Request) executeTurboHTTP(input *contextargs.Context, dynamicValu
pipeClient := rawhttp.NewPipelineClient(pipeOptions)
// defaultMaxWorkers should be a sufficient value to keep queues always full
- maxWorkers := defaultMaxWorkers
// in case the queue is bigger increase the workers
- if pipeOptions.MaxPendingRequests > maxWorkers {
- maxWorkers = pipeOptions.MaxPendingRequests
- }
+ maxWorkers := max(pipeOptions.MaxPendingRequests, defaultMaxWorkers)
// Stop-at-first-match logic while executing requests
// parallely using threads
From 248548e075db5822710c12a5336d8503e4c8e040 Mon Sep 17 00:00:00 2001
From: Alban Stourbe
Date: Tue, 24 Jun 2025 18:32:45 +0200
Subject: [PATCH 035/135] feat(ytt): add ytt files var + add vars from cli and
config
---
cmd/nuclei/main.go | 31 +++++++++++++++
integration_tests/fuzz/fuzz-body.yaml | 38 +++++++++++++++++++
pkg/input/formats/formats.go | 2 +
.../testdata/{ => ytt}/ginandjuice.ytt.yaml | 9 ++---
.../formats/testdata/ytt/ytt-profile.yaml | 10 +++++
pkg/input/formats/testdata/ytt/ytt-vars.yaml | 3 ++
pkg/input/formats/yaml/multidoc.go | 2 +-
pkg/input/formats/yaml/ytt.go | 7 +++-
pkg/input/provider/interface.go | 1 +
pkg/types/types.go | 2 +
10 files changed, 98 insertions(+), 7 deletions(-)
create mode 100644 integration_tests/fuzz/fuzz-body.yaml
rename pkg/input/formats/testdata/{ => ytt}/ginandjuice.ytt.yaml (71%)
create mode 100644 pkg/input/formats/testdata/ytt/ytt-profile.yaml
create mode 100644 pkg/input/formats/testdata/ytt/ytt-vars.yaml
diff --git a/cmd/nuclei/main.go b/cmd/nuclei/main.go
index e1a3bfb1c..13fb0d69d 100644
--- a/cmd/nuclei/main.go
+++ b/cmd/nuclei/main.go
@@ -18,6 +18,7 @@ import (
"github.com/projectdiscovery/utils/env"
_ "github.com/projectdiscovery/utils/pprof"
stringsutil "github.com/projectdiscovery/utils/strings"
+ "gopkg.in/yaml.v2"
"github.com/projectdiscovery/goflags"
"github.com/projectdiscovery/gologger"
@@ -261,6 +262,7 @@ on extensive configurability, massive extensibility and ease of use.`)
flagSet.BoolVarP(&options.FormatUseRequiredOnly, "required-only", "ro", false, "use only required fields in input format when generating requests"),
flagSet.BoolVarP(&options.SkipFormatValidation, "skip-format-validation", "sfv", false, "skip format validation (like missing vars) when parsing input file"),
flagSet.BoolVarP(&options.VarsTextTemplating, "vars-text-templating", "vtt", false, "enable text templating for vars in input file (only for yaml input mode)"),
+ flagSet.StringSliceVarP(&options.VarsFilePaths, "var-file-paths", "vfp", nil, "list of yaml file contained vars to inject into yaml input", goflags.CommaSeparatedStringSliceOptions),
)
flagSet.CreateGroup("templates", "Templates",
@@ -569,6 +571,7 @@ Additional documentation is available at: https://docs.nuclei.sh/getting-started
config.DefaultConfig.SetConfigDir(customConfigDir)
readFlagsConfig(flagSet)
}
+
if cfgFile != "" {
if !fileutil.FileExists(cfgFile) {
gologger.Fatal().Msgf("given config file '%s' does not exist", cfgFile)
@@ -577,6 +580,34 @@ Additional documentation is available at: https://docs.nuclei.sh/getting-started
if err := flagSet.MergeConfigFile(cfgFile); err != nil {
gologger.Fatal().Msgf("Could not read config: %s\n", err)
}
+
+ if !options.Vars.IsEmpty() {
+ // Maybe we should add vars to the config file as well?
+ file, err := os.Open(cfgFile)
+ if err != nil {
+ gologger.Fatal().Msgf("Could not open config file: %s\n", err)
+ }
+ defer file.Close()
+ data := make(map[string]interface{})
+ err = yaml.NewDecoder(file).Decode(&data)
+ if err != nil {
+ gologger.Fatal().Msgf("Could not decode config file: %s\n", err)
+ }
+
+ variables := data["var"]
+ if variables != nil {
+ for _, value := range variables.([]interface{}) {
+ if strVal, ok := value.(string); ok {
+ options.Vars.Set(strVal)
+ } else {
+ gologger.Warning().Msgf("Skipping non-string variable in config: %#v", value)
+ }
+ }
+ } else {
+ gologger.Warning().Msgf("No 'var' section found in config file: %s", cfgFile)
+ }
+
+ }
}
if options.NewTemplatesDirectory != "" {
config.DefaultConfig.SetTemplatesDir(options.NewTemplatesDirectory)
diff --git a/integration_tests/fuzz/fuzz-body.yaml b/integration_tests/fuzz/fuzz-body.yaml
new file mode 100644
index 000000000..01a3006f6
--- /dev/null
+++ b/integration_tests/fuzz/fuzz-body.yaml
@@ -0,0 +1,38 @@
+id: fuzz-body
+
+info:
+ name: fuzzing error sqli payloads in http req body
+ author: pdteam
+ severity: info
+ description: |
+ This template attempts to find SQL injection vulnerabilities by fuzzing http body
+ It automatically handles and parses json,xml,multipart form and x-www-form-urlencoded data
+ and performs fuzzing on the value of every key
+
+http:
+ - pre-condition:
+ - type: dsl
+ dsl:
+ - method != "GET"
+ - method != "HEAD"
+ condition: and
+
+ payloads:
+ injection:
+ - "'"
+ - "\""
+ - ";"
+
+ fuzzing:
+ - part: body
+ type: postfix
+ mode: single
+ fuzz:
+ - '{{injection}}'
+
+ stop-at-first-match: true
+ matchers:
+ - type: word
+ words:
+ - "unrecognized token:"
+ - "null"
diff --git a/pkg/input/formats/formats.go b/pkg/input/formats/formats.go
index a23ff5d06..acc6c31d4 100644
--- a/pkg/input/formats/formats.go
+++ b/pkg/input/formats/formats.go
@@ -32,6 +32,8 @@ type InputFormatOptions struct {
// this is used for text templating of variables based on carvel ytt
// Only available for Yaml formats
VarsTextTemplating bool
+ // VarsFilePaths is the path to the file containing variables
+ VarsFilePaths []string
}
// Format is an interface implemented by all input formats
diff --git a/pkg/input/formats/testdata/ginandjuice.ytt.yaml b/pkg/input/formats/testdata/ytt/ginandjuice.ytt.yaml
similarity index 71%
rename from pkg/input/formats/testdata/ginandjuice.ytt.yaml
rename to pkg/input/formats/testdata/ytt/ginandjuice.ytt.yaml
index f1889a67f..a43bca070 100644
--- a/pkg/input/formats/testdata/ginandjuice.ytt.yaml
+++ b/pkg/input/formats/testdata/ytt/ginandjuice.ytt.yaml
@@ -1,10 +1,9 @@
#@ load("@ytt:data", "data")
-#@ load("@ytt:assert", "assert")
+#@ load("@ytt:json", "json")
#@ def get_value(key, default=""):
#@ if hasattr(data.values, key):
-#@ value = getattr(data.values, key)
-#@ return str(value)
+#@ return str(getattr(data.values, key))
#@ else:
#@ return default
#@ end
@@ -17,10 +16,10 @@ request:
raw: |+
POST /users/3 HTTP/1.1
Host: ginandjuice.shop
- Authorization: Bearer 3x4mpl3t0k3n
+ Authorization: Bearer (@= get_value("token") @)
Accept-Encoding: gzip
Content-Type: application/x-www-form-urlencoded
Connection: close
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
- foo=(@= get_value("foo") @)&bar=(@= get_value("bar") @)
\ No newline at end of file
+ foo=(@= get_value("foo") @)&bar=(@= get_value("bar") @)&debug=(@= get_value("debug", "false") @)
\ No newline at end of file
diff --git a/pkg/input/formats/testdata/ytt/ytt-profile.yaml b/pkg/input/formats/testdata/ytt/ytt-profile.yaml
new file mode 100644
index 000000000..2cad498bc
--- /dev/null
+++ b/pkg/input/formats/testdata/ytt/ytt-profile.yaml
@@ -0,0 +1,10 @@
+list: pkg/input/formats/testdata/ytt/ginandjuice.ytt.yaml
+input-mode: yaml
+templates:
+ - integration_tests/fuzz/fuzz-body.yaml
+var:
+ - debug=true
+vars-text-templating: true
+var-file-paths:
+ - pkg/input/formats/testdata/ytt/ytt-vars.yaml
+dast: true
\ No newline at end of file
diff --git a/pkg/input/formats/testdata/ytt/ytt-vars.yaml b/pkg/input/formats/testdata/ytt/ytt-vars.yaml
new file mode 100644
index 000000000..be973bee8
--- /dev/null
+++ b/pkg/input/formats/testdata/ytt/ytt-vars.yaml
@@ -0,0 +1,3 @@
+foo: tata
+bar: foo
+token: TOKEN-BEARER
\ No newline at end of file
diff --git a/pkg/input/formats/yaml/multidoc.go b/pkg/input/formats/yaml/multidoc.go
index 679707672..1140d5509 100644
--- a/pkg/input/formats/yaml/multidoc.go
+++ b/pkg/input/formats/yaml/multidoc.go
@@ -56,7 +56,7 @@ func (j *YamlMultiDocFormat) Parse(input io.Reader, resultsCb formats.ParseReqRe
}
tpl := []string{string(data)}
dvs := mapToKeyValueSlice(j.opts.Variables)
- finalInput, err = ytt(tpl, dvs)
+ finalInput, err = ytt(tpl, dvs, j.opts.VarsFilePaths)
if err != nil {
return errors.Wrap(err, "could not apply ytt templating")
}
diff --git a/pkg/input/formats/yaml/ytt.go b/pkg/input/formats/yaml/ytt.go
index c075119ca..3ccf5f6d2 100644
--- a/pkg/input/formats/yaml/ytt.go
+++ b/pkg/input/formats/yaml/ytt.go
@@ -12,7 +12,7 @@ import (
"gopkg.in/yaml.v2"
)
-func ytt(tpl, dvs []string) (io.Reader, error) {
+func ytt(tpl, dvs []string, varFiles []string) (io.Reader, error) {
// create and invoke ytt "template" command
templatingOptions := yttcmd.NewOptions()
@@ -21,6 +21,11 @@ func ytt(tpl, dvs []string) (io.Reader, error) {
return nil, err
}
+ if len(varFiles) > 0 {
+ // Load vaarFiles into the templating options.
+ templatingOptions.DataValuesFlags.FromFiles = varFiles
+ }
+
// equivalent to `--data-value-yaml`
templatingOptions.DataValuesFlags.KVsFromYAML = dvs
diff --git a/pkg/input/provider/interface.go b/pkg/input/provider/interface.go
index 769af60fb..c98214dd3 100644
--- a/pkg/input/provider/interface.go
+++ b/pkg/input/provider/interface.go
@@ -117,6 +117,7 @@ func NewInputProvider(opts InputOptions) (InputProvider, error) {
SkipFormatValidation: opts.Options.SkipFormatValidation,
RequiredOnly: opts.Options.FormatUseRequiredOnly,
VarsTextTemplating: opts.Options.VarsTextTemplating,
+ VarsFilePaths: opts.Options.VarsFilePaths,
},
})
}
diff --git a/pkg/types/types.go b/pkg/types/types.go
index 5b71225cb..47c434072 100644
--- a/pkg/types/types.go
+++ b/pkg/types/types.go
@@ -421,6 +421,8 @@ type Options struct {
SkipFormatValidation bool
// VarsTextTemplating is used to inject variables into yaml input files
VarsTextTemplating bool
+ // VarsFilePaths is used to inject variables into yaml input files from a file
+ VarsFilePaths goflags.StringSlice
// PayloadConcurrency is the number of concurrent payloads to run per template
PayloadConcurrency int
// ProbeConcurrency is the number of concurrent http probes to run with httpx
From 1a9a7563c0c7f957d1cc8424ddc309b33af98126 Mon Sep 17 00:00:00 2001
From: Alban Stourbe
Date: Tue, 24 Jun 2025 18:39:29 +0200
Subject: [PATCH 036/135] feat: send struct from var file
---
pkg/input/formats/testdata/ytt/ginandjuice.ytt.yaml | 2 +-
pkg/input/formats/testdata/ytt/ytt-profile.yaml | 1 +
pkg/input/formats/testdata/ytt/ytt-vars.yaml | 6 +++---
3 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/pkg/input/formats/testdata/ytt/ginandjuice.ytt.yaml b/pkg/input/formats/testdata/ytt/ginandjuice.ytt.yaml
index a43bca070..b409ad214 100644
--- a/pkg/input/formats/testdata/ytt/ginandjuice.ytt.yaml
+++ b/pkg/input/formats/testdata/ytt/ginandjuice.ytt.yaml
@@ -22,4 +22,4 @@ request:
Connection: close
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
- foo=(@= get_value("foo") @)&bar=(@= get_value("bar") @)&debug=(@= get_value("debug", "false") @)
\ No newline at end of file
+ foo=(@= json.encode(data.values.foo) @)&bar=(@= get_value("bar") @)&debug=(@= get_value("debug", "false") @)
\ No newline at end of file
diff --git a/pkg/input/formats/testdata/ytt/ytt-profile.yaml b/pkg/input/formats/testdata/ytt/ytt-profile.yaml
index 2cad498bc..01e794ad4 100644
--- a/pkg/input/formats/testdata/ytt/ytt-profile.yaml
+++ b/pkg/input/formats/testdata/ytt/ytt-profile.yaml
@@ -4,6 +4,7 @@ templates:
- integration_tests/fuzz/fuzz-body.yaml
var:
- debug=true
+ - bar=bar
vars-text-templating: true
var-file-paths:
- pkg/input/formats/testdata/ytt/ytt-vars.yaml
diff --git a/pkg/input/formats/testdata/ytt/ytt-vars.yaml b/pkg/input/formats/testdata/ytt/ytt-vars.yaml
index be973bee8..625ba7ddb 100644
--- a/pkg/input/formats/testdata/ytt/ytt-vars.yaml
+++ b/pkg/input/formats/testdata/ytt/ytt-vars.yaml
@@ -1,3 +1,3 @@
-foo: tata
-bar: foo
-token: TOKEN-BEARER
\ No newline at end of file
+token: foobar
+foo:
+ bar: baz
\ No newline at end of file
From 99914e1a32f01a06c1e9781d99dcd22e4dd43853 Mon Sep 17 00:00:00 2001
From: Alban Stourbe
Date: Tue, 24 Jun 2025 18:45:35 +0200
Subject: [PATCH 037/135] fix code rabbit
---
cmd/nuclei/main.go | 18 ++++++++++--------
1 file changed, 10 insertions(+), 8 deletions(-)
diff --git a/cmd/nuclei/main.go b/cmd/nuclei/main.go
index 13fb0d69d..a2663b505 100644
--- a/cmd/nuclei/main.go
+++ b/cmd/nuclei/main.go
@@ -582,7 +582,7 @@ Additional documentation is available at: https://docs.nuclei.sh/getting-started
}
if !options.Vars.IsEmpty() {
- // Maybe we should add vars to the config file as well?
+ // Maybe we should add vars to the config file as well even if they are set via flags?
file, err := os.Open(cfgFile)
if err != nil {
gologger.Fatal().Msgf("Could not open config file: %s\n", err)
@@ -596,15 +596,17 @@ Additional documentation is available at: https://docs.nuclei.sh/getting-started
variables := data["var"]
if variables != nil {
- for _, value := range variables.([]interface{}) {
- if strVal, ok := value.(string); ok {
- options.Vars.Set(strVal)
- } else {
- gologger.Warning().Msgf("Skipping non-string variable in config: %#v", value)
+ if varSlice, ok := variables.([]interface{}); ok {
+ for _, value := range varSlice {
+ if strVal, ok := value.(string); ok {
+ options.Vars.Set(strVal)
+ } else {
+ gologger.Warning().Msgf("Skipping non-string variable in config: %#v", value)
+ }
}
+ } else {
+ gologger.Warning().Msgf("No 'var' section found in config file: %s", cfgFile)
}
- } else {
- gologger.Warning().Msgf("No 'var' section found in config file: %s", cfgFile)
}
}
From 3bcbcc6e652c469c03cf67573c794c05c716cf04 Mon Sep 17 00:00:00 2001
From: Dwi Siswanto <25837540+dwisiswant0@users.noreply.github.com>
Date: Wed, 25 Jun 2025 00:03:44 +0700
Subject: [PATCH 038/135] test(nuclei): adds multiproto benchmark test (#6270)
* test(nuclei): adds multiproto benchmark test
Signed-off-by: Dwi Siswanto
* test(nuclei): deferred runner close & rm duped `os.MkdirTemp`
Signed-off-by: Dwi Siswanto
---------
Signed-off-by: Dwi Siswanto
---
.../{main_test.go => main_benchmark_test.go} | 74 ++++-
.../basic-template-multiproto-mixed.yaml | 239 ++++++++++++++
.../basic-template-multiproto-raw.yaml | 292 ++++++++++++++++++
.../multiproto/basic-template-multiproto.yaml | 170 ++++++++++
4 files changed, 762 insertions(+), 13 deletions(-)
rename cmd/nuclei/{main_test.go => main_benchmark_test.go} (63%)
create mode 100644 cmd/nuclei/testdata/benchmark/multiproto/basic-template-multiproto-mixed.yaml
create mode 100644 cmd/nuclei/testdata/benchmark/multiproto/basic-template-multiproto-raw.yaml
create mode 100644 cmd/nuclei/testdata/benchmark/multiproto/basic-template-multiproto.yaml
diff --git a/cmd/nuclei/main_test.go b/cmd/nuclei/main_benchmark_test.go
similarity index 63%
rename from cmd/nuclei/main_test.go
rename to cmd/nuclei/main_benchmark_test.go
index 01c75d5c8..baf9dbfab 100644
--- a/cmd/nuclei/main_test.go
+++ b/cmd/nuclei/main_benchmark_test.go
@@ -3,28 +3,56 @@ package main_test
import (
"net/http"
"net/http/httptest"
+ "os"
"testing"
"time"
- "github.com/projectdiscovery/goflags"
"github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/gologger/levels"
"github.com/projectdiscovery/nuclei/v3/internal/runner"
"github.com/projectdiscovery/nuclei/v3/pkg/types"
)
-func BenchmarkRunEnumeration(b *testing.B) {
+var (
+ projectPath string
+ targetURL string
+)
+
+func TestMain(m *testing.M) {
+ // Set up
+
+ gologger.DefaultLogger.SetMaxLevel(levels.LevelSilent)
+ os.Setenv("DISABLE_STDOUT", "true")
+
+ var err error
+
+ projectPath, err = os.MkdirTemp("", "nuclei-benchmark-")
+ if err != nil {
+ panic(err)
+ }
+
dummyServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusNoContent)
}))
- defer dummyServer.Close()
+ targetURL = dummyServer.URL
- options := &types.Options{
- RemoteTemplateDomainList: goflags.StringSlice{
- "cloud.projectdiscovery.io",
- },
- ProjectPath: "/tmp",
- Targets: goflags.StringSlice{dummyServer.URL},
+ // Execute tests
+
+ exitCode := m.Run()
+
+ // Tear down
+
+ dummyServer.Close()
+ _ = os.RemoveAll(projectPath)
+ os.Unsetenv("DISABLE_STDOUT")
+
+ os.Exit(exitCode)
+}
+
+func getDefaultOptions() *types.Options {
+ return &types.Options{
+ RemoteTemplateDomainList: []string{"cloud.projectdiscovery.io"},
+ ProjectPath: projectPath,
StatsInterval: 5,
MetricsPort: 9092,
MaxHostError: 30,
@@ -66,22 +94,42 @@ func BenchmarkRunEnumeration(b *testing.B) {
// DialerKeepAlive: time.Duration(0),
// DASTServerAddress: "localhost:9055",
}
+}
+func runEnumBenchmark(b *testing.B, options *types.Options) {
runner.ParseOptions(options)
- // Disable logging to reduce benchmark noise.
- gologger.DefaultLogger.SetMaxLevel(levels.LevelSilent)
-
nucleiRunner, err := runner.New(options)
if err != nil {
b.Fatalf("failed to create runner: %s", err)
}
+ defer nucleiRunner.Close()
b.ResetTimer()
+ b.ReportAllocs()
for i := 0; i < b.N; i++ {
if err := nucleiRunner.RunEnumeration(); err != nil {
- b.Fatalf("RunEnumeration failed: %s", err)
+ b.Fatalf("%s failed: %s", b.Name(), err)
}
}
}
+
+func BenchmarkRunEnumeration(b *testing.B) {
+ // Default case: run enumeration with default options == all nuclei-templates
+ // b.Run("Default", func(b *testing.B) {
+ // options := getDefaultOptions()
+ // options.Targets = []string{targetURL}
+
+ // runEnumBenchmark(b, options)
+ // })
+
+ // Case: https://github.com/projectdiscovery/nuclei/pull/6258
+ b.Run("Multiproto", func(b *testing.B) {
+ options := getDefaultOptions()
+ options.Targets = []string{targetURL}
+ options.Templates = []string{"./cmd/nuclei/testdata/benchmark/multiproto/"}
+
+ runEnumBenchmark(b, options)
+ })
+}
diff --git a/cmd/nuclei/testdata/benchmark/multiproto/basic-template-multiproto-mixed.yaml b/cmd/nuclei/testdata/benchmark/multiproto/basic-template-multiproto-mixed.yaml
new file mode 100644
index 000000000..d11db6e2d
--- /dev/null
+++ b/cmd/nuclei/testdata/benchmark/multiproto/basic-template-multiproto-mixed.yaml
@@ -0,0 +1,239 @@
+id: basic-template-multiproto-mixed
+
+info:
+ name: Test Template Multiple Protocols (Mixed)
+ author: pdteam
+ severity: info
+
+http:
+ - method: GET
+ id: first_iter_http
+ path:
+ - '{{BaseURL}}/1'
+
+ matchers:
+ - type: word
+ words:
+ - "Test is test matcher text"
+
+ - method: GET
+ path:
+ - '{{BaseURL}}/2'
+
+ matchers:
+ - type: word
+ words:
+ - "Test is test matcher text"
+
+ - method: GET
+ path:
+ - '{{BaseURL}}/3'
+
+ matchers:
+ - type: word
+ words:
+ - "Test is test matcher text"
+
+ - method: GET
+ path:
+ - '{{BaseURL}}/4'
+
+ matchers:
+ - type: word
+ words:
+ - "Test is test matcher text"
+
+ - method: GET
+ path:
+ - '{{BaseURL}}/5'
+
+ matchers:
+ - type: word
+ words:
+ - "Test is test matcher text"
+
+ - method: GET
+ path:
+ - '{{BaseURL}}/6'
+
+ matchers:
+ - type: word
+ words:
+ - "Test is test matcher text"
+
+ - method: GET
+ path:
+ - '{{BaseURL}}/7'
+
+ matchers:
+ - type: word
+ words:
+ - "Test is test matcher text"
+
+ - method: GET
+ path:
+ - '{{BaseURL}}/8'
+
+ matchers:
+ - type: word
+ words:
+ - "Test is test matcher text"
+
+ - method: GET
+ path:
+ - '{{BaseURL}}/9'
+
+ matchers:
+ - type: word
+ words:
+ - "Test is test matcher text"
+
+ - raw:
+ - |
+ GET /10 HTTP/1.1
+ Host: {{Hostname}}
+ Origin: {{BaseURL}}
+ Connection: close
+ User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko)
+ Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
+ Accept-Language: en-US,en;q=0.9
+
+ matchers:
+ - type: word
+ words:
+ - "Test is test matcher text"
+
+ - raw:
+ - |
+ GET /11 HTTP/1.1
+ Host: {{Hostname}}
+ Origin: {{BaseURL}}
+ Connection: close
+ User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko)
+ Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
+ Accept-Language: en-US,en;q=0.9
+
+ matchers:
+ - type: word
+ words:
+ - "Test is test matcher text"
+
+ - raw:
+ - |
+ GET /12 HTTP/1.1
+ Host: {{Hostname}}
+ Origin: {{BaseURL}}
+ Connection: close
+ User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko)
+ Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
+ Accept-Language: en-US,en;q=0.9
+
+ matchers:
+ - type: word
+ words:
+ - "Test is test matcher text"
+
+ - raw:
+ - |
+ GET /13 HTTP/1.1
+ Host: {{Hostname}}
+ Origin: {{BaseURL}}
+ Connection: close
+ User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko)
+ Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
+ Accept-Language: en-US,en;q=0.9
+
+ matchers:
+ - type: word
+ words:
+ - "Test is test matcher text"
+
+ - raw:
+ - |
+ GET /14 HTTP/1.1
+ Host: {{Hostname}}
+ Origin: {{BaseURL}}
+ Connection: close
+ User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko)
+ Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
+ Accept-Language: en-US,en;q=0.9
+
+ matchers:
+ - type: word
+ words:
+ - "Test is test matcher text"
+
+ - raw:
+ - |
+ GET / HTTP/1.1
+ Host: {{Hostname}}
+ Origin: {{BaseURL}}
+ Connection: close
+ User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko)
+ Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
+ Accept-Language: en-US,en;q=0.9
+
+ matchers:
+ - type: word
+ words:
+ - "Test is test matcher text"
+
+ - raw:
+ - |
+ GET /15 HTTP/1.1
+ Host: {{Hostname}}
+ Origin: {{BaseURL}}
+ Connection: close
+ User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko)
+ Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
+ Accept-Language: en-US,en;q=0.9
+
+ matchers:
+ - type: word
+ words:
+ - "Test is test matcher text"
+
+ - raw:
+ - |
+ GET /16 HTTP/1.1
+ Host: {{Hostname}}
+ Origin: {{BaseURL}}
+ Connection: close
+ User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko)
+ Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
+ Accept-Language: en-US,en;q=0.9
+
+ matchers:
+ - type: word
+ words:
+ - "Test is test matcher text"
+
+ - raw:
+ - |
+ GET /17 HTTP/1.1
+ Host: {{Hostname}}
+ Origin: {{BaseURL}}
+ Connection: close
+ User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko)
+ Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
+ Accept-Language: en-US,en;q=0.9
+
+ matchers:
+ - type: word
+ words:
+ - "Test is test matcher text"
+
+ - raw:
+ - |
+ GET /18 HTTP/1.1
+ Host: {{Hostname}}
+ Origin: {{BaseURL}}
+ Connection: close
+ User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko)
+ Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
+ Accept-Language: en-US,en;q=0.9
+
+ matchers:
+ - type: word
+ words:
+ - "Test is test matcher text"
\ No newline at end of file
diff --git a/cmd/nuclei/testdata/benchmark/multiproto/basic-template-multiproto-raw.yaml b/cmd/nuclei/testdata/benchmark/multiproto/basic-template-multiproto-raw.yaml
new file mode 100644
index 000000000..f868fdc57
--- /dev/null
+++ b/cmd/nuclei/testdata/benchmark/multiproto/basic-template-multiproto-raw.yaml
@@ -0,0 +1,292 @@
+id: basic-template-multiproto-raw
+
+info:
+ name: Test Template Multiple Protocols RAW
+ author: pdteam
+ severity: info
+
+http:
+ - raw:
+ - |
+ GET /1 HTTP/1.1
+ Host: {{Hostname}}
+ Origin: {{BaseURL}}
+ Connection: close
+ User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko)
+ Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
+ Accept-Language: en-US,en;q=0.9
+
+ matchers:
+ - type: word
+ words:
+ - "Test is test matcher text"
+
+ - raw:
+ - |
+ GET /2 HTTP/1.1
+ Host: {{Hostname}}
+ Origin: {{BaseURL}}
+ Connection: close
+ User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko)
+ Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
+ Accept-Language: en-US,en;q=0.9
+
+ matchers:
+ - type: word
+ words:
+ - "Test is test matcher text"
+
+ - raw:
+ - |
+ GET /3 HTTP/1.1
+ Host: {{Hostname}}
+ Origin: {{BaseURL}}
+ Connection: close
+ User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko)
+ Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
+ Accept-Language: en-US,en;q=0.9
+
+ matchers:
+ - type: word
+ words:
+ - "Test is test matcher text"
+
+ - raw:
+ - |
+ GET /4 HTTP/1.1
+ Host: {{Hostname}}
+ Origin: {{BaseURL}}
+ Connection: close
+ User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko)
+ Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
+ Accept-Language: en-US,en;q=0.9
+
+ matchers:
+ - type: word
+ words:
+ - "Test is test matcher text"
+
+ - raw:
+ - |
+ GET /5 HTTP/1.1
+ Host: {{Hostname}}
+ Origin: {{BaseURL}}
+ Connection: close
+ User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko)
+ Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
+ Accept-Language: en-US,en;q=0.9
+
+ matchers:
+ - type: word
+ words:
+ - "Test is test matcher text"
+
+ - raw:
+ - |
+ GET /6 HTTP/1.1
+ Host: {{Hostname}}
+ Origin: {{BaseURL}}
+ Connection: close
+ User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko)
+ Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
+ Accept-Language: en-US,en;q=0.9
+
+ matchers:
+ - type: word
+ words:
+ - "Test is test matcher text"
+
+ - raw:
+ - |
+ GET /7 HTTP/1.1
+ Host: {{Hostname}}
+ Origin: {{BaseURL}}
+ Connection: close
+ User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko)
+ Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
+ Accept-Language: en-US,en;q=0.9
+
+ matchers:
+ - type: word
+ words:
+ - "Test is test matcher text"
+
+ - raw:
+ - |
+ GET /8 HTTP/1.1
+ Host: {{Hostname}}
+ Origin: {{BaseURL}}
+ Connection: close
+ User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko)
+ Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
+ Accept-Language: en-US,en;q=0.9
+
+ matchers:
+ - type: word
+ words:
+ - "Test is test matcher text"
+
+ - raw:
+ - |
+ GET /9 HTTP/1.1
+ Host: {{Hostname}}
+ Origin: {{BaseURL}}
+ Connection: close
+ User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko)
+ Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
+ Accept-Language: en-US,en;q=0.9
+
+ matchers:
+ - type: word
+ words:
+ - "Test is test matcher text"
+
+ - raw:
+ - |
+ GET /10 HTTP/1.1
+ Host: {{Hostname}}
+ Origin: {{BaseURL}}
+ Connection: close
+ User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko)
+ Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
+ Accept-Language: en-US,en;q=0.9
+
+ matchers:
+ - type: word
+ words:
+ - "Test is test matcher text"
+
+ - raw:
+ - |
+ GET /11 HTTP/1.1
+ Host: {{Hostname}}
+ Origin: {{BaseURL}}
+ Connection: close
+ User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko)
+ Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
+ Accept-Language: en-US,en;q=0.9
+
+ matchers:
+ - type: word
+ words:
+ - "Test is test matcher text"
+
+ - raw:
+ - |
+ GET /12 HTTP/1.1
+ Host: {{Hostname}}
+ Origin: {{BaseURL}}
+ Connection: close
+ User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko)
+ Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
+ Accept-Language: en-US,en;q=0.9
+
+ matchers:
+ - type: word
+ words:
+ - "Test is test matcher text"
+
+ - raw:
+ - |
+ GET /13 HTTP/1.1
+ Host: {{Hostname}}
+ Origin: {{BaseURL}}
+ Connection: close
+ User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko)
+ Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
+ Accept-Language: en-US,en;q=0.9
+
+ matchers:
+ - type: word
+ words:
+ - "Test is test matcher text"
+
+ - raw:
+ - |
+ GET /14 HTTP/1.1
+ Host: {{Hostname}}
+ Origin: {{BaseURL}}
+ Connection: close
+ User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko)
+ Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
+ Accept-Language: en-US,en;q=0.9
+
+ matchers:
+ - type: word
+ words:
+ - "Test is test matcher text"
+
+ - raw:
+ - |
+ GET / HTTP/1.1
+ Host: {{Hostname}}
+ Origin: {{BaseURL}}
+ Connection: close
+ User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko)
+ Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
+ Accept-Language: en-US,en;q=0.9
+
+ matchers:
+ - type: word
+ words:
+ - "Test is test matcher text"
+
+ - raw:
+ - |
+ GET /15 HTTP/1.1
+ Host: {{Hostname}}
+ Origin: {{BaseURL}}
+ Connection: close
+ User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko)
+ Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
+ Accept-Language: en-US,en;q=0.9
+
+ matchers:
+ - type: word
+ words:
+ - "Test is test matcher text"
+
+ - raw:
+ - |
+ GET /16 HTTP/1.1
+ Host: {{Hostname}}
+ Origin: {{BaseURL}}
+ Connection: close
+ User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko)
+ Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
+ Accept-Language: en-US,en;q=0.9
+
+ matchers:
+ - type: word
+ words:
+ - "Test is test matcher text"
+
+ - raw:
+ - |
+ GET /17 HTTP/1.1
+ Host: {{Hostname}}
+ Origin: {{BaseURL}}
+ Connection: close
+ User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko)
+ Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
+ Accept-Language: en-US,en;q=0.9
+
+ matchers:
+ - type: word
+ words:
+ - "Test is test matcher text"
+
+ - raw:
+ - |
+ GET /18 HTTP/1.1
+ Host: {{Hostname}}
+ Origin: {{BaseURL}}
+ Connection: close
+ User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko)
+ Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
+ Accept-Language: en-US,en;q=0.9
+
+ matchers:
+ - type: word
+ words:
+ - "Test is test matcher text"
\ No newline at end of file
diff --git a/cmd/nuclei/testdata/benchmark/multiproto/basic-template-multiproto.yaml b/cmd/nuclei/testdata/benchmark/multiproto/basic-template-multiproto.yaml
new file mode 100644
index 000000000..6a7d37c86
--- /dev/null
+++ b/cmd/nuclei/testdata/benchmark/multiproto/basic-template-multiproto.yaml
@@ -0,0 +1,170 @@
+id: basic-template-multiproto
+
+info:
+ name: Test Template Multiple Protocols
+ author: pdteam
+ severity: info
+
+http:
+ - method: GET
+ id: first_iter_http
+ path:
+ - '{{BaseURL}}/1'
+
+ matchers:
+ - type: word
+ words:
+ - "Test is test matcher text"
+
+ - method: GET
+ path:
+ - '{{BaseURL}}/2'
+
+ matchers:
+ - type: word
+ words:
+ - "Test is test matcher text"
+
+ - method: GET
+ path:
+ - '{{BaseURL}}/3'
+
+ matchers:
+ - type: word
+ words:
+ - "Test is test matcher text"
+
+ - method: GET
+ path:
+ - '{{BaseURL}}/4'
+
+ matchers:
+ - type: word
+ words:
+ - "Test is test matcher text"
+
+ - method: GET
+ path:
+ - '{{BaseURL}}/5'
+
+ matchers:
+ - type: word
+ words:
+ - "Test is test matcher text"
+
+ - method: GET
+ path:
+ - '{{BaseURL}}/6'
+
+ matchers:
+ - type: word
+ words:
+ - "Test is test matcher text"
+
+ - method: GET
+ path:
+ - '{{BaseURL}}/7'
+
+ matchers:
+ - type: word
+ words:
+ - "Test is test matcher text"
+
+ - method: GET
+ path:
+ - '{{BaseURL}}/8'
+
+ matchers:
+ - type: word
+ words:
+ - "Test is test matcher text"
+
+ - method: GET
+ path:
+ - '{{BaseURL}}/9'
+
+ matchers:
+ - type: word
+ words:
+ - "Test is test matcher text"
+
+ - method: GET
+ path:
+ - '{{BaseURL}}/10'
+
+ matchers:
+ - type: word
+ words:
+ - "Test is test matcher text"
+
+ - method: GET
+ path:
+ - '{{BaseURL}}/11'
+
+ matchers:
+ - type: word
+ words:
+ - "Test is test matcher text"
+
+ - method: GET
+ path:
+ - '{{BaseURL}}/12'
+
+ matchers:
+ - type: word
+ words:
+ - "Test is test matcher text"
+
+ - method: GET
+ path:
+ - '{{BaseURL}}/13'
+
+ matchers:
+ - type: word
+ words:
+ - "Test is test matcher text"
+
+ - method: GET
+ path:
+ - '{{BaseURL}}/14'
+
+ matchers:
+ - type: word
+ words:
+ - "Test is test matcher text"
+
+ - method: GET
+ path:
+ - '{{BaseURL}}/15'
+
+ matchers:
+ - type: word
+ words:
+ - "Test is test matcher text"
+
+ - method: GET
+ path:
+ - '{{BaseURL}}/16'
+
+ matchers:
+ - type: word
+ words:
+ - "Test is test matcher text"
+
+ - method: GET
+ path:
+ - '{{BaseURL}}/17'
+
+ matchers:
+ - type: word
+ words:
+ - "Test is test matcher text"
+
+ - method: GET
+ path:
+ - '{{BaseURL}}/18'
+
+ matchers:
+ - type: word
+ words:
+ - "Test is test matcher text"
\ No newline at end of file
From 2c3df33a9837c90f058f5019cdb09428f6590535 Mon Sep 17 00:00:00 2001
From: Emmanuel Ferdman
Date: Wed, 25 Jun 2025 00:23:15 +0300
Subject: [PATCH 039/135] chore: update GoReleaser configurations (#6280)
Signed-off-by: Emmanuel Ferdman
---
.goreleaser.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.goreleaser.yml b/.goreleaser.yml
index d33aabc1f..2d2f61379 100644
--- a/.goreleaser.yml
+++ b/.goreleaser.yml
@@ -38,9 +38,9 @@ builds:
# goarch: [amd64]
archives:
- - format: zip
+ - formats: [zip]
id: nuclei
- builds: [nuclei-cli]
+ ids: [nuclei-cli]
name_template: '{{ .ProjectName }}_{{ .Version }}_{{ if eq .Os "darwin" }}macOS{{ else }}{{ .Os }}{{ end }}_{{ .Arch }}'
checksum:
From 937fa1252b6bb2bec051f4b9980e692188974ee7 Mon Sep 17 00:00:00 2001
From: Alban Stourbe
Date: Thu, 26 Jun 2025 09:42:14 +0200
Subject: [PATCH 040/135] fix(main.go): add errcheck
---
cmd/nuclei/main.go | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/cmd/nuclei/main.go b/cmd/nuclei/main.go
index a2663b505..2991fb81e 100644
--- a/cmd/nuclei/main.go
+++ b/cmd/nuclei/main.go
@@ -599,7 +599,10 @@ Additional documentation is available at: https://docs.nuclei.sh/getting-started
if varSlice, ok := variables.([]interface{}); ok {
for _, value := range varSlice {
if strVal, ok := value.(string); ok {
- options.Vars.Set(strVal)
+ err = options.Vars.Set(strVal)
+ if err != nil {
+ gologger.Warning().Msgf("Could not set variable from config file: %s\n", err)
+ }
} else {
gologger.Warning().Msgf("Skipping non-string variable in config: %#v", value)
}
From 7b1a02710eb21c7fceb0a654abd641a64e72d5bd Mon Sep 17 00:00:00 2001
From: Cho hyun-sik <78861124+1223v@users.noreply.github.com>
Date: Sat, 28 Jun 2025 05:38:44 +0900
Subject: [PATCH 041/135] docs: refine Bug Bounty hunter section in Korean docs
(#6287)
---
README_KR.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README_KR.md b/README_KR.md
index c59825cdb..6181c866b 100644
--- a/README_KR.md
+++ b/README_KR.md
@@ -341,7 +341,7 @@ Nuclei를 사용하면 자체 검사 모음으로 테스트 접근 방식을 사
- 몇 분 안에 수천 개의 호스트를 처리할 수 있음.
- 간단한 YAML DSL로 사용자 지정 테스트 접근 방식을 쉽게 자동화할 수 있음.
-버그 바운티 워크플로에 맞는 다른 오픈 소스 프로젝트를 확인할 수 있습니다.: [github.com/projectdiscovery](http://github.com/projectdiscovery), 또한, 우리는 매일 [Chaos에서 DNS 데이터를 갱신해 호스팅합니다.](http://chaos.projectdiscovery.io).
+버그 바운티 워크플로에 맞는 다른 오픈 소스 프로젝트를 확인할 수 있습니다.: [github.com/projectdiscovery](http://github.com/projectdiscovery), 또한, 우리는 매일 [Chaos에서 DNS 데이터를 갱신해 호스팅합니다](http://chaos.projectdiscovery.io).
From 2b729e40373cc81c13ee104844b3839bbe96c559 Mon Sep 17 00:00:00 2001
From: Tarun Koyalwar <45962551+tarunKoyalwar@users.noreply.github.com>
Date: Mon, 30 Jun 2025 15:13:00 +0530
Subject: [PATCH 042/135] fix context leak in flow (#6282)
* fix context leak in flow
* handle sizedwaitpool when not reused
---
pkg/js/compiler/compiler.go | 24 +++++++++++++++++++++---
pkg/js/compiler/compiler_test.go | 2 +-
pkg/protocols/code/code.go | 2 +-
pkg/protocols/javascript/js.go | 6 +++---
pkg/tmplexec/exec.go | 2 +-
pkg/tmplexec/flow/flow_executor.go | 7 ++++++-
pkg/tmplexec/flow/vm.go | 10 +++++++---
7 files changed, 40 insertions(+), 13 deletions(-)
diff --git a/pkg/js/compiler/compiler.go b/pkg/js/compiler/compiler.go
index b13e7f9ec..cd698e4a0 100644
--- a/pkg/js/compiler/compiler.go
+++ b/pkg/js/compiler/compiler.go
@@ -156,9 +156,27 @@ func (c *Compiler) ExecuteWithOptions(program *goja.Program, args *ExecuteArgs,
return res, nil
}
-// Wraps a script in a function and compiles it.
-func WrapScriptNCompile(script string, strict bool) (*goja.Program, error) {
- if !stringsutil.ContainsAny(script, exportAsToken, exportToken) {
+// if the script uses export/ExportAS tokens then we can run it in IIFE mode
+// but if not we can't run it
+func CanRunAsIIFE(script string) bool {
+ return stringsutil.ContainsAny(script, exportAsToken, exportToken)
+}
+
+// SourceIIFEMode is a mode where the script is wrapped in a function and compiled.
+// This is used when the script is not exported or exported as a function.
+func SourceIIFEMode(script string, strict bool) (*goja.Program, error) {
+ val := fmt.Sprintf(`
+ (function() {
+ %s
+ })()
+ `, script)
+ return goja.Compile("", val, strict)
+}
+
+// SourceAutoMode is a mode where the script is wrapped in a function and compiled.
+// This is used when the script is exported or exported as a function.
+func SourceAutoMode(script string, strict bool) (*goja.Program, error) {
+ if !CanRunAsIIFE(script) {
// this will not be run in a pooled runtime
return goja.Compile("", script, strict)
}
diff --git a/pkg/js/compiler/compiler_test.go b/pkg/js/compiler/compiler_test.go
index 3a43a4016..01acb0d06 100644
--- a/pkg/js/compiler/compiler_test.go
+++ b/pkg/js/compiler/compiler_test.go
@@ -21,7 +21,7 @@ func TestNewCompilerConsoleDebug(t *testing.T) {
})
compiler := New()
- p, err := WrapScriptNCompile("console.log('hello world');", false)
+ p, err := SourceAutoMode("console.log('hello world');", false)
if err != nil {
t.Fatal(err)
}
diff --git a/pkg/protocols/code/code.go b/pkg/protocols/code/code.go
index b3344d08d..1d687d235 100644
--- a/pkg/protocols/code/code.go
+++ b/pkg/protocols/code/code.go
@@ -130,7 +130,7 @@ func (request *Request) Compile(options *protocols.ExecutorOptions) error {
// compile pre-condition if any
if request.PreCondition != "" {
- preConditionCompiled, err := compiler.WrapScriptNCompile(request.PreCondition, false)
+ preConditionCompiled, err := compiler.SourceAutoMode(request.PreCondition, false)
if err != nil {
return errorutil.NewWithTag(request.TemplateID, "could not compile pre-condition: %s", err)
}
diff --git a/pkg/protocols/javascript/js.go b/pkg/protocols/javascript/js.go
index 344199fb3..e8b9c0b38 100644
--- a/pkg/protocols/javascript/js.go
+++ b/pkg/protocols/javascript/js.go
@@ -215,7 +215,7 @@ func (request *Request) Compile(options *protocols.ExecutorOptions) error {
// proceed with whatever args we have
args.Args, _ = request.evaluateArgs(allVars, options, true)
- initCompiled, err := compiler.WrapScriptNCompile(request.Init, false)
+ initCompiled, err := compiler.SourceAutoMode(request.Init, false)
if err != nil {
return errorutil.NewWithTag(request.TemplateID, "could not compile init code: %s", err)
}
@@ -236,7 +236,7 @@ func (request *Request) Compile(options *protocols.ExecutorOptions) error {
// compile pre-condition if any
if request.PreCondition != "" {
- preConditionCompiled, err := compiler.WrapScriptNCompile(request.PreCondition, false)
+ preConditionCompiled, err := compiler.SourceAutoMode(request.PreCondition, false)
if err != nil {
return errorutil.NewWithTag(request.TemplateID, "could not compile pre-condition: %s", err)
}
@@ -245,7 +245,7 @@ func (request *Request) Compile(options *protocols.ExecutorOptions) error {
// compile actual source code
if request.Code != "" {
- scriptCompiled, err := compiler.WrapScriptNCompile(request.Code, false)
+ scriptCompiled, err := compiler.SourceAutoMode(request.Code, false)
if err != nil {
return errorutil.NewWithTag(request.TemplateID, "could not compile javascript code: %s", err)
}
diff --git a/pkg/tmplexec/exec.go b/pkg/tmplexec/exec.go
index d0ed09331..c59b6c123 100644
--- a/pkg/tmplexec/exec.go
+++ b/pkg/tmplexec/exec.go
@@ -43,7 +43,7 @@ func NewTemplateExecuter(requests []protocols.Request, options *protocols.Execut
// we use a dummy input here because goal of flow executor at this point is to just check
// syntax and other things are correct before proceeding to actual execution
// during execution new instance of flow will be created as it is tightly coupled with lot of executor options
- p, err := compiler.WrapScriptNCompile(options.Flow, false)
+ p, err := compiler.SourceAutoMode(options.Flow, false)
if err != nil {
return nil, fmt.Errorf("could not compile flow: %s", err)
}
diff --git a/pkg/tmplexec/flow/flow_executor.go b/pkg/tmplexec/flow/flow_executor.go
index 62112e0f8..a8c554679 100644
--- a/pkg/tmplexec/flow/flow_executor.go
+++ b/pkg/tmplexec/flow/flow_executor.go
@@ -8,6 +8,7 @@ import (
"sync/atomic"
"github.com/dop251/goja"
+ "github.com/projectdiscovery/nuclei/v3/pkg/js/compiler"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/generators"
"github.com/projectdiscovery/nuclei/v3/pkg/scan"
@@ -195,7 +196,11 @@ func (f *FlowExecutor) ExecuteWithResults(ctx *scan.ScanContext) error {
// get a new runtime from pool
runtime := GetJSRuntime(f.options.Options)
- defer PutJSRuntime(runtime) // put runtime back to pool
+ defer func() {
+ // whether to reuse or not depends on the whether script modifies
+ // global scope or not,
+ PutJSRuntime(runtime, compiler.CanRunAsIIFE(f.options.Flow))
+ }()
defer func() {
// remove set builtin
_ = runtime.GlobalObject().Delete("set")
diff --git a/pkg/tmplexec/flow/vm.go b/pkg/tmplexec/flow/vm.go
index f1f7dbb84..88033c250 100644
--- a/pkg/tmplexec/flow/vm.go
+++ b/pkg/tmplexec/flow/vm.go
@@ -35,7 +35,7 @@ func GetJSRuntime(opts *types.Options) *goja.Runtime {
if opts.JsConcurrency < 100 {
opts.JsConcurrency = 100
}
- sizedgojapool, _ = sizedpool.New[*goja.Runtime](
+ sizedgojapool, _ = sizedpool.New(
sizedpool.WithPool[*goja.Runtime](gojapool),
sizedpool.WithSize[*goja.Runtime](int64(opts.JsConcurrency)),
)
@@ -45,8 +45,12 @@ func GetJSRuntime(opts *types.Options) *goja.Runtime {
}
// PutJSRuntime returns a JS runtime to pool
-func PutJSRuntime(runtime *goja.Runtime) {
- sizedgojapool.Put(runtime)
+func PutJSRuntime(runtime *goja.Runtime, reuse bool) {
+ if reuse {
+ sizedgojapool.Put(runtime)
+ } else {
+ sizedgojapool.Put(gojapool.Get().(*goja.Runtime))
+ }
}
func registerBuiltins(runtime *goja.Runtime) {
From 87ed0b2bb93e8106ac06397db50f210156cf9816 Mon Sep 17 00:00:00 2001
From: Dwi Siswanto <25837540+dwisiswant0@users.noreply.github.com>
Date: Tue, 1 Jul 2025 00:40:44 +0700
Subject: [PATCH 043/135] build: bump all direct modules (#6290)
* chore: fix non-constant fmt string in call
Signed-off-by: Dwi Siswanto
* build: bump all direct modules
Signed-off-by: Dwi Siswanto
* chore(hosterrorscache): update import path
Signed-off-by: Dwi Siswanto
* fix(charts): break changes
Signed-off-by: Dwi Siswanto
* build: pinned `github.com/zmap/zcrypto` to v0.0.0-20240512203510-0fef58d9a9db
Signed-off-by: Dwi Siswanto
* chore: golangci-lint auto fixes
Signed-off-by: Dwi Siswanto
* chore: satisfy lints
Signed-off-by: Dwi Siswanto
* build: migrate `github.com/xanzy/go-gitlab` => `gitlab.com/gitlab-org/api/client-go`
Signed-off-by: Dwi Siswanto
* feat(json): update build constraints
Signed-off-by: Dwi Siswanto
* chore: dont panicking on close err
Signed-off-by: Dwi Siswanto
---------
Signed-off-by: Dwi Siswanto
---
cmd/docgen/docgen.go | 4 +-
cmd/functional-test/main.go | 4 +-
cmd/generate-checksum/main.go | 4 +-
cmd/integration-test/custom-dir.go | 4 +-
cmd/integration-test/dsl.go | 4 +-
cmd/integration-test/flow.go | 2 +-
cmd/integration-test/fuzz.go | 10 +-
cmd/integration-test/generic.go | 9 +-
cmd/integration-test/headless.go | 8 +-
cmd/integration-test/http.go | 94 +-
cmd/integration-test/integration-test.go | 4 +-
cmd/integration-test/library.go | 4 +-
cmd/integration-test/loader.go | 32 +-
cmd/integration-test/network.go | 28 +-
cmd/integration-test/ssl.go | 24 +-
cmd/integration-test/template-dir.go | 4 +-
cmd/integration-test/workflow.go | 24 +-
cmd/nuclei/main.go | 6 +-
cmd/nuclei/main_benchmark_test.go | 4 +-
cmd/tmc/main.go | 10 +-
cmd/tools/fuzzplayground/main.go | 4 +-
examples/with_speed_control/main.go | 3 +-
go.mod | 410 +++----
go.sum | 1054 +++++------------
internal/pdcp/writer.go | 14 +-
internal/runner/healthcheck.go | 6 +-
internal/runner/options.go | 10 +-
internal/runner/proxy.go | 11 +-
internal/runner/runner.go | 10 +-
internal/runner/runner_test.go | 24 +-
internal/server/server.go | 2 +-
pkg/authprovider/authx/dynamic.go | 8 +-
pkg/authprovider/authx/dynamic_test.go | 14 +-
pkg/catalog/config/ignorefile.go | 4 +-
pkg/catalog/config/template.go | 4 +-
pkg/catalog/loader/ai_loader.go | 4 +-
pkg/catalog/loader/loader.go | 4 +-
pkg/catalog/loader/remote_loader.go | 9 +-
pkg/external/customtemplates/gitlab.go | 2 +-
pkg/external/customtemplates/s3.go | 4 +-
pkg/fuzz/analyzers/time/analyzer.go | 2 +-
pkg/fuzz/analyzers/time/time_delay.go | 5 +-
pkg/fuzz/component/path.go | 8 +-
pkg/fuzz/component/path_test.go | 6 +-
pkg/fuzz/component/query.go | 2 +-
pkg/fuzz/component/query_test.go | 4 +-
pkg/fuzz/dataformat/multipart.go | 6 +-
pkg/fuzz/execute.go | 2 +-
pkg/fuzz/parts.go | 2 +-
pkg/fuzz/stats/stats.go | 5 +-
pkg/input/formats/burp/burp_test.go | 4 +-
pkg/input/formats/formats.go | 4 +-
pkg/input/formats/json/json_test.go | 4 +-
pkg/input/formats/openapi/generator.go | 8 +-
pkg/input/formats/openapi/openapi_test.go | 4 +-
pkg/input/formats/swagger/swagger_test.go | 4 +-
pkg/input/formats/yaml/multidoc_test.go | 4 +-
pkg/input/provider/http/multiformat.go | 2 +-
pkg/input/provider/list/hmap.go | 4 +-
pkg/input/transform_test.go | 4 +-
pkg/installer/template_test.go | 6 +-
pkg/installer/versioncheck.go | 4 +-
pkg/installer/zipslip_unix_test.go | 4 +-
pkg/js/devtools/bindgen/output.go | 20 +-
pkg/js/libs/kerberos/sendtokdc.go | 16 +-
pkg/js/libs/ldap/ldap.go | 11 +-
pkg/js/libs/mssql/mssql.go | 12 +-
pkg/js/libs/mysql/mysql.go | 12 +-
pkg/js/libs/mysql/mysql_private.go | 4 +-
pkg/js/libs/oracle/oracle.go | 4 +-
pkg/js/libs/pop3/pop3.go | 4 +-
pkg/js/libs/postgres/postgres.go | 16 +-
pkg/js/libs/rdp/rdp.go | 8 +-
pkg/js/libs/redis/redis.go | 20 +-
pkg/js/libs/rsync/rsync.go | 4 +-
pkg/js/libs/smb/smb.go | 8 +-
pkg/js/libs/smb/smb_private.go | 4 +-
pkg/js/libs/smb/smbghost.go | 4 +-
pkg/js/libs/smtp/smtp.go | 8 +-
pkg/js/libs/ssh/ssh.go | 8 +-
pkg/js/libs/telnet/telnet.go | 4 +-
pkg/js/libs/vnc/vnc.go | 4 +-
pkg/js/utils/util.go | 4 +-
pkg/operators/operators.go | 2 +-
pkg/output/output.go | 16 +-
pkg/progress/progress.go | 6 +-
pkg/projectfile/project.go | 2 +-
pkg/protocols/code/code.go | 8 +-
.../common/automaticscan/automaticscan.go | 6 +-
.../common/expressions/expressions.go | 6 +-
pkg/protocols/common/generators/load.go | 4 +-
.../common/hosterrorscache/hosterrorscache.go | 4 +-
pkg/protocols/common/interactsh/interactsh.go | 8 +-
pkg/protocols/common/randomip/randomip.go | 2 +-
pkg/protocols/dns/cluster.go | 3 +-
pkg/protocols/dns/dnsclientpool/clientpool.go | 2 +-
pkg/protocols/dns/operators.go | 2 +-
pkg/protocols/file/file.go | 2 +-
pkg/protocols/file/find.go | 4 +-
pkg/protocols/file/find_test.go | 4 +-
pkg/protocols/file/request.go | 24 +-
pkg/protocols/file/request_test.go | 4 +-
pkg/protocols/headless/engine/engine.go | 4 +-
pkg/protocols/headless/engine/page.go | 4 +-
pkg/protocols/headless/engine/page_actions.go | 2 +-
.../headless/engine/page_actions_test.go | 8 +-
pkg/protocols/headless/request.go | 10 +-
pkg/protocols/http/build_request.go | 6 +-
pkg/protocols/http/build_request_test.go | 8 +-
pkg/protocols/http/cluster.go | 2 +-
pkg/protocols/http/race/syncedreadcloser.go | 2 +-
pkg/protocols/http/request.go | 6 +-
pkg/protocols/http/request_annotations.go | 6 +-
.../http/request_annotations_test.go | 4 +-
pkg/protocols/http/request_fuzz.go | 8 +-
pkg/protocols/http/request_test.go | 2 +-
pkg/protocols/http/signerpool/signerpool.go | 2 +-
pkg/protocols/http/utils.go | 2 +-
pkg/protocols/network/request.go | 9 +-
pkg/protocols/offlinehttp/find_test.go | 4 +-
.../offlinehttp/read_response_test.go | 6 +-
pkg/protocols/offlinehttp/request.go | 4 +-
pkg/protocols/ssl/ssl.go | 2 +-
pkg/protocols/utils/variables.go | 5 +-
pkg/protocols/websocket/websocket.go | 4 +-
pkg/reporting/dedupe/dedupe.go | 4 +-
pkg/reporting/dedupe/dedupe_test.go | 4 +-
pkg/reporting/exporters/es/elasticsearch.go | 4 +-
pkg/reporting/exporters/markdown/markdown.go | 4 +-
pkg/reporting/format/format_utils.go | 12 +-
pkg/reporting/reporting.go | 6 +-
pkg/reporting/trackers/gitlab/gitlab.go | 2 +-
pkg/reporting/trackers/linear/linear.go | 4 +-
pkg/scan/charts/charts.go | 4 +-
pkg/scan/charts/echarts.go | 70 +-
pkg/templates/cluster.go | 7 +-
pkg/templates/compile.go | 6 +-
pkg/templates/parser.go | 4 +-
pkg/templates/templates.go | 6 +-
pkg/testutils/fuzzplayground/db.go | 4 +-
pkg/testutils/fuzzplayground/server.go | 12 +-
pkg/testutils/integration.go | 6 +-
pkg/tmplexec/flow/flow_executor.go | 4 +-
pkg/tmplexec/flow/flow_internal.go | 2 +-
pkg/utils/json/doc.go | 2 +-
pkg/utils/json/json.go | 3 +-
pkg/utils/json/json_fallback.go | 4 +-
147 files changed, 1203 insertions(+), 1347 deletions(-)
diff --git a/cmd/docgen/docgen.go b/cmd/docgen/docgen.go
index 51c2a195d..ca075a19c 100644
--- a/cmd/docgen/docgen.go
+++ b/cmd/docgen/docgen.go
@@ -19,7 +19,9 @@ func writeToFile(filename string, data []byte) {
if err != nil {
log.Fatalf("Could not create file %s: %s\n", filename, err)
}
- defer file.Close()
+ defer func() {
+ _ = file.Close()
+ }()
_, err = file.Write(data)
if err != nil {
diff --git a/cmd/functional-test/main.go b/cmd/functional-test/main.go
index 78114fdb3..9e605522f 100644
--- a/cmd/functional-test/main.go
+++ b/cmd/functional-test/main.go
@@ -41,7 +41,9 @@ func runFunctionalTests(debug bool) (error, bool) {
if err != nil {
return errors.Wrap(err, "could not open test cases"), true
}
- defer file.Close()
+ defer func() {
+ _ = file.Close()
+ }()
errored, failedTestCases := runTestCases(file, debug)
diff --git a/cmd/generate-checksum/main.go b/cmd/generate-checksum/main.go
index a381387fa..9a3e7b8ed 100644
--- a/cmd/generate-checksum/main.go
+++ b/cmd/generate-checksum/main.go
@@ -23,7 +23,9 @@ func main() {
if err != nil {
log.Fatalf("Could not create file: %s\n", err)
}
- defer file.Close()
+ defer func() {
+ _ = file.Close()
+ }()
err = filepath.WalkDir(templatesDirectory, func(path string, d fs.DirEntry, err error) error {
if err != nil || d.IsDir() {
diff --git a/cmd/integration-test/custom-dir.go b/cmd/integration-test/custom-dir.go
index 550027f06..b1ea83cc6 100644
--- a/cmd/integration-test/custom-dir.go
+++ b/cmd/integration-test/custom-dir.go
@@ -18,7 +18,9 @@ func (h *customConfigDirTest) Execute(filePath string) error {
if err != nil {
return err
}
- defer os.RemoveAll(customTempDirectory)
+ defer func() {
+ _ = os.RemoveAll(customTempDirectory)
+ }()
results, err := testutils.RunNucleiBareArgsAndGetResults(debug, []string{"NUCLEI_CONFIG_DIR=" + customTempDirectory}, "-t", filePath, "-u", "8x8exch02.8x8.com")
if err != nil {
return err
diff --git a/cmd/integration-test/dsl.go b/cmd/integration-test/dsl.go
index 4e4a275ef..c311b8292 100644
--- a/cmd/integration-test/dsl.go
+++ b/cmd/integration-test/dsl.go
@@ -21,7 +21,7 @@ type dslVersionWarning struct{}
func (d *dslVersionWarning) Execute(templatePath string) error {
router := httprouter.New()
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
- fmt.Fprintf(w, "DSL version parsing warning test")
+ _, _ = fmt.Fprintf(w, "DSL version parsing warning test")
})
ts := httptest.NewServer(router)
defer ts.Close()
@@ -37,7 +37,7 @@ type dslShowVersionWarning struct{}
func (d *dslShowVersionWarning) Execute(templatePath string) error {
router := httprouter.New()
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
- fmt.Fprintf(w, "DSL version parsing warning test")
+ _, _ = fmt.Fprintf(w, "DSL version parsing warning test")
})
ts := httptest.NewServer(router)
defer ts.Close()
diff --git a/cmd/integration-test/flow.go b/cmd/integration-test/flow.go
index 46ae7cf5f..1c103b95a 100644
--- a/cmd/integration-test/flow.go
+++ b/cmd/integration-test/flow.go
@@ -49,7 +49,7 @@ func (t *iterateValuesFlow) Execute(filePath string) error {
}
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
w.WriteHeader(http.StatusOK)
- _, _ = w.Write([]byte(fmt.Sprint(testemails)))
+ _, _ = fmt.Fprint(w, testemails)
})
router.GET("/user/"+getBase64(testemails[0]), func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
w.WriteHeader(http.StatusOK)
diff --git a/cmd/integration-test/fuzz.go b/cmd/integration-test/fuzz.go
index 230fff031..c2c4bee3a 100644
--- a/cmd/integration-test/fuzz.go
+++ b/cmd/integration-test/fuzz.go
@@ -55,7 +55,7 @@ func (h *httpFuzzQuery) Execute(filePath string) error {
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
w.Header().Set("Content-Type", "text/html")
value := r.URL.Query().Get("id")
- fmt.Fprintf(w, "This is test matcher text: %v", value)
+ _, _ = fmt.Fprintf(w, "This is test matcher text: %v", value)
})
ts := httptest.NewTLSServer(router)
defer ts.Close()
@@ -75,7 +75,7 @@ func (h *fuzzModeOverride) Execute(filePath string) error {
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
w.Header().Set("Content-Type", "text/html")
value := r.URL.Query().Get("id")
- fmt.Fprintf(w, "This is test matcher text: %v", value)
+ _, _ = fmt.Fprintf(w, "This is test matcher text: %v", value)
})
ts := httptest.NewTLSServer(router)
defer ts.Close()
@@ -120,7 +120,7 @@ func (h *fuzzTypeOverride) Execute(filePath string) error {
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
w.Header().Set("Content-Type", "text/html")
value := r.URL.Query().Get("id")
- fmt.Fprintf(w, "This is test matcher text: %v", value)
+ _, _ = fmt.Fprintf(w, "This is test matcher text: %v", value)
})
ts := httptest.NewTLSServer(router)
defer ts.Close()
@@ -164,7 +164,7 @@ func (h *HeadlessFuzzingQuery) Execute(filePath string) error {
router := httprouter.New()
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
resp := fmt.Sprintf("%s", r.URL.Query().Get("url"))
- fmt.Fprint(w, resp)
+ _, _ = fmt.Fprint(w, resp)
})
ts := httptest.NewTLSServer(router)
defer ts.Close()
@@ -190,7 +190,7 @@ func (h *fuzzMultipleMode) Execute(filePath string) error {
}
w.Header().Set("Content-Type", "text/html")
resp := fmt.Sprintf("This is multi-mode fuzzing test: %v ", xClientId)
- fmt.Fprint(w, resp)
+ _, _ = fmt.Fprint(w, resp)
})
ts := httptest.NewTLSServer(router)
defer ts.Close()
diff --git a/cmd/integration-test/generic.go b/cmd/integration-test/generic.go
index 95ab5694c..f5edfc946 100644
--- a/cmd/integration-test/generic.go
+++ b/cmd/integration-test/generic.go
@@ -82,14 +82,15 @@ func (h *clientCertificate) Execute(filePath string) error {
return
}
- fmt.Fprintf(w, "Hello, %s!\n", r.TLS.PeerCertificates[0].Subject)
+ _, _ = fmt.Fprintf(w, "Hello, %s!\n", r.TLS.PeerCertificates[0].Subject)
})
_ = os.WriteFile("server.crt", []byte(serverCRT), permissionutil.ConfigFilePermission)
_ = os.WriteFile("server.key", []byte(serverKey), permissionutil.ConfigFilePermission)
- defer os.Remove("server.crt")
- defer os.Remove("server.key")
-
+ defer func() {
+ _ = os.Remove("server.crt")
+ _ = os.Remove("server.key")
+ }()
serverCert, _ := tls.LoadX509KeyPair("server.crt", "server.key")
certPool := x509.NewCertPool()
diff --git a/cmd/integration-test/headless.go b/cmd/integration-test/headless.go
index abe93acc9..04ccd295d 100644
--- a/cmd/integration-test/headless.go
+++ b/cmd/integration-test/headless.go
@@ -178,7 +178,9 @@ func (h *headlessFileUpload) Execute(filePath string) error {
return
}
- defer file.Close()
+ defer func() {
+ _ = file.Close()
+ }()
content, err := io.ReadAll(file)
if err != nil {
@@ -235,7 +237,9 @@ func (h *headlessFileUploadNegative) Execute(filePath string) error {
return
}
- defer file.Close()
+ defer func() {
+ _ = file.Close()
+ }()
content, err := io.ReadAll(file)
if err != nil {
diff --git a/cmd/integration-test/http.go b/cmd/integration-test/http.go
index f0e5d1ae2..315f90218 100644
--- a/cmd/integration-test/http.go
+++ b/cmd/integration-test/http.go
@@ -108,7 +108,7 @@ func (h *httpMatcherExtractorDynamicExtractor) Execute(filePath string) error {
Domains