Repository: projectdiscovery/nuclei

Issue:
Integrate metadata validation in Cache.Has to detect template disk changes
## Problem

In SDK use cases where a single `Parser` instance remains active for an extended period, templates on disk may change while the parser continues to use cached copies. Currently, the `parsedTemplate` and `compiledTemplate` caches are populated during the first call to `(*Parser).ParseTemplate` and remain in memory for the parser's lifetime. These caches return cached copies even if the file on disk changes, unless the update process runs mid-execution or something explicitly invalidates/purges the cache.

No calls to `(parsed|compiled)Template.Purge()` are currently present in the codebase to handle this scenario.

## Proposed Solution

Integrate a minimal/quick metadata validation layer into `Cache.Has` that:
- Stays fast but better handles disk changes
- Avoids forcing a full template reload
- Validates template metadata efficiently to detect changes

This would allow the cache to remain performant while properly invalidating entries when the underlying template files are modified.

## Context

- Related PR: https://github.com/projectdiscovery/nuclei/pull/6504
- Discussion: https://github.com/projectdiscovery/nuclei/pull/6504#discussion_r1888577889
- Requested by: @dwisiswant0

Hints from issue comments:

Solution patch:
diff --git a/.claude/settings.local.json b/.claude/settings.local.json
deleted file mode 100644
index bcd49f4c..00000000
--- a/.claude/settings.local.json
+++ /dev/null
@@ -1,35 +0,0 @@
-{
-  "permissions": {
-    "allow": [
-      "Bash(find:*)",
-      "Bash(mkdir:*)",
-      "Bash(cp:*)",
-      "Bash(ls:*)",
-      "Bash(make:*)",
-      "Bash(go:*)",
-      "Bash(golangci-lint:*)",
-      "Bash(git merge:*)",
-      "Bash(git add:*)",
-      "Bash(git commit:*)",
-      "Bash(git push:*)",
-      "Bash(git pull:*)",
-      "Bash(git fetch:*)",
-      "Bash(git checkout:*)",
-      "WebFetch(*)",
-      "Write(*)",
-      "WebSearch(*)",
-      "MultiEdit(*)",
-      "Edit(*)",
-      "Bash(gh:*)",
-      "Bash(grep:*)",
-      "Bash(tree:*)",
-      "Bash(./nuclei:*)",
-      "WebFetch(domain:github.com)"
-    ],
-    "deny": [
-      "Bash(make run:*)",
-      "Bash(./bin/nuclei:*)"
-    ],
-    "defaultMode": "acceptEdits"
-  }
-}
\ No newline at end of file
diff --git a/.github/ISSUE_TEMPLATE/reference-templates/bug-report-reference.yml b/.github/ISSUE_TEMPLATE/bug-report.yml
similarity index 100%
rename from .github/ISSUE_TEMPLATE/reference-templates/bug-report-reference.yml
rename to .github/ISSUE_TEMPLATE/bug-report.yml
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
index 4a0c58e2..82b8869a 100644
--- a/.github/ISSUE_TEMPLATE/config.yml
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -2,10 +2,6 @@ blank_issues_enabled: false
 
 contact_links:
 
-  - name: 🐛 Report a Bug (Start with Discussion)
-    url: https://github.com/orgs/projectdiscovery/discussions/new?category=q-a
-    about: Start by reporting your issue in discussions for proper triage. Issues will be created after review to avoid duplicate/invalid reports.
-
   - name: 💡 Request a Feature (Start with Discussion)
     url: https://github.com/orgs/projectdiscovery/discussions/new?category=ideas
     about: Share your feature idea in discussions first. This helps validate and refine the request before creating an issue.
diff --git a/.github/workflows/govulncheck.yaml b/.github/workflows/govulncheck.yaml
index 9796b709..11898380 100644
--- a/.github/workflows/govulncheck.yaml
+++ b/.github/workflows/govulncheck.yaml
@@ -20,7 +20,7 @@ jobs:
       - uses: projectdiscovery/actions/setup/go@v1
       - run: go install golang.org/x/vuln/cmd/govulncheck@latest
       - run: govulncheck -scan package -format sarif ./... > $OUTPUT
-      - uses: github/codeql-action/upload-sarif@v3
+      - uses: github/codeql-action/upload-sarif@v4
         with:
           sarif_file: "${{ env.OUTPUT }}"
           category: "govulncheck"
diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml
index cc7f7b98..d616e8b7 100644
--- a/.github/workflows/tests.yaml
+++ b/.github/workflows/tests.yaml
@@ -120,11 +120,11 @@ jobs:
       security-events: write
     steps:
       - uses: actions/checkout@v5
-      - uses: github/codeql-action/init@v3
+      - uses: github/codeql-action/init@v4
         with:
           languages: 'go'
-      - uses: github/codeql-action/autobuild@v3
-      - uses: github/codeql-action/analyze@v3
+      - uses: github/codeql-action/autobuild@v4
+      - uses: github/codeql-action/analyze@v4
 
   release:
     name: "Release test"
diff --git a/.gitignore b/.gitignore
index 8e4f9d93..25c2c06c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,7 +8,7 @@
 .gitignore
 .idea
 .vscode
-
+.claude/settings.local.json
 # Binaries
 /bin/*
 /bindgen
diff --git a/Makefile b/Makefile
index bfb0b5a6..d0d995bf 100644
--- a/Makefile
+++ b/Makefile
@@ -147,8 +147,6 @@ template-validate: build
 template-validate:
 	./bin/nuclei -ut
 	./bin/nuclei -validate \
-		-et .github/ \
-		-et helpers/payloads/ \
 		-et http/technologies \
 		-t dns \
 		-t ssl \
@@ -157,7 +155,5 @@ template-validate:
 		-ept code
 	./bin/nuclei -validate \
 		-w workflows \
-		-et .github/ \
-		-et helpers/payloads/ \
 		-et http/technologies \
 		-ept code
\ No newline at end of file
diff --git a/README.md b/README.md
index 490b6070..72d05dc1 100644
--- a/README.md
+++ b/README.md
@@ -111,7 +111,7 @@ Browse the full Nuclei [**`documentation here`**](https://docs.projectdiscovery.
 
 ### Installation
 
-`nuclei` requires **go1.23** to install successfully. Run the following command to get the repo:
+`nuclei` requires **go >= 1.24.1** to install successfully. Run the following command to get the repo:
 
 ```sh
 go install -v github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest
@@ -286,6 +286,7 @@ RATE-LIMIT:
    -jsc, -js-concurrency int          maximum number of javascript runtimes to be executed in parallel (default 120)
    -pc, -payload-concurrency int      max payload concurrency for each template (default 25)
    -prc, -probe-concurrency int       http probe concurrency with httpx (default 50)
+   -tlc, -template-loading-concurrency int  maximum number of concurrent template loading operations (default 50)
 
 OPTIMIZATIONS:
    -timeout int                     time to wait in seconds before timeout (default 10)
diff --git a/README_CN.md b/README_CN.md
index 99f150e6..5fb4dd14 100644
--- a/README_CN.md
+++ b/README_CN.md
@@ -238,6 +238,7 @@ UNCOVER引擎:
    -c, -concurrency int                  并行执行的最大模板数量（默认：25）
    -hbs, -headless-bulk-size int         每个模板并行运行的无头主机最大数量（默认：10）
    -headc, -headless-concurrency int     并行指定无头主机最大数量（默认：10）
+   -tlc, -template-loading-concurrency int  最大并发模板加载操作数（默认：50）
 
 
 优化：
diff --git a/README_ES.md b/README_ES.md
index 27f60ee8..ec7949ef 100644
--- a/README_ES.md
+++ b/README_ES.md
@@ -244,6 +244,7 @@ RATE-LIMIT:
    -headc, -headless-concurrency int  número máximo de plantillas headless a ejecutar en paralelo (por defecto 10)
    -jsc, -js-concurrency int          número máximo de entornos de ejecución de JavaScript a ejecutar en paralelo (por defecto 120)
    -pc, -payload-concurrency int      concurrencia máxima de carga útil para cada plantilla (por defecto 25)
+   -tlc, -template-loading-concurrency int  número máximo de operaciones de carga de plantillas concurrentes (por defecto 50)
 
 OPTIMIZATIONS:
    -timeout int                     tiempo de espera en segundos (por defecto 10)
diff --git a/README_ID.md b/README_ID.md
index 05c163c2..459352b4 100644
--- a/README_ID.md
+++ b/README_ID.md
@@ -211,6 +211,7 @@ RATE-LIMIT:
    -c, -concurrency int               maximum number of templates to be executed in parallel (default 25)
    -hbs, -headless-bulk-size int      maximum number of headless hosts to be analyzed in parallel per template (default 10)
    -headc, -headless-concurrency int  maximum number of headless templates to be executed in parallel (default 10)
+   -tlc, -template-loading-concurrency int  maximum number of concurrent template loading operations (default 50)
 
 OPTIMIZATIONS:
    -timeout int                        time to wait in seconds before timeout (default 10)
diff --git a/README_KR.md b/README_KR.md
index 6181c866..d0828564 100644
--- a/README_KR.md
+++ b/README_KR.md
@@ -209,6 +209,7 @@ RATE-LIMIT:
    -c, -concurrency int               병렬로 실행할 최대 템플릿 수 (기본값 25)
    -hbs, -headless-bulk-size int      템플릿당 병렬로 분석할 최대 headless 호스트 수 (기본값 10)
    -headc, -headless-concurrency int  병렬로 실행할 최대 headless 템플릿 수 (기본값 10)
+   -tlc, -template-loading-concurrency int  최대 동시 템플릿 로딩 작업 수 (기본값 50)
 
 OPTIMIZATIONS:
    -timeout int                     타임아웃 전에 기다릴 초 수 (기본값 10)
diff --git a/README_PT-BR.md b/README_PT-BR.md
index 012f878f..e63a3d8a 100644
--- a/README_PT-BR.md
+++ b/README_PT-BR.md
@@ -244,6 +244,7 @@ RATE-LIMIT:
    -headc, -headless-concurrency int  número máximo de templates headless a serem executados em paralelo (padrão 10)
    -jsc, -js-concurrency int          número máximo de ambientes de execução de JavaScript a serem executados em paralelo (padrão 120)
    -pc, -payload-concurrency int      concorrência máxima de payload para cada template (padrão 25)
+   -tlc, -template-loading-concurrency int  número máximo de operações de carregamento de templates concorrentes (padrão 50)
 
 OPTIMIZATIONS:
    -timeout int                     tempo limite em segundos (padrão 10)
diff --git a/SYNTAX-REFERENCE.md b/SYNTAX-REFERENCE.md
index 24cbd04d..8c969912 100755
--- a/SYNTAX-REFERENCE.md
+++ b/SYNTAX-REFERENCE.md
@@ -3218,7 +3218,7 @@ Inputs contains inputs for the network socket
 <div class="dt">
 
 description: |
-   Port is the port to send network requests to. this acts as default port but is overriden if target/input contains
+   Port is the port to send network requests to. this acts as default port but is overridden if target/input contains
  non-http(s) ports like 80,8080,8081 etc
 
 </div>
diff --git a/cmd/nuclei/main.go b/cmd/nuclei/main.go
index c08f52bf..188d3fba 100644
--- a/cmd/nuclei/main.go
+++ b/cmd/nuclei/main.go
@@ -411,6 +411,7 @@ on extensive configurability, massive extensibility and ease of use.`)
 		flagSet.IntVarP(&options.JsConcurrency, "js-concurrency", "jsc", 120, "maximum number of javascript runtimes to be executed in parallel"),
 		flagSet.IntVarP(&options.PayloadConcurrency, "payload-concurrency", "pc", 25, "max payload concurrency for each template"),
 		flagSet.IntVarP(&options.ProbeConcurrency, "probe-concurrency", "prc", 50, "http probe concurrency with httpx"),
+		flagSet.IntVarP(&options.TemplateLoadingConcurrency, "template-loading-concurrency", "tlc", types.DefaultTemplateLoadingConcurrency, "maximum number of concurrent template loading operations"),
 	)
 	flagSet.CreateGroup("optimization", "Optimizations",
 		flagSet.IntVar(&options.Timeout, "timeout", 10, "time to wait in seconds before timeout"),
diff --git a/go.mod b/go.mod
index cfb19222..d8854f73 100644
--- a/go.mod
+++ b/go.mod
@@ -18,16 +18,16 @@ require (
 	github.com/json-iterator/go v1.1.12
 	github.com/julienschmidt/httprouter v1.3.0
 	github.com/logrusorgru/aurora v2.0.3+incompatible
-	github.com/miekg/dns v1.1.66
+	github.com/miekg/dns v1.1.68
 	github.com/olekukonko/tablewriter v1.0.8
 	github.com/pkg/errors v0.9.1
 	github.com/projectdiscovery/clistats v0.1.1
-	github.com/projectdiscovery/fastdialer v0.4.11
-	github.com/projectdiscovery/hmap v0.0.94
+	github.com/projectdiscovery/fastdialer v0.4.13
+	github.com/projectdiscovery/hmap v0.0.95
 	github.com/projectdiscovery/interactsh v1.2.4
 	github.com/projectdiscovery/rawhttp v0.1.90
-	github.com/projectdiscovery/retryabledns v1.0.107
-	github.com/projectdiscovery/retryablehttp-go v1.0.125
+	github.com/projectdiscovery/retryabledns v1.0.108
+	github.com/projectdiscovery/retryablehttp-go v1.0.128
 	github.com/projectdiscovery/yamldoc-go v1.0.6
 	github.com/remeh/sizedwaitgroup v1.0.0
 	github.com/rs/xid v1.6.0
@@ -91,26 +91,26 @@ require (
 	github.com/microsoft/go-mssqldb v1.9.2
 	github.com/ory/dockertest/v3 v3.12.0
 	github.com/praetorian-inc/fingerprintx v1.1.15
-	github.com/projectdiscovery/dsl v0.7.0
+	github.com/projectdiscovery/dsl v0.8.0
 	github.com/projectdiscovery/fasttemplate v0.0.2
 	github.com/projectdiscovery/gcache v0.0.0-20241015120333-12546c6e3f4c
 	github.com/projectdiscovery/go-smb2 v0.0.0-20240129202741-052cc450c6cb
 	github.com/projectdiscovery/goflags v0.1.74
-	github.com/projectdiscovery/gologger v1.1.55
+	github.com/projectdiscovery/gologger v1.1.58
 	github.com/projectdiscovery/gostruct v0.0.2
 	github.com/projectdiscovery/gozero v0.1.0
 	github.com/projectdiscovery/httpx v1.7.2-0.20250911192144-fc425deb041a
-	github.com/projectdiscovery/mapcidr v1.1.34
+	github.com/projectdiscovery/mapcidr v1.1.96
 	github.com/projectdiscovery/n3iwf v0.0.0-20230523120440-b8cd232ff1f5
-	github.com/projectdiscovery/networkpolicy v0.1.25
+	github.com/projectdiscovery/networkpolicy v0.1.26
 	github.com/projectdiscovery/ratelimit v0.0.82
 	github.com/projectdiscovery/rdap v0.9.0
 	github.com/projectdiscovery/sarif v0.0.1
 	github.com/projectdiscovery/tlsx v1.2.1
 	github.com/projectdiscovery/uncover v1.1.0
-	github.com/projectdiscovery/useragent v0.0.101
-	github.com/projectdiscovery/utils v0.5.0
-	github.com/projectdiscovery/wappalyzergo v0.2.47
+	github.com/projectdiscovery/useragent v0.0.102
+	github.com/projectdiscovery/utils v0.6.0
+	github.com/projectdiscovery/wappalyzergo v0.2.50
 	github.com/redis/go-redis/v9 v9.11.0
 	github.com/seh-msft/burpxml v1.0.1
 	github.com/shurcooL/graphql v0.0.0-20230722043721-ed46e5a46466
@@ -174,6 +174,7 @@ require (
 	github.com/bodgit/plumbing v1.3.0 // indirect
 	github.com/bodgit/sevenzip v1.6.0 // indirect
 	github.com/bodgit/windows v1.0.1 // indirect
+	github.com/brianvoe/gofakeit/v7 v7.2.1 // indirect
 	github.com/buger/jsonparser v1.1.1 // indirect
 	github.com/bytedance/sonic/loader v0.3.0 // indirect
 	github.com/caddyserver/certmagic v0.19.2 // indirect
@@ -189,7 +190,7 @@ require (
 	github.com/cloudflare/cfssl v1.6.4 // indirect
 	github.com/cloudflare/circl v1.6.1 // indirect
 	github.com/cloudwego/base64x v0.1.5 // indirect
-	github.com/cnf/structhash v0.0.0-20201127153200-e1b16c1ebc08 // indirect
+	github.com/cnf/structhash v0.0.0-20250313080605-df4c6cc74a9a // indirect
 	github.com/containerd/continuity v0.4.5 // indirect
 	github.com/containerd/errdefs v1.0.0 // indirect
 	github.com/containerd/errdefs/pkg v0.3.0 // indirect
@@ -241,6 +242,8 @@ require (
 	github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 // indirect
 	github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
 	github.com/gorilla/css v1.0.1 // indirect
+	github.com/gosimple/slug v1.15.0 // indirect
+	github.com/gosimple/unidecode v1.0.1 // indirect
 	github.com/hashicorp/errwrap v1.1.0 // indirect
 	github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
 	github.com/hashicorp/go-multierror v1.1.1 // indirect
@@ -318,7 +321,7 @@ require (
 	github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
 	github.com/projectdiscovery/asnmap v1.1.1 // indirect
 	github.com/projectdiscovery/blackrock v0.0.1 // indirect
-	github.com/projectdiscovery/cdncheck v1.2.0 // indirect
+	github.com/projectdiscovery/cdncheck v1.2.5 // 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
@@ -335,7 +338,7 @@ require (
 	github.com/tidwall/buntdb v1.3.1 // indirect
 	github.com/tidwall/gjson v1.18.0 // indirect
 	github.com/tidwall/grect v0.1.4 // indirect
-	github.com/tidwall/match v1.1.1 // indirect
+	github.com/tidwall/match v1.2.0 // indirect
 	github.com/tidwall/pretty v1.2.1 // indirect
 	github.com/tidwall/rtred v0.1.2 // indirect
 	github.com/tidwall/tinyqueue v0.1.1 // indirect
@@ -394,11 +397,11 @@ require (
 	go.uber.org/zap v1.27.0 // indirect
 	goftp.io/server/v2 v2.0.1 // indirect
 	golang.org/x/crypto v0.42.0 // indirect
-	golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b
-	golang.org/x/mod v0.27.0 // indirect
+	golang.org/x/exp v0.0.0-20250911091902-df9299821621
+	golang.org/x/mod v0.28.0 // indirect
 	golang.org/x/sys v0.36.0 // indirect
 	golang.org/x/time v0.11.0 // indirect
-	golang.org/x/tools v0.36.0
+	golang.org/x/tools v0.37.0
 	google.golang.org/protobuf v1.36.6 // indirect
 	gopkg.in/alecthomas/kingpin.v2 v2.2.6 // indirect
 	gopkg.in/corvus-ch/zbase32.v1 v1.0.0 // indirect
diff --git a/go.sum b/go.sum
index 1ad6e6ab..4a27a01a 100644
--- a/go.sum
+++ b/go.sum
@@ -468,6 +468,8 @@ github.com/bodgit/windows v1.0.1 h1:tF7K6KOluPYygXa3Z2594zxlkbKPAOvqr97etrGNIz4=
 github.com/bodgit/windows v1.0.1/go.mod h1:a6JLwrB4KrTR5hBpp8FI9/9W9jJfeQ2h4XDXU74ZCdM=
 github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
 github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
+github.com/brianvoe/gofakeit/v7 v7.2.1 h1:AGojgaaCdgq4Adzrd2uWdbGNDyX6MWNhHdQBraNfOHI=
+github.com/brianvoe/gofakeit/v7 v7.2.1/go.mod h1:QXuPeBw164PJCzCUZVmgpgHJ3Llj49jSLVkKPMtxtxA=
 github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
 github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
 github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
@@ -554,8 +556,8 @@ github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101/go.mod h1:eXthEFrGJvWH
 github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa/go.mod h1:x/1Gn8zydmfq8dk6e9PdstVsDgu9RuyIIJqAaF//0IM=
 github.com/cncf/xds/go v0.0.0-20240318125728-8a4994d93e50/go.mod h1:5e1+Vvlzido69INQaVO6d87Qn543Xr6nooe9Kz7oBFM=
 github.com/cncf/xds/go v0.0.0-20240423153145-555b57ec207b/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
-github.com/cnf/structhash v0.0.0-20201127153200-e1b16c1ebc08 h1:ox2F0PSMlrAAiAdknSRMDrAr8mfxPCfSZolH+/qQnyQ=
-github.com/cnf/structhash v0.0.0-20201127153200-e1b16c1ebc08/go.mod h1:pCxVEbcm3AMg7ejXyorUXi6HQCzOIBf7zEDVPtw0/U4=
+github.com/cnf/structhash v0.0.0-20250313080605-df4c6cc74a9a h1:Ohw57yVY2dBTt+gsC6aZdteyxwlxfbtgkFEMTEkwgSw=
+github.com/cnf/structhash v0.0.0-20250313080605-df4c6cc74a9a/go.mod h1:pCxVEbcm3AMg7ejXyorUXi6HQCzOIBf7zEDVPtw0/U4=
 github.com/containerd/continuity v0.4.5 h1:ZRoN1sXq9u7V6QoHMcVWGhOwDFqZ4B9i5H6un1Wh0x4=
 github.com/containerd/continuity v0.4.5/go.mod h1:/lNJvtJKUQStBzpVQ1+rasXO1LAWtUQssk28EZvJ3nE=
 github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI=
@@ -933,6 +935,10 @@ github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8=
 github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0=
 github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
 github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
+github.com/gosimple/slug v1.15.0 h1:wRZHsRrRcs6b0XnxMUBM6WK1U1Vg5B0R7VkIf1Xzobo=
+github.com/gosimple/slug v1.15.0/go.mod h1:UiRaFH+GEilHstLUmcBgWcI42viBN7mAb818JrYOeFQ=
+github.com/gosimple/unidecode v1.0.1 h1:hZzFTMMqSswvf0LBJZCZgThIZrpDHFXux9KeGmn6T/o=
+github.com/gosimple/unidecode v1.0.1/go.mod h1:CP0Cr1Y1kogOtx0bJblKzsVWrqYaqfNOnHzpgWw4Awc=
 github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
 github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
 github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks=
@@ -1132,8 +1138,8 @@ github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB
 github.com/microsoft/go-mssqldb v1.9.2 h1:nY8TmFMQOHpm2qVWo6y4I2mAmVdZqlGiMGAYt64Ibbs=
 github.com/microsoft/go-mssqldb v1.9.2/go.mod h1:GBbW9ASTiDC+mpgWDGKdm3FnFLTUsLYN3iFL90lQ+PA=
 github.com/miekg/dns v1.1.35/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
-github.com/miekg/dns v1.1.66 h1:FeZXOS3VCVsKnEAd+wBkjMC3D2K+ww66Cq3VnCINuJE=
-github.com/miekg/dns v1.1.66/go.mod h1:jGFzBsSNbJw6z1HYut1RKBKHA9PBdxeHrZG8J+gC2WE=
+github.com/miekg/dns v1.1.68 h1:jsSRkNozw7G/mnmXULynzMNIsgY2dHC8LO6U6Ij2JEA=
+github.com/miekg/dns v1.1.68/go.mod h1:fujopn7TB3Pu3JM69XaawiU0wqjpL9/8xGop5UrTPps=
 github.com/mikelolasagasti/xz v1.0.1 h1:Q2F2jX0RYJUG3+WsM+FJknv+6eVjsjXNDV0KJXZzkD0=
 github.com/mikelolasagasti/xz v1.0.1/go.mod h1:muAirjiOUxPRXwm9HdDtB3uoRPrGnL85XHtokL9Hcgc=
 github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY=
@@ -1249,14 +1255,14 @@ 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.2.0 h1:KzBk+U7w7vQ5y//pCfynQq8qxnFbf2XFmjGltmPJogs=
-github.com/projectdiscovery/cdncheck v1.2.0/go.mod h1:dSyW7D7ItsBp9dRoBh2JrL/s16lZkToUN2XvODNSGjA=
+github.com/projectdiscovery/cdncheck v1.2.5 h1:LCN5qBpxmF4SXxAvdCo0zH6YRUnVmNWxzAVcpMhRbOo=
+github.com/projectdiscovery/cdncheck v1.2.5/go.mod h1:hXim20sWKECI4u7RD+kxEkEogMjGUZwYEcaiyzvE0Tg=
 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.7.0 h1:tfZcsVCoujXvJq2AtplMUWdSvYcQt81uDcNCfHzTLC8=
-github.com/projectdiscovery/dsl v0.7.0/go.mod h1:tRkJQglLwBjaH9Z5wcf/zZOafo+G1TyrhKV6CtQnD4k=
-github.com/projectdiscovery/fastdialer v0.4.11 h1:6JYoORInQiENFPTqGMI+1GaL5hOTD/sjWrSbzM8d+Z0=
-github.com/projectdiscovery/fastdialer v0.4.11/go.mod h1:i2dB26BHw0BMrx7ccbHcb/1LE5q9gy0ojvBytATl38E=
+github.com/projectdiscovery/dsl v0.8.0 h1:T7csfhoZ4RuhTX3zw/hr/G7OkDvC/+mKgUZvjkrxxsY=
+github.com/projectdiscovery/dsl v0.8.0/go.mod h1:V+XFrOE8xaBQm3wAR6MY1xmB26+Gr6LeUAo1AzwwHic=
+github.com/projectdiscovery/fastdialer v0.4.13 h1:cxRHqGNBQffBDzBNTle0+4jfj57e+l7Q7bXqtf3lNPM=
+github.com/projectdiscovery/fastdialer v0.4.13/go.mod h1:V7g6xD3r0PXGWmiQUbUVBYeKusAXbpdePuEz1jGDeY8=
 github.com/projectdiscovery/fasttemplate v0.0.2 h1:h2cISk5xDhlJEinlBQS6RRx0vOlOirB2y3Yu4PJzpiA=
 github.com/projectdiscovery/fasttemplate v0.0.2/go.mod h1:XYWWVMxnItd+r0GbjA1GCsUopMw1/XusuQxdyAIHMCw=
 github.com/projectdiscovery/freeport v0.0.7 h1:Q6uXo/j8SaV/GlAHkEYQi8WQoPXyJWxyspx+aFmz9Qk=
@@ -1267,14 +1273,14 @@ 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.55 h1:ASHPXrDyyvFSRMpWXK/UptujU/KwDGgVGbn9BhF8azo=
-github.com/projectdiscovery/gologger v1.1.55/go.mod h1:RtAcBG7KzTWmAEVEVWiBbKGKsYpqzxKXzn3yhAFkfic=
+github.com/projectdiscovery/gologger v1.1.58 h1:6qWSTTU5jtLz0nu+20xv6aZyovWlPMbXKadADSKKL+I=
+github.com/projectdiscovery/gologger v1.1.58/go.mod h1:8FJFKmo0N4ITIH3n1Jy4ze6ijr+mA3t78g+VpN8uBRU=
 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.1.0 h1:QC+WPEsEVFtPmAm9FiIVT/obv9rF/pS2mnag8zXIAQI=
 github.com/projectdiscovery/gozero v0.1.0/go.mod h1:gJUNa8eQgMxLaa0UiLChPTV71/BLLrlPAaUp1C2mrhs=
-github.com/projectdiscovery/hmap v0.0.94 h1:Q2/89U2rkDVz59j/WBzaRPmpRrYamDWnzQgauk+K03E=
-github.com/projectdiscovery/hmap v0.0.94/go.mod h1:QtqZlGUwq3/SNiwEfArayfwrZU4g0/tpw6lJlxP1XEI=
+github.com/projectdiscovery/hmap v0.0.95 h1:OO6MCySlK2xMzvJmsYUwdaI7YWv/U437OtsN0Ovw72k=
+github.com/projectdiscovery/hmap v0.0.95/go.mod h1:KiTRdGd/GzX7uaoFWPrPBxPf4X/uZ9HTQ9dQ8x7x1bo=
 github.com/projectdiscovery/httpx v1.7.2-0.20250911192144-fc425deb041a h1:5NBp4BegAQuT3QSnbBKt05LH1nOyEeFAXYh1+aE3Nlo=
 github.com/projectdiscovery/httpx v1.7.2-0.20250911192144-fc425deb041a/go.mod h1:SQl92RiEuBnv1QQ8aQLC3b1lfgGHttoqUV0cTTvlzxQ=
 github.com/projectdiscovery/interactsh v1.2.4 h1:WUSj+fxbcV53J64oIAhbYzCKD1w/IyenyRBhkI5jiqI=
@@ -1283,22 +1289,22 @@ github.com/projectdiscovery/ldapserver v1.0.2-0.20240219154113-dcc758ebc0cb h1:M
 github.com/projectdiscovery/ldapserver v1.0.2-0.20240219154113-dcc758ebc0cb/go.mod h1:vmgC0DTFCfoCLp0RAfsfYTZZan0QMVs+cmTbH6blfjk=
 github.com/projectdiscovery/machineid v0.0.0-20240226150047-2e2c51e35983 h1:ZScLodGSezQVwsQDtBSMFp72WDq0nNN+KE/5DHKY5QE=
 github.com/projectdiscovery/machineid v0.0.0-20240226150047-2e2c51e35983/go.mod h1:3G3BRKui7nMuDFAZKR/M2hiOLtaOmyukT20g88qRQjI=
-github.com/projectdiscovery/mapcidr v1.1.34 h1:udr83vQ7oz3kEOwlsU6NC6o08leJzSDQtls1wmXN/kM=
-github.com/projectdiscovery/mapcidr v1.1.34/go.mod h1:1+1R6OkKSAKtWDXE9RvxXtXPoajXTYX0eiEdkqlhQqQ=
+github.com/projectdiscovery/mapcidr v1.1.96 h1:MHDKi7rxrTVYsQWzLxfYcop/EPYa3ldUjB+oMbmuLBI=
+github.com/projectdiscovery/mapcidr v1.1.96/go.mod h1:be4kT3vBPxsJeeu3e50/0ZuhhfPMNjxOCCEeD4bryqE=
 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.25 h1:2f3Nxp4ncz/95hm6PkIDLcjMJI6ei2YsgkQ29NZn7b0=
-github.com/projectdiscovery/networkpolicy v0.1.25/go.mod h1:6zQPoZRyGeNq0WvWnL5cbah3mCg9KJiOn5tgVQWGIn4=
+github.com/projectdiscovery/networkpolicy v0.1.26 h1:RxZJoOyDM/Ru4GNHmrlsjBHqWz0TFMchK35S2W3Suw8=
+github.com/projectdiscovery/networkpolicy v0.1.26/go.mod h1:wC25awxBHp9y4o30hMeSobFaMHw+gWlcy55tL3Z84fM=
 github.com/projectdiscovery/ratelimit v0.0.82 h1:rtO5SQf5uQFu5zTahTaTcO06OxmG8EIF1qhdFPIyTak=
 github.com/projectdiscovery/ratelimit v0.0.82/go.mod h1:z076BrLkBb5yS7uhHNoCTf8X/BvFSGRxwQ8EzEL9afM=
 github.com/projectdiscovery/rawhttp v0.1.90 h1:LOSZ6PUH08tnKmWsIwvwv1Z/4zkiYKYOSZ6n+8RFKtw=
 github.com/projectdiscovery/rawhttp v0.1.90/go.mod h1:VZYAM25UI/wVB3URZ95ZaftgOnsbphxyAw/XnQRRz4Y=
 github.com/projectdiscovery/rdap v0.9.0 h1:wPhHx5pQ2QI+WGhyNb2PjhTl0NtB39Nk7YFZ9cp8ZGA=
 github.com/projectdiscovery/rdap v0.9.0/go.mod h1:zk4yrJFQ2Hy36Aqk+DvotYQxYAeALaCJ5ORySkff36Q=
-github.com/projectdiscovery/retryabledns v1.0.107 h1:Rd1JK7hfL68xRg3RzXmw9Q6B6WSNv9bdPhUoGvvebyg=
-github.com/projectdiscovery/retryabledns v1.0.107/go.mod h1:XddeOhDpwS0qR8/T4GXRGgDQsLhtRHw3TRdMsgJs28o=
-github.com/projectdiscovery/retryablehttp-go v1.0.125 h1:/00K0xHXIRLn2awpn6RD66rzBUyGfweHmtrGeDyKWok=
-github.com/projectdiscovery/retryablehttp-go v1.0.125/go.mod h1:69TkYApUaekghXT1TJxiwKLdEY1xO+H7RCDsHx5eKWg=
+github.com/projectdiscovery/retryabledns v1.0.108 h1:47LYRW2LY/0cDnZQfUhoOHNxe9rNc9NQ9ZfNrV/GbyM=
+github.com/projectdiscovery/retryabledns v1.0.108/go.mod h1:j7H7K6JZePh9PeNleeRUtDSrkUKMpwDhZw3Ogewzio8=
+github.com/projectdiscovery/retryablehttp-go v1.0.128 h1:A8j3cUAQxWDDZFLI+fw8BOEx+lgb9HPYs5JKkt+TX4g=
+github.com/projectdiscovery/retryablehttp-go v1.0.128/go.mod h1:u69sqeVz5tZAEf63s61WWSu6KawhsJJvCfJgdAvTNJM=
 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=
@@ -1307,12 +1313,12 @@ github.com/projectdiscovery/tlsx v1.2.1 h1:R8QgKb/vxd6Y0cfGFBYs4nn0zodHABeeLPqJj
 github.com/projectdiscovery/tlsx v1.2.1/go.mod h1:p19UHGQ6bvcbvhO4NvYBKOxlE4QvrUaectx9g/Mm3JA=
 github.com/projectdiscovery/uncover v1.1.0 h1:UDp/qLZn78YZb6VPoOrfyP1vz+ojEx8VrTTyjjRt9UU=
 github.com/projectdiscovery/uncover v1.1.0/go.mod h1:2rXINmMe/lmVAt2jn9CpAOs9An57/JEeLZobY3Z9kUs=
-github.com/projectdiscovery/useragent v0.0.101 h1:8A+XOJ/nIH+WqW8ogLxJ/psemGp8ATQ2/GuKroJ/81E=
-github.com/projectdiscovery/useragent v0.0.101/go.mod h1:RGoRw1BQ/lJnhYMbMpEKjyAAgCaDCr/+GsULo5yEJ2I=
-github.com/projectdiscovery/utils v0.5.0 h1:DN7mg2DpyObLByuObXzAFEkdNRDoPUnqE5N2szd3b3c=
-github.com/projectdiscovery/utils v0.5.0/go.mod h1:eCAWMmyaNxyPWbiKv1oeYJLIKpxceHE2+NWx3Jodhqk=
-github.com/projectdiscovery/wappalyzergo v0.2.47 h1:8cqpgVfby3AlnYDDDFUkuEZRvYCmVZvrKLxSnf09j1Q=
-github.com/projectdiscovery/wappalyzergo v0.2.47/go.mod h1:kPzB+L3ISGO5m8u5fukjlF5FJFJ1NLV86emOx+k3AVU=
+github.com/projectdiscovery/useragent v0.0.102 h1:Xfr8a7LQhIu0zeSz5gBxGCdyuqZbhkOMAEQUcEZXyBU=
+github.com/projectdiscovery/useragent v0.0.102/go.mod h1:DIfLRBKZ6dLhHRnMYkxdg6Jpu0kpE3pJlMG94dsIchY=
+github.com/projectdiscovery/utils v0.6.0 h1:rH4Haei7uHgqEq6pFGe8U+iD4PoBWUDB8LhoNxPawkk=
+github.com/projectdiscovery/utils v0.6.0/go.mod h1:NT7ExqILrDukgBFPPLBKQzSKYMBfecNcab7jT1bakRE=
+github.com/projectdiscovery/wappalyzergo v0.2.50 h1:vPhnTE60PTFuU1oiDZwP+Wa+EWx3Zrx925z18dHL3Ec=
+github.com/projectdiscovery/wappalyzergo v0.2.50/go.mod h1:kPzB+L3ISGO5m8u5fukjlF5FJFJ1NLV86emOx+k3AVU=
 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=
@@ -1458,8 +1464,9 @@ github.com/tidwall/grect v0.1.4 h1:dA3oIgNgWdSspFzn1kS4S/RDpZFLrIxAZOdJKjYapOg=
 github.com/tidwall/grect v0.1.4/go.mod h1:9FBsaYRaR0Tcy4UwefBX/UDcDcDy9V5jUcxHzv2jd5Q=
 github.com/tidwall/lotsa v1.0.2 h1:dNVBH5MErdaQ/xd9s769R31/n2dXavsQ0Yf4TMEHHw8=
 github.com/tidwall/lotsa v1.0.2/go.mod h1:X6NiU+4yHA3fE3Puvpnn1XMDrFZrE9JO2/w+UMuqgR8=
-github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
 github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
+github.com/tidwall/match v1.2.0 h1:0pt8FlkOwjN2fPt4bIl4BoNxb98gGHN2ObFEDkrfZnM=
+github.com/tidwall/match v1.2.0/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
 github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
 github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
 github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
@@ -1714,8 +1721,8 @@ golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EH
 golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
 golang.org/x/exp v0.0.0-20230206171751-46f607a40771/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
 golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
-golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b h1:M2rDM6z3Fhozi9O7NWsxAkg/yqS/lQJ6PmkyIV3YP+o=
-golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8=
+golang.org/x/exp v0.0.0-20250911091902-df9299821621 h1:2id6c1/gto0kaHYyrixvknJ8tUK/Qs5IsmBtrc+FtgU=
+golang.org/x/exp v0.0.0-20250911091902-df9299821621/go.mod h1:TwQYMMnGpvZyc+JpB/UAuTNIsVJifOlSkrZkhcvpVUk=
 golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
 golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
 golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
@@ -1765,8 +1772,8 @@ golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
 golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
 golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
 golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
-golang.org/x/mod v0.27.0 h1:kb+q2PyFnEADO2IEF935ehFUXlWiNjJWtRNgBLSfbxQ=
-golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc=
+golang.org/x/mod v0.28.0 h1:gQBtGhjxykdjY9YhZpSlZIsbnaE2+PgjfLWUQTnoZ1U=
+golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI=
 golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -2169,8 +2176,8 @@ golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58
 golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg=
 golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
 golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
-golang.org/x/tools v0.36.0 h1:kWS0uv/zsvHEle1LbV5LE8QujrxB3wfQyxHfhOk0Qkg=
-golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s=
+golang.org/x/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE=
+golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
diff --git a/pkg/catalog/config/nucleiconfig.go b/pkg/catalog/config/nucleiconfig.go
index e62dd37f..b74b9ad3 100644
--- a/pkg/catalog/config/nucleiconfig.go
+++ b/pkg/catalog/config/nucleiconfig.go
@@ -350,7 +350,7 @@ func (c *Config) IsDebugArgEnabled(arg string) bool {
 
 // parseDebugArgs from string
 func (c *Config) parseDebugArgs(data string) {
-	// use space as seperator instead of commas
+	// use space as separator instead of commas
 	tmp := strings.Fields(data)
 	for _, v := range tmp {
 		key := v
diff --git a/pkg/catalog/config/template.go b/pkg/catalog/config/template.go
index 3d7b33de..2f799918 100644
--- a/pkg/catalog/config/template.go
+++ b/pkg/catalog/config/template.go
@@ -12,7 +12,10 @@ import (
 	stringsutil "github.com/projectdiscovery/utils/strings"
 )
 
-var knownConfigFiles = []string{"cves.json", "contributors.json", "TEMPLATES-STATS.json"}
+var (
+	knownConfigFiles     = []string{"cves.json", "contributors.json", "TEMPLATES-STATS.json"}
+	knownMiscDirectories = []string{".git", ".github", "helpers"}
+)
 
 // TemplateFormat
 type TemplateFormat uint8
@@ -23,6 +26,25 @@ const (
 	Unknown
 )
 
+// GetKnownConfigFiles returns known config files.
+func GetKnownConfigFiles() []string {
+	return knownConfigFiles
+}
+
+// GetKnownMiscDirectories returns known misc directories with trailing slashes.
+//
+// The trailing slash ensures that directory matching is explicit and avoids
+// falsely match files with similar names (e.g. "helpers" matching
+// "some-helpers.yaml"), since [IsTemplate] checks against normalized full paths.
+func GetKnownMiscDirectories() []string {
+	trailedSlashDirs := make([]string, 0, len(knownMiscDirectories))
+	for _, dir := range knownMiscDirectories {
+		trailedSlashDirs = append(trailedSlashDirs, dir+string(os.PathSeparator))
+	}
+
+	return trailedSlashDirs
+}
+
 // GetTemplateFormatFromExt returns template format
 func GetTemplateFormatFromExt(filePath string) TemplateFormat {
 	fileExt := strings.ToLower(filepath.Ext(filePath))
@@ -41,13 +63,22 @@ func GetSupportTemplateFileExtensions() []string {
 	return []string{extensions.YAML, extensions.JSON}
 }
 
-// IsTemplate is a callback function used by goflags to decide if given file should be read
-// if it is not a nuclei-template file only then file is read
-func IsTemplate(filename string) bool {
-	if stringsutil.ContainsAny(filename, knownConfigFiles...) {
+// IsTemplate returns true if the file is a template based on its path.
+// It used by goflags and other places to filter out non-template files.
+func IsTemplate(fpath string) bool {
+	fpath = filepath.FromSlash(fpath)
+	fname := filepath.Base(fpath)
+	fext := strings.ToLower(filepath.Ext(fpath))
+
+	if stringsutil.ContainsAny(fname, GetKnownConfigFiles()...) {
+		return false
+	}
+
+	if stringsutil.ContainsAny(fpath, GetKnownMiscDirectories()...) {
 		return false
 	}
-	return stringsutil.EqualFoldAny(filepath.Ext(filename), GetSupportTemplateFileExtensions()...)
+
+	return stringsutil.EqualFoldAny(fext, GetSupportTemplateFileExtensions()...)
 }
 
 type template struct {
diff --git a/pkg/catalog/disk/find.go b/pkg/catalog/disk/find.go
index 7a70c1bc..0a89ba54 100644
--- a/pkg/catalog/disk/find.go
+++ b/pkg/catalog/disk/find.go
@@ -257,7 +257,7 @@ func (c *DiskCatalog) findDirectoryMatches(absPath string, processed map[string]
 				if err != nil {
 					return nil
 				}
-				if !d.IsDir() && config.GetTemplateFormatFromExt(path) != config.Unknown {
+				if !d.IsDir() && config.IsTemplate(path) {
 					if _, ok := processed[path]; !ok {
 						results = append(results, path)
 						processed[path] = struct{}{}
@@ -281,7 +281,7 @@ func (c *DiskCatalog) findDirectoryMatches(absPath string, processed map[string]
 				if err != nil {
 					return nil
 				}
-				if !d.IsDir() && config.GetTemplateFormatFromExt(path) != config.Unknown {
+				if !d.IsDir() && config.IsTemplate(path) {
 					if _, ok := processed[path]; !ok {
 						results = append(results, path)
 						processed[path] = struct{}{}
diff --git a/pkg/catalog/loader/loader.go b/pkg/catalog/loader/loader.go
index b1887149..a68153d8 100644
--- a/pkg/catalog/loader/loader.go
+++ b/pkg/catalog/loader/loader.go
@@ -7,6 +7,7 @@ import (
 	"os"
 	"sort"
 	"strings"
+	"sync"
 
 	"github.com/logrusorgru/aurora"
 	"github.com/pkg/errors"
@@ -88,6 +89,9 @@ type Store struct {
 
 	logger *gologger.Logger
 
+	// parserCacheOnce is used to cache the parser cache result
+	parserCacheOnce func() *templates.Cache
+
 	// NotFoundCallback is called for each not found template
 	// This overrides error handling for not found templates
 	NotFoundCallback func(template string) bool
@@ -155,6 +159,18 @@ func New(cfg *Config) (*Store, error) {
 		logger:         cfg.Logger,
 	}
 
+	store.parserCacheOnce = sync.OnceValue(func() *templates.Cache {
+		if cfg.ExecutorOptions == nil || cfg.ExecutorOptions.Parser == nil {
+			return nil
+		}
+
+		if parser, ok := cfg.ExecutorOptions.Parser.(*templates.Parser); ok {
+			return parser.Cache()
+		}
+
+		return nil
+	})
+
 	// Do a check to see if we have URLs in templates flag, if so
 	// we need to processs them separately and remove them from the initial list
 	var templatesFinal []string
@@ -310,11 +326,11 @@ func (store *Store) LoadTemplatesOnlyMetadata() error {
 			store.logger.Warning().Msg(err.Error())
 		}
 	}
-	parserItem, ok := store.config.ExecutorOptions.Parser.(*templates.Parser)
-	if !ok {
+
+	templatesCache := store.parserCacheOnce()
+	if templatesCache == nil {
 		return errors.New("invalid parser")
 	}
-	templatesCache := parserItem.Cache()
 
 	loadedTemplateIDs := mapsutil.NewSyncLockMap[string, struct{}]()
 
@@ -386,6 +402,7 @@ func (store *Store) areTemplatesValid(filteredTemplatePaths map[string]struct{})
 
 func (store *Store) areWorkflowOrTemplatesValid(filteredTemplatePaths map[string]struct{}, isWorkflow bool, load func(templatePath string, tagFilter *templates.TagFilter) (bool, error)) bool {
 	areTemplatesValid := true
+	parsedCache := store.parserCacheOnce()
 
 	for templatePath := range filteredTemplatePaths {
 		if _, err := load(templatePath, store.tagFilter); err != nil {
@@ -395,13 +412,26 @@ func (store *Store) areWorkflowOrTemplatesValid(filteredTemplatePaths map[string
 			}
 		}
 
-		template, err := templates.Parse(templatePath, store.preprocessor, store.config.ExecutorOptions)
-		if err != nil {
-			if isParsingError(store, "Error occurred parsing template %s: %s\n", templatePath, err) {
-				areTemplatesValid = false
-				continue
+		var template *templates.Template
+		var err error
+
+		if parsedCache != nil {
+			if cachedTemplate, _, cacheErr := parsedCache.Has(templatePath); cacheErr == nil && cachedTemplate != nil {
+				template = cachedTemplate
+			}
+		}
+
+		if template == nil {
+			template, err = templates.Parse(templatePath, store.preprocessor, store.config.ExecutorOptions)
+			if err != nil {
+				if isParsingError(store, "Error occurred parsing template %s: %s\n", templatePath, err) {
+					areTemplatesValid = false
+					continue
+				}
 			}
-		} else if template == nil {
+		}
+
+		if template == nil {
 			// NOTE(dwisiswant0): possibly global matchers template.
 			// This could definitely be handled better, for example by returning an
 			// `ErrGlobalMatchersTemplate` during `templates.Parse` and checking it
@@ -524,7 +554,11 @@ func (store *Store) LoadTemplatesWithTags(templatesList, tags []string) []*templ
 		}
 	}
 
-	wgLoadTemplates, errWg := syncutil.New(syncutil.WithSize(50))
+	concurrency := store.config.ExecutorOptions.Options.TemplateLoadingConcurrency
+	if concurrency <= 0 {
+		concurrency = types.DefaultTemplateLoadingConcurrency
+	}
+	wgLoadTemplates, errWg := syncutil.New(syncutil.WithSize(concurrency))
 	if errWg != nil {
 		panic("could not create wait group")
 	}
diff --git a/pkg/catalog/loader/remote_loader.go b/pkg/catalog/loader/remote_loader.go
index ccd5c27f..0455846e 100644
--- a/pkg/catalog/loader/remote_loader.go
+++ b/pkg/catalog/loader/remote_loader.go
@@ -97,7 +97,7 @@ func getRemoteContent(URL string, remoteTemplateDomainList []string, contentType
 		_ = response.Body.Close()
 	}()
 	if response.StatusCode < 200 || response.StatusCode > 299 {
-		return RemoteContent{Error: fmt.Errorf("get \"%s\": unexpect status %d", URL, response.StatusCode)}
+		return RemoteContent{Error: fmt.Errorf("get \"%s\": unexpected status %d", URL, response.StatusCode)}
 	}
 
 	scanner := bufio.NewScanner(response.Body)
diff --git a/pkg/fuzz/analyzers/time/time_delay.go b/pkg/fuzz/analyzers/time/time_delay.go
index d37b83e7..e22c9999 100644
--- a/pkg/fuzz/analyzers/time/time_delay.go
+++ b/pkg/fuzz/analyzers/time/time_delay.go
@@ -61,7 +61,7 @@ func checkTimingDependency(
 
 	var requestsSent []requestsSentMetadata
 	for requestsLeft > 0 {
-		isCorrelationPossible, delayRecieved, err := sendRequestAndTestConfidence(regression, highSleepTimeSeconds, requestSender, baselineDelay)
+		isCorrelationPossible, delayReceived, err := sendRequestAndTestConfidence(regression, highSleepTimeSeconds, requestSender, baselineDelay)
 		if err != nil {
 			return false, "", err
 		}
@@ -69,29 +69,29 @@ func checkTimingDependency(
 			return false, "", nil
 		}
 		// Check the delay is greater than baseline by seconds requested
-		if delayRecieved < baselineDelay+float64(highSleepTimeSeconds)*0.8 {
+		if delayReceived < baselineDelay+float64(highSleepTimeSeconds)*0.8 {
 			return false, "", nil
 		}
 		requestsSent = append(requestsSent, requestsSentMetadata{
 			delay:         highSleepTimeSeconds,
-			delayReceived: delayRecieved,
+			delayReceived: delayReceived,
 		})
 
-		isCorrelationPossibleSecond, delayRecievedSecond, err := sendRequestAndTestConfidence(regression, int(DefaultLowSleepTimeSeconds), requestSender, baselineDelay)
+		isCorrelationPossibleSecond, delayReceivedSecond, err := sendRequestAndTestConfidence(regression, int(DefaultLowSleepTimeSeconds), requestSender, baselineDelay)
 		if err != nil {
 			return false, "", err
 		}
 		if !isCorrelationPossibleSecond {
 			return false, "", nil
 		}
-		if delayRecievedSecond < baselineDelay+float64(DefaultLowSleepTimeSeconds)*0.8 {
+		if delayReceivedSecond < baselineDelay+float64(DefaultLowSleepTimeSeconds)*0.8 {
 			return false, "", nil
 		}
 		requestsLeft = requestsLeft - 2
 
 		requestsSent = append(requestsSent, requestsSentMetadata{
 			delay:         int(DefaultLowSleepTimeSeconds),
-			delayReceived: delayRecievedSecond,
+			delayReceived: delayReceivedSecond,
 		})
 	}
 
diff --git a/pkg/fuzz/dataformat/json.go b/pkg/fuzz/dataformat/json.go
index 99dd0430..5b6a1b95 100644
--- a/pkg/fuzz/dataformat/json.go
+++ b/pkg/fuzz/dataformat/json.go
@@ -12,7 +12,7 @@ import (
 // and not arrays
 //
 // TODO: Support arrays + other JSON oddities by
-// adding more attirbutes to the map[string]interface{}
+// adding more attributes to the map[string]interface{}
 type JSON struct{}
 
 var (
diff --git a/pkg/fuzz/frequency/tracker.go b/pkg/fuzz/frequency/tracker.go
index 063912b4..c7a630e3 100644
--- a/pkg/fuzz/frequency/tracker.go
+++ b/pkg/fuzz/frequency/tracker.go
@@ -21,14 +21,14 @@ import (
 // for parameters that are less likely to give results for a rule.
 type Tracker struct {
 	frequencies             gcache.Cache
-	paramOccurenceThreshold int
+	paramOccurrenceThreshold int
 
 	isDebug bool
 }
 
 const (
 	DefaultMaxTrackCount           = 10000
-	DefaultParamOccurenceThreshold = 10
+	DefaultParamOccurrenceThreshold = 10
 )
 
 type cacheItem struct {
@@ -38,7 +38,7 @@ type cacheItem struct {
 
 // New creates a new frequency tracker with a given maximum
 // number of params to track in LRU fashion with a max error threshold
-func New(maxTrackCount, paramOccurenceThreshold int) *Tracker {
+func New(maxTrackCount, paramOccurrenceThreshold int) *Tracker {
 	gc := gcache.New(maxTrackCount).ARC().Build()
 
 	var isDebug bool
@@ -48,7 +48,7 @@ func New(maxTrackCount, paramOccurenceThreshold int) *Tracker {
 	return &Tracker{
 		isDebug:                 isDebug,
 		frequencies:             gc,
-		paramOccurenceThreshold: paramOccurenceThreshold,
+		paramOccurrenceThreshold: paramOccurrenceThreshold,
 	}
 }
 
@@ -56,10 +56,10 @@ func (t *Tracker) Close() {
 	t.frequencies.Purge()
 }
 
-// MarkParameter marks a parameter as frequently occuring once.
+// MarkParameter marks a parameter as frequently occurring once.
 //
-// The logic requires a parameter to be marked as frequently occuring
-// multiple times before it's considered as frequently occuring.
+// The logic requires a parameter to be marked as frequently occurring
+// multiple times before it's considered as frequently occurring.
 func (t *Tracker) MarkParameter(parameter, target, template string) {
 	normalizedTarget := normalizeTarget(target)
 	key := getFrequencyKey(parameter, normalizedTarget, template)
@@ -81,7 +81,7 @@ func (t *Tracker) MarkParameter(parameter, target, template string) {
 	_ = t.frequencies.Set(key, existingCacheItemValue)
 }
 
-// IsParameterFrequent checks if a parameter is frequently occuring
+// IsParameterFrequent checks if a parameter is frequently occurring
 // in the input with no much results.
 func (t *Tracker) IsParameterFrequent(parameter, target, template string) bool {
 	normalizedTarget := normalizeTarget(target)
@@ -97,7 +97,7 @@ func (t *Tracker) IsParameterFrequent(parameter, target, template string) bool {
 	}
 	existingCacheItemValue := existingCacheItem.(*cacheItem)
 
-	if existingCacheItemValue.errors.Load() >= int32(t.paramOccurenceThreshold) {
+	if existingCacheItemValue.errors.Load() >= int32(t.paramOccurrenceThreshold) {
 		existingCacheItemValue.Do(func() {
 			gologger.Verbose().Msgf("[%s] Skipped %s from parameter for %s as found uninteresting %d times", template, parameter, target, existingCacheItemValue.errors.Load())
 		})
@@ -106,7 +106,7 @@ func (t *Tracker) IsParameterFrequent(parameter, target, template string) bool {
 	return false
 }
 
-// UnmarkParameter unmarks a parameter as frequently occuring. This carries
+// UnmarkParameter unmarks a parameter as frequently occurring. This carries
 // more weight and resets the frequency counter for the parameter causing
 // it to be checked again. This is done when results are found.
 func (t *Tracker) UnmarkParameter(parameter, target, template string) {
diff --git a/pkg/fuzz/parts.go b/pkg/fuzz/parts.go
index 7d0b51af..1b0835fa 100644
--- a/pkg/fuzz/parts.go
+++ b/pkg/fuzz/parts.go
@@ -136,7 +136,7 @@ func (rule *Rule) executePartComponentOnKV(input *ExecuteRuleInput, payload Valu
 				return qerr
 			}
 
-			// after building change back to original value to avoid repeating it in furthur requests
+			// after building change back to original value to avoid repeating it in further requests
 			if origKey != "" {
 				err = ruleComponent.SetValue(origKey, types.ToString(origValue)) // change back to previous value for temp
 				if err != nil {
diff --git a/pkg/installer/versioncheck.go b/pkg/installer/versioncheck.go
index f7764c73..8595bdfc 100644
--- a/pkg/installer/versioncheck.go
+++ b/pkg/installer/versioncheck.go
@@ -83,7 +83,7 @@ func UpdateIgnoreFile() error {
 }
 
 func doVersionCheck(isSDK bool) error {
-	// we use global retryablehttp client so its not immeditely gc'd if any references are held
+	// we use global retryablehttp client so its not immediately gc'd if any references are held
 	// and according our config we have idle connections which are shown as leaked by goleak in tests
 	// i.e we close all idle connections after our use and it doesn't affect any other part of the code
 	defer retryableHttpClient.HTTPClient.CloseIdleConnections()
diff --git a/pkg/js/CONTRIBUTE.md b/pkg/js/CONTRIBUTE.md
index 3608b173..e4c62d9d 100644
--- a/pkg/js/CONTRIBUTE.md
+++ b/pkg/js/CONTRIBUTE.md
@@ -9,7 +9,7 @@ The Very First before making any type of contribution to javascript runtime in n
 
 ## Documentation/Typo Contribution
 
-Most of Javascript API Reference documentation is auto-generated with help of code-generation and [jsdocgen](./devtools/jsdocgen/README.md) and hence any type of documentation contribution are always welcome and can be done by editing [javscript jsdoc](./generated/js/) files
+Most of Javascript API Reference documentation is auto-generated with help of code-generation and [jsdocgen](./devtools/jsdocgen/README.md) and hence any type of documentation contribution are always welcome and can be done by editing [javascript jsdoc](./generated/js/) files
 
 
 ## Improving Existing Libraries(aka node_modules)
@@ -33,7 +33,7 @@ Libraries/node_modules represent adding new protocol or something similar and sh
 
 ## Adding Helper Objects/Types/Functions
 
-Helper objects/types/functions can simply be understood as javascript utils to simplify writing javscript and reduce code duplication in javascript templates. Helper functions/objects are divided into two categories
+Helper objects/types/functions can simply be understood as javascript utils to simplify writing javascript and reduce code duplication in javascript templates. Helper functions/objects are divided into two categories
 
 ### javascript based helpers
 
@@ -47,7 +47,7 @@ go based helpers are written in go and can import any go library if required. Mi
 
 ### Updating / Publishing Docs
 
-Javscript Protocol Documentation is auto-generated using [jsdoc] and is hosted at [js-proto-docs](https://projectdiscovery.github.io/js-proto-docs/). To update documentation, please follow steps mentioned at [projectdiscovery/js-proto-docs](https://github.com/projectdiscovery/js-proto-docs)
+Javascript Protocol Documentation is auto-generated using [jsdoc] and is hosted at [js-proto-docs](https://projectdiscovery.github.io/js-proto-docs/). To update documentation, please follow steps mentioned at [projectdiscovery/js-proto-docs](https://github.com/projectdiscovery/js-proto-docs)
 
 
 ### Go Code Guidelines
@@ -60,7 +60,7 @@ Javscript Protocol Documentation is auto-generated using [jsdoc] and is hosted a
 		return false, protocolstate.ErrHostDenied.Msgf(host)
 	}
 ```
-3. Keep exported package clean. Do not keep unncessary global exports which the consumer of the API doesn't need to know about. Keep only user-exposed API public.
+3. Keep exported package clean. Do not keep unnecessary global exports which the consumer of the API doesn't need to know about. Keep only user-exposed API public.
 4. Use timeouts and context cancellation when calling Network related stuff. Also make sure to close your connections or provide a mechanism to the user of the API to do so.
 5. Always try to return single types from inside javascript with an error like `(IsRDP, error)` instead of returning multiple values `(name, version string, err error)`. The second one will get converted to an array is much harder for consumers to deal with. Instead, try to return `Structures` which will be accessible natively.
 
diff --git a/pkg/js/compiler/compiler.go b/pkg/js/compiler/compiler.go
index 3e8af509..adb36fe8 100644
--- a/pkg/js/compiler/compiler.go
+++ b/pkg/js/compiler/compiler.go
@@ -16,7 +16,7 @@ import (
 )
 
 var (
-	// ErrJSExecDeadline is the error returned when alloted time for script execution exceeds
+	// ErrJSExecDeadline is the error returned when allotted time for script execution exceeds
 	ErrJSExecDeadline = errkit.New("js engine execution deadline exceeded").SetKind(errkit.ErrKindDeadline).Build()
 )
 
diff --git a/pkg/js/compiler/pool.go b/pkg/js/compiler/pool.go
index a8b98b01..d8fa9696 100644
--- a/pkg/js/compiler/pool.go
+++ b/pkg/js/compiler/pool.go
@@ -214,7 +214,7 @@ func createNewRuntime() *goja.Runtime {
 	// by default import below modules every time
 	_ = runtime.Set("console", require.Require(runtime, console.ModuleName))
 
-	// Register embedded javacript helpers
+	// Register embedded javascript helpers
 	if err := global.RegisterNativeScripts(runtime); err != nil {
 		gologger.Error().Msgf("Could not register scripts: %s\n", err)
 	}
diff --git a/pkg/js/devtools/tsgen/parser.go b/pkg/js/devtools/tsgen/parser.go
index 9f7d81ed..0bf012d9 100644
--- a/pkg/js/devtools/tsgen/parser.go
+++ b/pkg/js/devtools/tsgen/parser.go
@@ -72,7 +72,7 @@ func (p *EntityParser) Parse() error {
 	for _, file := range p.syntax {
 		// Traverse the AST and find all relevant declarations
 		ast.Inspect(file, func(n ast.Node) bool {
-			// look for funtions and methods
+			// look for functions and methods
 			// and generate entities for them
 			fn, ok := n.(*ast.FuncDecl)
 			if ok {
diff --git a/pkg/js/generated/ts/mysql.ts b/pkg/js/generated/ts/mysql.ts
index bf5c8812..4007f057 100755
--- a/pkg/js/generated/ts/mysql.ts
+++ b/pkg/js/generated/ts/mysql.ts
@@ -64,7 +64,7 @@ export class MySQLClient {
     
 
     /**
-    * returns MySQLInfo when fingerpint is successful
+    * returns MySQLInfo when fingerprint is successful
     * @example
     * ```javascript
     * const mysql = require('nuclei/mysql');
diff --git a/pkg/js/global/helpers.go b/pkg/js/global/helpers.go
index 3df194d3..a51e3a46 100644
--- a/pkg/js/global/helpers.go
+++ b/pkg/js/global/helpers.go
@@ -41,7 +41,7 @@ func registerAdditionalHelpers(runtime *goja.Runtime) {
 
 func init() {
 	// these are dummy functions we use trigger documentation generation
-	// actual definations are in exports.js
+	// actual definitions are in exports.js
 	_ = gojs.RegisterFuncWithSignature(nil, gojs.FuncOpts{
 		Name: "to_json",
 		Signatures: []string{
diff --git a/pkg/js/libs/mysql/mysql.go b/pkg/js/libs/mysql/mysql.go
index c48c73a8..5e57aa66 100644
--- a/pkg/js/libs/mysql/mysql.go
+++ b/pkg/js/libs/mysql/mysql.go
@@ -127,7 +127,7 @@ type (
 	}
 )
 
-// returns MySQLInfo when fingerpint is successful
+// returns MySQLInfo when fingerprint is successful
 // @example
 // ```javascript
 // const mysql = require('nuclei/mysql');
diff --git a/pkg/js/libs/structs/smbexploit.js b/pkg/js/libs/structs/smbexploit.js
index 80f3b13c..aac76e9e 100644
--- a/pkg/js/libs/structs/smbexploit.js
+++ b/pkg/js/libs/structs/smbexploit.js
@@ -66,7 +66,7 @@ final.append(packet.bytes());
 
 console.log("Netbios", netbios.hex(), netbios.len());
 console.log("Header", header.hex(), header.len());
-console.log("Negotation", negotiation.hex(), negotiation.len());
+console.log("Negotiation", negotiation.hex(), negotiation.len());
 console.log("Packet", final.hex(), final.len());
 
 const c = require("nuclei/libnet");
diff --git a/pkg/output/output.go b/pkg/output/output.go
index f7909320..e18d2613 100644
--- a/pkg/output/output.go
+++ b/pkg/output/output.go
@@ -439,7 +439,7 @@ func getJSONLogRequestFromError(templatePath, input, requestType string, request
 			request.Attrs = slog.GroupValue(errX.Attrs()...)
 		}
 	}
-	// check if address slog attr is avaiable in error if set use it
+	// check if address slog attr is available in error if set use it
 	if val := errkit.GetAttrValue(requestErr, "address"); val.Any() != nil {
 		request.Address = val.String()
 	}
diff --git a/pkg/protocols/code/code.go b/pkg/protocols/code/code.go
index 92d951ba..4455f558 100644
--- a/pkg/protocols/code/code.go
+++ b/pkg/protocols/code/code.go
@@ -41,7 +41,7 @@ const (
 var (
 	// pythonEnvRegexCompiled is the compiled regex for python environment variables
 	pythonEnvRegexCompiled = regexp.MustCompile(pythonEnvRegex)
-	// ErrCodeExecutionDeadline is the error returned when alloted time for script execution exceeds
+	// ErrCodeExecutionDeadline is the error returned when allotted time for script execution exceeds
 	ErrCodeExecutionDeadline = errkit.New("code execution deadline exceeded").SetKind(errkit.ErrKindDeadline).Build()
 )
 
@@ -279,7 +279,7 @@ func (request *Request) ExecuteWithResults(input *contextargs.Context, dynamicVa
 			fmt.Fprintf(sb, "\n%v\n%v\n%v\n", dashes, "Command Output:", dashes)
 			sb.WriteString(gOutput.DebugData.String())
 			sb.WriteString("\n")
-			sb.WriteString("[WRN] Command Output here is stdout+sterr, in response variables they are seperate (use -v -svd flags for more details)")
+			sb.WriteString("[WRN] Command Output here is stdout+sterr, in response variables they are separate (use -v -svd flags for more details)")
 			return sb.String()
 		})
 	}
diff --git a/pkg/protocols/common/expressions/expressions.go b/pkg/protocols/common/expressions/expressions.go
index bd04cabf..30a73339 100644
--- a/pkg/protocols/common/expressions/expressions.go
+++ b/pkg/protocols/common/expressions/expressions.go
@@ -4,6 +4,7 @@ import (
 	"strings"
 
 	"github.com/Knetic/govaluate"
+	"github.com/projectdiscovery/gologger"
 
 	"github.com/projectdiscovery/nuclei/v3/pkg/operators/common/dsl"
 	"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/marker"
@@ -56,10 +57,12 @@ func evaluate(data string, base map[string]interface{}) (string, error) {
 		// turns expressions (either helper functions+base values or base values)
 		compiled, err := govaluate.NewEvaluableExpressionWithFunctions(expression, dsl.HelperFunctions)
 		if err != nil {
+			gologger.Warning().Msgf("Failed to compile expression '%s': %v", expression, err)
 			continue
 		}
 		result, err := compiled.Evaluate(base)
 		if err != nil {
+			gologger.Warning().Msgf("Failed to evaluate expression '%s': %v", expression, err)
 			continue
 		}
 		// replace incrementally
diff --git a/pkg/protocols/common/generators/generators.go b/pkg/protocols/common/generators/generators.go
index fbb7f155..6bda3134 100644
--- a/pkg/protocols/common/generators/generators.go
+++ b/pkg/protocols/common/generators/generators.go
@@ -75,7 +75,7 @@ type aggressionLevelToPayloads struct {
 
 // parsePayloadsWithAggression parses the payloads with the aggression level
 //
-// Three agression are supported -
+// Three aggression are supported -
 //   - low
 //   - medium
 //   - high
@@ -83,7 +83,7 @@ type aggressionLevelToPayloads struct {
 // low is the default level. If medium is specified, all templates from
 // low and medium are executed. Similarly with high, including all templates
 // from low, medium, high.
-func parsePayloadsWithAggression(name string, v map[interface{}]interface{}, agression string) (map[string]interface{}, error) {
+func parsePayloadsWithAggression(name string, v map[interface{}]interface{}, aggression string) (map[string]interface{}, error) {
 	payloadsLevels := &aggressionLevelToPayloads{}
 
 	for k, v := range v {
@@ -107,7 +107,7 @@ func parsePayloadsWithAggression(name string, v map[interface{}]interface{}, agr
 	}
 
 	payloads := make(map[string]interface{})
-	switch agression {
+	switch aggression {
 	case "low":
 		payloads[name] = payloadsLevels.Low
 	case "medium":
@@ -116,7 +116,7 @@ func parsePayloadsWithAggression(name string, v map[interface{}]interface{}, agr
 		payloads[name] = append(payloadsLevels.Low, payloadsLevels.Medium...)
 		payloads[name] = append(payloads[name].([]interface{}), payloadsLevels.High...)
 	default:
-		return nil, errors.Errorf("invalid aggression level %s specified for %s", agression, name)
+		return nil, errors.Errorf("invalid aggression level %s specified for %s", aggression, name)
 	}
 	return payloads, nil
 }
diff --git a/pkg/protocols/headless/engine/page_actions.go b/pkg/protocols/headless/engine/page_actions.go
index 47548046..a3126569 100644
--- a/pkg/protocols/headless/engine/page_actions.go
+++ b/pkg/protocols/headless/engine/page_actions.go
@@ -33,8 +33,8 @@ import (
 var (
 	errinvalidArguments = errkit.New("invalid arguments provided")
 	ErrLFAccessDenied   = errkit.New("Use -allow-local-file-access flag to enable local file access")
-	// ErrActionExecDealine is the error returned when alloted time for action execution exceeds
-	ErrActionExecDealine = errkit.New("headless action execution deadline exceeded").SetKind(errkit.ErrKindDeadline).Build()
+	// ErrActionExecDeadline is the error returned when allotted time for action execution exceeds
+	ErrActionExecDeadline = errkit.New("headless action execution deadline exceeded").SetKind(errkit.ErrKindDeadline).Build()
 )
 
 const (
@@ -824,7 +824,7 @@ func (p *Page) WaitEvent(act *Action, out ActionData) (func() error, error) {
 	// Just wait the event to happen
 	waitFunc := func() (err error) {
 		// execute actual wait event
-		ctx, cancel := context.WithTimeoutCause(context.Background(), maxDuration, ErrActionExecDealine)
+		ctx, cancel := context.WithTimeoutCause(context.Background(), maxDuration, ErrActionExecDeadline)
 		defer cancel()
 
 		err = contextutil.ExecFunc(ctx, p.page.WaitEvent(waitEvent))
diff --git a/pkg/protocols/http/build_request.go b/pkg/protocols/http/build_request.go
index 980573c9..567e73ca 100644
--- a/pkg/protocols/http/build_request.go
+++ b/pkg/protocols/http/build_request.go
@@ -210,7 +210,7 @@ func (r *requestGenerator) Make(ctx context.Context, input *contextargs.Context,
 	// optionvars are vars passed from CLI or env variables
 	optionVars := generators.BuildPayloadFromOptions(r.request.options.Options)
 
-	variablesMap, interactURLs := r.options.Variables.EvaluateWithInteractsh(generators.MergeMaps(defaultReqVars, optionVars), r.options.Interactsh)
+	variablesMap, interactURLs := r.options.Variables.EvaluateWithInteractsh(generators.MergeMaps(defaultReqVars, optionVars, dynamicValues), r.options.Interactsh)
 	if len(interactURLs) > 0 {
 		r.interactshURLs = append(r.interactshURLs, interactURLs...)
 	}
diff --git a/pkg/protocols/http/request.go b/pkg/protocols/http/request.go
index 37c78eac..9698b4ad 100644
--- a/pkg/protocols/http/request.go
+++ b/pkg/protocols/http/request.go
@@ -59,9 +59,9 @@ const (
 
 var (
 	MaxBodyRead = 10 * unitutils.Mega
-	// ErrMissingVars is error occured when variables are missing
+	// ErrMissingVars is error occurred when variables are missing
 	ErrMissingVars = errkit.New("stop execution due to unresolved variables").SetKind(nucleierr.ErrTemplateLogic).Build()
-	// ErrHttpEngineRequestDeadline is error occured when request deadline set by http request engine is exceeded
+	// ErrHttpEngineRequestDeadline is error occurred when request deadline set by http request engine is exceeded
 	ErrHttpEngineRequestDeadline = errkit.New("http request engine deadline exceeded").SetKind(errkit.ErrKindDeadline).Build()
 )
 
@@ -150,7 +150,7 @@ func (request *Request) executeRaceRequest(input *contextargs.Context, previous
 
 	// look for unresponsive hosts and cancel inflight requests as well
 	spmHandler.SetOnResultCallback(func(err error) {
-		// marks thsi host as unresponsive if applicable
+		// marks this host as unresponsive if applicable
 		request.markHostError(input, err)
 		if request.isUnresponsiveAddress(input) {
 			// stop all inflight requests
@@ -203,7 +203,7 @@ func (request *Request) executeParallelHTTP(input *contextargs.Context, dynamicV
 	}
 
 	// Stop-at-first-match logic while executing requests
-	// parallely using threads
+	// parallelly using threads
 	shouldStop := (request.options.Options.StopAtFirstMatch || request.StopAtFirstMatch || request.options.StopAtFirstMatch)
 
 	ctx, cancel := context.WithCancel(context.Background())
@@ -232,7 +232,7 @@ func (request *Request) executeParallelHTTP(input *contextargs.Context, dynamicV
 
 	// look for unresponsive hosts and cancel inflight requests as well
 	spmHandler.SetOnResultCallback(func(err error) {
-		// marks thsi host as unresponsive if applicable
+		// marks this host as unresponsive if applicable
 		request.markHostError(input, err)
 		if request.isUnresponsiveAddress(input) {
 			// stop all inflight requests
@@ -390,7 +390,7 @@ func (request *Request) executeTurboHTTP(input *contextargs.Context, dynamicValu
 	maxWorkers := max(pipeOptions.MaxPendingRequests, defaultMaxWorkers)
 
 	// Stop-at-first-match logic while executing requests
-	// parallely using threads
+	// parallelly using threads
 	shouldStop := (request.options.Options.StopAtFirstMatch || request.StopAtFirstMatch || request.options.StopAtFirstMatch)
 
 	ctx, cancel := context.WithCancel(context.Background())
@@ -419,7 +419,7 @@ func (request *Request) executeTurboHTTP(input *contextargs.Context, dynamicValu
 
 	// look for unresponsive hosts and cancel inflight requests as well
 	spmHandler.SetOnResultCallback(func(err error) {
-		// marks thsi host as unresponsive if applicable
+		// marks this host as unresponsive if applicable
 		request.markHostError(input, err)
 		if request.isUnresponsiveAddress(input) {
 			// stop all inflight requests
@@ -953,7 +953,7 @@ func (request *Request) executeRequest(input *contextargs.Context, generatedRequ
 		}
 	})
 
-	// evaluate responses continiously until first redirect request in reverse order
+	// evaluate responses continuously until first redirect request in reverse order
 	for respChain.Has() {
 		// fill buffers, read response body and reuse connection
 		if err := respChain.Fill(); err != nil {
diff --git a/pkg/protocols/http/request_annotations.go b/pkg/protocols/http/request_annotations.go
index 1d01f8c9..217e21a3 100644
--- a/pkg/protocols/http/request_annotations.go
+++ b/pkg/protocols/http/request_annotations.go
@@ -31,12 +31,12 @@ var (
 	reOnceAnnotation = regexp.MustCompile(`(?m)^@once\s*$`)
 
 	// ErrTimeoutAnnotationDeadline is the error returned when a specific amount of time was exceeded for a request
-	// which was alloted using @timeout annotation this usually means that vulnerability was not found
+	// which was allotted using @timeout annotation this usually means that vulnerability was not found
 	// in rare case it could also happen due to network congestion
 	// the assigned class is TemplateLogic since this in almost every case means that server is not vulnerable
 	ErrTimeoutAnnotationDeadline = errkit.New("timeout annotation deadline exceeded").SetKind(nucleierr.ErrTemplateLogic).Build()
 	// ErrRequestTimeoutDeadline is the error returned when a specific amount of time was exceeded for a request
-	// this happens when the request execution exceeds alloted time
+	// this happens when the request execution exceeds allotted time
 	ErrRequestTimeoutDeadline = errkit.New("request timeout deadline exceeded when notimeout is set").SetKind(errkit.ErrKindDeadline).Build()
 )
 
diff --git a/pkg/protocols/network/network.go b/pkg/protocols/network/network.go
index 4a5088f6..16af0362 100644
--- a/pkg/protocols/network/network.go
+++ b/pkg/protocols/network/network.go
@@ -59,7 +59,7 @@ type Request struct {
 	//   Inputs contains inputs for the network socket
 	Inputs []*Input `yaml:"inputs,omitempty" json:"inputs,omitempty" jsonschema:"title=inputs for the network request,description=Inputs contains any input/output for the current request"`
 	// description: |
-	//   Port is the port to send network requests to. this acts as default port but is overriden if target/input contains
+	//   Port is the port to send network requests to. this acts as default port but is overridden if target/input contains
 	// non-http(s) ports like 80,8080,8081 etc
 	Port string `yaml:"port,omitempty" json:"port,omitempty" jsonschema:"title=port to send requests to,description=Port to send network requests to,oneof_type=string;integer"`
 
diff --git a/pkg/protocols/protocols.go b/pkg/protocols/protocols.go
index c3ee5c19..69a8b7be 100644
--- a/pkg/protocols/protocols.go
+++ b/pkg/protocols/protocols.go
@@ -336,7 +336,7 @@ type Request interface {
 type OutputEventCallback func(result *output.InternalWrappedEvent)
 
 func MakeDefaultResultEvent(request Request, wrapped *output.InternalWrappedEvent) []*output.ResultEvent {
-	// Note: operator result is generated if something was succesfull match/extract/dynamic-extract
+	// Note: operator result is generated if something was successful match/extract/dynamic-extract
 	// but results should not be generated if
 	// 1. no match was found and some dynamic values were extracted
 	// 2. if something was extracted (matchers exist but no match was found)
diff --git a/pkg/reporting/trackers/linear/jsonutil/jsonutil.go b/pkg/reporting/trackers/linear/jsonutil/jsonutil.go
index d3b8ca5f..1bb87eaa 100644
--- a/pkg/reporting/trackers/linear/jsonutil/jsonutil.go
+++ b/pkg/reporting/trackers/linear/jsonutil/jsonutil.go
@@ -41,7 +41,7 @@ func UnmarshalGraphQL(data []byte, v any) error {
 	}
 }
 
-// decoder is a JSON decoder that performs custom unmarshaling behavior
+// decoder is a JSON decoder that performs custom unmarshalling behavior
 // for GraphQL query data structures. It's implemented on top of a JSON tokenizer.
 type decoder struct {
 	tokenizer interface {
@@ -54,7 +54,7 @@ type decoder struct {
 	// Stacks of values where to unmarshal.
 	// The top of each stack is the reflect.Value where to unmarshal next JSON value.
 	//
-	// The reason there's more than one stack is because we might be unmarshaling
+	// The reason there's more than one stack is because we might be unmarshalling
 	// a single JSON value into multiple GraphQL fragments or embedded structs, so
 	// we keep track of them all.
 	vs [][]reflect.Value
diff --git a/pkg/scan/scan_context.go b/pkg/scan/scan_context.go
index 51b98007..70ac8770 100644
--- a/pkg/scan/scan_context.go
+++ b/pkg/scan/scan_context.go
@@ -65,7 +65,7 @@ func (s *ScanContext) GenerateResult() []*output.ResultEvent {
 	return s.results
 }
 
-// LogEvent logs events to all events and triggeres any callbacks
+// LogEvent logs events to all events and triggers any callbacks
 func (s *ScanContext) LogEvent(e *output.InternalWrappedEvent) {
 	s.m.Lock()
 	defer s.m.Unlock()
@@ -88,7 +88,7 @@ func (s *ScanContext) LogEvent(e *output.InternalWrappedEvent) {
 	s.results = append(s.results, e.Results...)
 }
 
-// LogError logs error to all events and triggeres any callbacks
+// LogError logs error to all events and triggers any callbacks
 func (s *ScanContext) LogError(err error) {
 	s.m.Lock()
 	defer s.m.Unlock()
diff --git a/pkg/templates/compile.go b/pkg/templates/compile.go
index a9730043..22e988c6 100644
--- a/pkg/templates/compile.go
+++ b/pkg/templates/compile.go
@@ -32,7 +32,7 @@ import (
 var (
 	ErrCreateTemplateExecutor          = errors.New("cannot create template executer")
 	ErrIncompatibleWithOfflineMatching = errors.New("template can't be used for offline matching")
-	// track how many templates are verfied and by which signer
+	// track how many templates are verified and by which signer
 	SignatureStats = map[string]*atomic.Uint64{}
 )
 
@@ -47,13 +47,138 @@ func init() {
 	SignatureStats[Unsigned] = &atomic.Uint64{}
 }
 
+// updateRequestOptions updates options for all request types in a template
+func updateRequestOptions(template *Template) {
+	for i, r := range template.RequestsDNS {
+		rCopy := *r
+		rCopy.UpdateOptions(template.Options)
+		template.RequestsDNS[i] = &rCopy
+	}
+	for i, r := range template.RequestsHTTP {
+		rCopy := *r
+		rCopy.UpdateOptions(template.Options)
+		template.RequestsHTTP[i] = &rCopy
+	}
+	for i, r := range template.RequestsCode {
+		rCopy := *r
+		rCopy.UpdateOptions(template.Options)
+		template.RequestsCode[i] = &rCopy
+	}
+	for i, r := range template.RequestsFile {
+		rCopy := *r
+		rCopy.UpdateOptions(template.Options)
+		template.RequestsFile[i] = &rCopy
+	}
+	for i, r := range template.RequestsHeadless {
+		rCopy := *r
+		rCopy.UpdateOptions(template.Options)
+		template.RequestsHeadless[i] = &rCopy
+	}
+	for i, r := range template.RequestsNetwork {
+		rCopy := *r
+		rCopy.UpdateOptions(template.Options)
+		template.RequestsNetwork[i] = &rCopy
+	}
+	for i, r := range template.RequestsJavascript {
+		rCopy := *r
+		rCopy.UpdateOptions(template.Options)
+		template.RequestsJavascript[i] = &rCopy
+	}
+	for i, r := range template.RequestsSSL {
+		rCopy := *r
+		rCopy.UpdateOptions(template.Options)
+		template.RequestsSSL[i] = &rCopy
+	}
+	for i, r := range template.RequestsWHOIS {
+		rCopy := *r
+		rCopy.UpdateOptions(template.Options)
+		template.RequestsWHOIS[i] = &rCopy
+	}
+	for i, r := range template.RequestsWebsocket {
+		rCopy := *r
+		rCopy.UpdateOptions(template.Options)
+		template.RequestsWebsocket[i] = &rCopy
+	}
+}
+
+// parseFromSource parses a template from source with caching support
+func parseFromSource(filePath string, preprocessor Preprocessor, options *protocols.ExecutorOptions, parser *Parser) (*Template, error) {
+	var reader io.ReadCloser
+	if !options.DoNotCache {
+		_, raw, err := parser.parsedTemplatesCache.Has(filePath)
+		if err == nil && raw != nil {
+			reader = io.NopCloser(bytes.NewReader(raw))
+		}
+	}
+
+	var err error
+	if reader == nil {
+		reader, err = utils.ReaderFromPathOrURL(filePath, options.Catalog)
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	defer func() {
+		_ = reader.Close()
+	}()
+
+	options = options.Copy()
+	options.TemplatePath = filePath
+
+	template, err := ParseTemplateFromReader(reader, preprocessor, options)
+	if err != nil {
+		return nil, err
+	}
+
+	if template.isGlobalMatchersEnabled() {
+		item := &globalmatchers.Item{
+			TemplateID:   template.ID,
+			TemplatePath: filePath,
+			TemplateInfo: template.Info,
+		}
+
+		for _, request := range template.RequestsHTTP {
+			item.Operators = append(item.Operators, request.CompiledOperators)
+		}
+
+		options.GlobalMatchers.AddOperator(item)
+
+		return nil, nil
+	}
+
+	// Compile the workflow request
+	if len(template.Workflows) > 0 {
+		compiled := &template.Workflow
+
+		compileWorkflow(filePath, preprocessor, options, compiled, options.WorkflowLoader)
+		template.CompiledWorkflow = compiled
+		template.CompiledWorkflow.Options = options
+	}
+
+	template.Path = filePath
+	if !options.DoNotCache {
+		parser.compiledTemplatesCache.Store(filePath, template, nil, err)
+	}
+
+	return template, nil
+}
+
+// getParser returns a cached parser instance
+func getParser(options *protocols.ExecutorOptions) *Parser {
+	parser, ok := options.Parser.(*Parser)
+	if !ok || parser == nil {
+		panic("invalid parser")
+	}
+
+	return parser
+}
+
 // Parse parses a yaml request template file
 // TODO make sure reading from the disk the template parsing happens once: see parsers.ParseTemplate vs templates.Parse
 func Parse(filePath string, preprocessor Preprocessor, options *protocols.ExecutorOptions) (*Template, error) {
-	parser, ok := options.Parser.(*Parser)
-	if !ok {
-		panic("not a parser")
-	}
+	parser := getParser(options)
+
 	if !options.DoNotCache {
 		if value, _, _ := parser.compiledTemplatesCache.Has(filePath); value != nil {
 			// Copy the template, apply new options, and recompile requests
@@ -68,12 +193,14 @@ func Parse(filePath string, preprocessor Preprocessor, options *protocols.Execut
 			if tplCopy.Options.Variables.Len() > 0 {
 				newBase.Variables = tplCopy.Options.Variables
 			}
+
 			if len(tplCopy.Options.Constants) > 0 {
 				newBase.Constants = tplCopy.Options.Constants
 			}
-			tplCopy.Options = newBase
 
+			tplCopy.Options = newBase
 			tplCopy.Options.ApplyNewEngineOptions(options)
+
 			if tplCopy.CompiledWorkflow != nil {
 				tplCopy.CompiledWorkflow.Options.ApplyNewEngineOptions(options)
 				for _, w := range tplCopy.CompiledWorkflow.Workflows {
@@ -83,69 +210,8 @@ func Parse(filePath string, preprocessor Preprocessor, options *protocols.Execut
 				}
 			}
 
-			// TODO: Reconsider whether to recompile requests. Compiling these is just as slow
-			// as not using a cache at all, but may be necessary.
-
-			for i, r := range tplCopy.RequestsDNS {
-				rCopy := *r
-				rCopy.UpdateOptions(tplCopy.Options)
-				//	rCopy.Compile(tplCopy.Options)
-				tplCopy.RequestsDNS[i] = &rCopy
-			}
-			for i, r := range tplCopy.RequestsHTTP {
-				rCopy := *r
-				rCopy.UpdateOptions(tplCopy.Options)
-				//	rCopy.Compile(tplCopy.Options)
-				tplCopy.RequestsHTTP[i] = &rCopy
-			}
-			for i, r := range tplCopy.RequestsCode {
-				rCopy := *r
-				rCopy.UpdateOptions(tplCopy.Options)
-				//	rCopy.Compile(tplCopy.Options)
-				tplCopy.RequestsCode[i] = &rCopy
-			}
-			for i, r := range tplCopy.RequestsFile {
-				rCopy := *r
-				rCopy.UpdateOptions(tplCopy.Options)
-				//	rCopy.Compile(tplCopy.Options)
-				tplCopy.RequestsFile[i] = &rCopy
-			}
-			for i, r := range tplCopy.RequestsHeadless {
-				rCopy := *r
-				rCopy.UpdateOptions(tplCopy.Options)
-				//	rCopy.Compile(tplCopy.Options)
-				tplCopy.RequestsHeadless[i] = &rCopy
-			}
-			for i, r := range tplCopy.RequestsNetwork {
-				rCopy := *r
-				rCopy.UpdateOptions(tplCopy.Options)
-				//	rCopy.Compile(tplCopy.Options)
-				tplCopy.RequestsNetwork[i] = &rCopy
-			}
-			for i, r := range tplCopy.RequestsJavascript {
-				rCopy := *r
-				rCopy.UpdateOptions(tplCopy.Options)
-				//rCopy.Compile(tplCopy.Options)
-				tplCopy.RequestsJavascript[i] = &rCopy
-			}
-			for i, r := range tplCopy.RequestsSSL {
-				rCopy := *r
-				rCopy.UpdateOptions(tplCopy.Options)
-				// rCopy.Compile(tplCopy.Options)
-				tplCopy.RequestsSSL[i] = &rCopy
-			}
-			for i, r := range tplCopy.RequestsWHOIS {
-				rCopy := *r
-				rCopy.UpdateOptions(tplCopy.Options)
-				// rCopy.Compile(tplCopy.Options)
-				tplCopy.RequestsWHOIS[i] = &rCopy
-			}
-			for i, r := range tplCopy.RequestsWebsocket {
-				rCopy := *r
-				rCopy.UpdateOptions(tplCopy.Options)
-				// rCopy.Compile(tplCopy.Options)
-				tplCopy.RequestsWebsocket[i] = &rCopy
-			}
+			// Update options for all request types
+			updateRequestOptions(&tplCopy)
 			template := &tplCopy
 
 			if template.isGlobalMatchersEnabled() {
@@ -154,12 +220,16 @@ func Parse(filePath string, preprocessor Preprocessor, options *protocols.Execut
 					TemplatePath: filePath,
 					TemplateInfo: template.Info,
 				}
+
 				for _, request := range template.RequestsHTTP {
 					item.Operators = append(item.Operators, request.CompiledOperators)
 				}
+
 				options.GlobalMatchers.AddOperator(item)
+
 				return nil, nil
 			}
+
 			// Compile the workflow request
 			if len(template.Workflows) > 0 {
 				compiled := &template.Workflow
@@ -172,61 +242,12 @@ func Parse(filePath string, preprocessor Preprocessor, options *protocols.Execut
 				// options.Logger.Error().Msgf("returning cached template %s after recompiling %d requests", tplCopy.Options.TemplateID, tplCopy.Requests())
 				return template, nil
 			}
-			// else: fallthrough to re-parse template from scratch
-		}
-	}
 
-	var reader io.ReadCloser
-	if !options.DoNotCache {
-		_, raw, err := parser.parsedTemplatesCache.Has(filePath)
-		if err == nil && raw != nil {
-			reader = io.NopCloser(bytes.NewReader(raw))
-		}
-	}
-	var err error
-	if reader == nil {
-		reader, err = utils.ReaderFromPathOrURL(filePath, options.Catalog)
-		if err != nil {
-			return nil, err
-		}
-	}
-
-	defer func() {
-		_ = reader.Close()
-	}()
-
-	// Make a copy of the options for this template
-	options = options.Copy()
-	options.TemplatePath = filePath
-	template, err := ParseTemplateFromReader(reader, preprocessor, options)
-	if err != nil {
-		return nil, err
-	}
-	if template.isGlobalMatchersEnabled() {
-		item := &globalmatchers.Item{
-			TemplateID:   template.ID,
-			TemplatePath: filePath,
-			TemplateInfo: template.Info,
-		}
-		for _, request := range template.RequestsHTTP {
-			item.Operators = append(item.Operators, request.CompiledOperators)
+			// else: fallthrough to re-parse template from scratch
 		}
-		options.GlobalMatchers.AddOperator(item)
-		return nil, nil
 	}
-	// Compile the workflow request
-	if len(template.Workflows) > 0 {
-		compiled := &template.Workflow
 
-		compileWorkflow(filePath, preprocessor, options, compiled, options.WorkflowLoader)
-		template.CompiledWorkflow = compiled
-		template.CompiledWorkflow.Options = options
-	}
-	template.Path = filePath
-	if !options.DoNotCache {
-		parser.compiledTemplatesCache.Store(filePath, template, nil, err)
-	}
-	return template, nil
+	return parseFromSource(filePath, preprocessor, options, parser)
 }
 
 // isGlobalMatchersEnabled checks if any of requests in the template
diff --git a/pkg/templates/template_sign.go b/pkg/templates/template_sign.go
index 9e46769f..4cd94f9f 100644
--- a/pkg/templates/template_sign.go
+++ b/pkg/templates/template_sign.go
@@ -40,7 +40,7 @@ func UseOptionsForSigner(opts *types.Options) {
 // New Signer/Verification logic requires it to load content of file references
 // and this is done respecting sandbox restrictions to avoid any security issues
 // AllowLocalFileAccess is a function that allows local file access by disabling sandbox restrictions
-// and **MUST** be called before signing / verifying any templates for intialization
+// and **MUST** be called before signing / verifying any templates for initialization
 func TemplateSignerLFA() {
 	defaultOpts.AllowLocalFileAccess = true
 }
diff --git a/pkg/templates/templates_doc.go b/pkg/templates/templates_doc.go
index c6b2186e..44787237 100644
--- a/pkg/templates/templates_doc.go
+++ b/pkg/templates/templates_doc.go
@@ -1402,7 +1402,7 @@ func init() {
 	NETWORKRequestDoc.Fields[6].Name = "port"
 	NETWORKRequestDoc.Fields[6].Type = "string"
 	NETWORKRequestDoc.Fields[6].Note = ""
-	NETWORKRequestDoc.Fields[6].Description = "description: |\n   Port is the port to send network requests to. this acts as default port but is overriden if target/input contains\n non-http(s) ports like 80,8080,8081 etc"
+	NETWORKRequestDoc.Fields[6].Description = "description: |\n   Port is the port to send network requests to. this acts as default port but is overridden if target/input contains\n non-http(s) ports like 80,8080,8081 etc"
 	NETWORKRequestDoc.Fields[6].Comments[encoder.LineComment] = " description: |"
 	NETWORKRequestDoc.Fields[7].Name = "exclude-ports"
 	NETWORKRequestDoc.Fields[7].Type = "string"
@@ -2107,8 +2107,8 @@ func init() {
 	JAVASCRIPTRequestDoc.Fields[7].Name = "threads"
 	JAVASCRIPTRequestDoc.Fields[7].Type = "int"
 	JAVASCRIPTRequestDoc.Fields[7].Note = ""
-	JAVASCRIPTRequestDoc.Fields[7].Description = "Payload concurreny i.e threads for sending requests."
-	JAVASCRIPTRequestDoc.Fields[7].Comments[encoder.LineComment] = "Payload concurreny i.e threads for sending requests."
+	JAVASCRIPTRequestDoc.Fields[7].Description = "Payload concurrency i.e threads for sending requests."
+	JAVASCRIPTRequestDoc.Fields[7].Comments[encoder.LineComment] = "Payload concurrency i.e threads for sending requests."
 
 	JAVASCRIPTRequestDoc.Fields[7].AddExample("Send requests using 10 concurrent threads", 10)
 	JAVASCRIPTRequestDoc.Fields[8].Name = "payloads"
diff --git a/pkg/templates/workflows.go b/pkg/templates/workflows.go
index 50029af1..ea07f7e1 100644
--- a/pkg/templates/workflows.go
+++ b/pkg/templates/workflows.go
@@ -94,10 +94,17 @@ func parseWorkflowTemplate(workflow *workflows.WorkflowTemplate, preprocessor Pr
 
 		if len(template.RequestsCode) > 0 {
 			if !options.Options.EnableCodeTemplates {
-				gologger.Warning().Msgf("`-code` flag not found, skipping code template from workflow: %v\n", path)
+				// NOTE(dwisiswant0): It is safe to continue here during
+				// validation mode, because the template has already been parsed
+				// and syntax-validated by templates.Parse() above. It only
+				// prevents adding to workflow's executer list and suppresses
+				// warning messages.
+				if !options.Options.Validate {
+					gologger.Warning().Msgf("`-code` flag not found, skipping code template from workflow: %v\n", path)
+				}
 				continue
 			} else if !template.Verified {
-				// unverfied code templates are not allowed in workflows
+				// unverified code templates are not allowed in workflows
 				gologger.Warning().Msgf("skipping unverified code template from workflow: %v\n", path)
 				continue
 			}
diff --git a/pkg/tmplexec/README.md b/pkg/tmplexec/README.md
index 26e80daf..10c1b5b0 100644
--- a/pkg/tmplexec/README.md
+++ b/pkg/tmplexec/README.md
@@ -1,6 +1,6 @@
 # tmplexec
 
-tmplexec also known as template executer executes template it is different from `protocols` package which only contains logic within the scope of one protocol. tmplexec is resposible for executing `Template` with defined logic. with introduction of `multi protocol` and `flow` templates (deprecated package protocols/common/executer) did not seem appropriate/helpful anymore as it is outside of protocol scope and deals with execution of template which can contain 1 requests , or multiple requests of same protocol or multiple requests of different protocols. tmplexec is responsible for executing template and handling all logic related to it.
+tmplexec also known as template executer executes template it is different from `protocols` package which only contains logic within the scope of one protocol. tmplexec is responsible for executing `Template` with defined logic. with introduction of `multi protocol` and `flow` templates (deprecated package protocols/common/executer) did not seem appropriate/helpful anymore as it is outside of protocol scope and deals with execution of template which can contain 1 requests , or multiple requests of same protocol or multiple requests of different protocols. tmplexec is responsible for executing template and handling all logic related to it.
 
 ## Engine/Backends
 
diff --git a/pkg/tmplexec/flow/README.md b/pkg/tmplexec/flow/README.md
index 0b4fc498..f208f742 100644
--- a/pkg/tmplexec/flow/README.md
+++ b/pkg/tmplexec/flow/README.md
@@ -114,7 +114,7 @@ To better understand orchestration we can try to build a template for vhost enum
 
 **for basic vhost enumeration a template should** 
 - do a PTR lookup for given ip
-- get SSL ceritificate for given ip (i.e tls-grab)
+- get SSL certificate for given ip (i.e tls-grab)
   - extract subject_cn from certificate
   - extract subject_alt_names(SAN) from certificate
   - filter out wildcard prefix from above values
@@ -316,4 +316,4 @@ This section contains a brief description of all nuclei JS bindings and their us
   And that's it , this automatically converts any slice/array to map and removes duplicates from it and returns a slice/array of unique values
 
 ------
-> Similar to DSL helper functions . we can either use built in functions available with `Javscript (ECMAScript 5.1)` or use DSL helper functions and its upto user to decide which one to uses
\ No newline at end of file
+> Similar to DSL helper functions . we can either use built in functions available with `Javascript (ECMAScript 5.1)` or use DSL helper functions and its upto user to decide which one to uses
\ No newline at end of file
diff --git a/pkg/tmplexec/multiproto/multi.go b/pkg/tmplexec/multiproto/multi.go
index ef029861..62cf79c8 100644
--- a/pkg/tmplexec/multiproto/multi.go
+++ b/pkg/tmplexec/multiproto/multi.go
@@ -66,7 +66,7 @@ func (m *MultiProtocol) ExecuteWithResults(ctx *scan.ScanContext) error {
 
 	// template context: contains values extracted using `internal` extractor from previous protocols
 	// these values are extracted from each protocol in queue and are passed to next protocol in queue
-	// instead of adding seperator field to handle such cases these values are appended to `dynamicValues` (which are meant to be used in workflows)
+	// instead of adding separator field to handle such cases these values are appended to `dynamicValues` (which are meant to be used in workflows)
 	// this makes it possible to use multi protocol templates in workflows
 	// Note: internal extractor values take precedence over dynamicValues from workflows (i.e other templates in workflow)
 
diff --git a/pkg/types/nucleierr/kinds.go b/pkg/types/nucleierr/kinds.go
index 9042beaa..1594d8f8 100644
--- a/pkg/types/nucleierr/kinds.go
+++ b/pkg/types/nucleierr/kinds.go
@@ -7,7 +7,7 @@ import (
 )
 
 var (
-	// ErrTemplateLogic are errors that occured due to missing variable or something similar in template logic
+	// ErrTemplateLogic are errors that occurred due to missing variable or something similar in template logic
 	// so this is more of a virtual error that is expected due to template logic
 	ErrTemplateLogic = errkit.NewPrimitiveErrKind("TemplateLogic", "Error expected due to template logic", isTemplateLogicKind)
 )
diff --git a/pkg/types/types.go b/pkg/types/types.go
index 26e98ba6..08ed924f 100644
--- a/pkg/types/types.go
+++ b/pkg/types/types.go
@@ -20,6 +20,8 @@ import (
 	unitutils "github.com/projectdiscovery/utils/unit"
 )
 
+const DefaultTemplateLoadingConcurrency = 50
+
 var (
 	// ErrNoMoreRequests is internal error to indicate that generator has no more requests to generate
 	ErrNoMoreRequests = io.EOF
@@ -429,6 +431,8 @@ type Options struct {
 	PayloadConcurrency int
 	// ProbeConcurrency is the number of concurrent http probes to run with httpx
 	ProbeConcurrency int
+	// TemplateLoadingConcurrency is the number of concurrent template loading operations
+	TemplateLoadingConcurrency int
 	// Dast only runs DAST templates
 	DAST bool
 	// DASTServer is the flag to start nuclei as a DAST server
@@ -775,19 +779,20 @@ func (options *Options) HasClientCertificates() bool {
 // DefaultOptions returns default options for nuclei
 func DefaultOptions() *Options {
 	return &Options{
-		RateLimit:               150,
-		RateLimitDuration:       time.Second,
-		BulkSize:                25,
-		TemplateThreads:         25,
-		HeadlessBulkSize:        10,
-		PayloadConcurrency:      25,
-		HeadlessTemplateThreads: 10,
-		ProbeConcurrency:        50,
-		Timeout:                 5,
-		Retries:                 1,
-		MaxHostError:            30,
-		ResponseReadSize:        10 * unitutils.Mega,
-		ResponseSaveSize:        unitutils.Mega,
+		RateLimit:                  150,
+		RateLimitDuration:          time.Second,
+		BulkSize:                   25,
+		TemplateThreads:            25,
+		HeadlessBulkSize:           10,
+		PayloadConcurrency:         25,
+		HeadlessTemplateThreads:    10,
+		ProbeConcurrency:           50,
+		TemplateLoadingConcurrency: DefaultTemplateLoadingConcurrency,
+		Timeout:                    5,
+		Retries:                    1,
+		MaxHostError:               30,
+		ResponseReadSize:           10 * unitutils.Mega,
+		ResponseSaveSize:           unitutils.Mega,
 	}
 }
 
diff --git a/pkg/utils/http_probe.go b/pkg/utils/http_probe.go
index 9e3046fe..3cc7d5d0 100644
--- a/pkg/utils/http_probe.go
+++ b/pkg/utils/http_probe.go
@@ -2,22 +2,46 @@ package utils
 
 import (
 	"fmt"
+	"net"
 	"net/http"
 
 	"github.com/projectdiscovery/httpx/common/httpx"
 	"github.com/projectdiscovery/nuclei/v3/pkg/input/types"
 	"github.com/projectdiscovery/useragent"
+	sliceutil "github.com/projectdiscovery/utils/slice"
 )
 
-var (
-	HttpSchemes = []string{"https", "http"}
-)
+var commonHttpPorts = []string{
+	"80",
+	"8080",
+}
+var defaultHttpSchemes = []string{
+	"https",
+	"http",
+}
+var httpFirstSchemes = []string{
+	"http",
+	"https",
+}
+
+// determineSchemeOrder for the input
+func determineSchemeOrder(input string) []string {
+	// if input has port that is commonly used for HTTP, return http then https
+	if _, port, err := net.SplitHostPort(input); err == nil {
+		if sliceutil.Contains(commonHttpPorts, port) {
+			return httpFirstSchemes
+		}
+	}
+
+	return defaultHttpSchemes
+}
 
-// ProbeURL probes the scheme for a URL. first HTTPS is tried
-// and if any errors occur http is tried. If none succeeds, probing
-// is abandoned for such URLs.
+// ProbeURL probes the scheme for a URL.
+// http schemes are selected with heuristics
+// If none succeeds, probing is abandoned for such URLs.
 func ProbeURL(input string, httpxclient *httpx.HTTPX) string {
-	for _, scheme := range HttpSchemes {
+	schemes := determineSchemeOrder(input)
+	for _, scheme := range schemes {
 		formedURL := fmt.Sprintf("%s://%s", scheme, input)
 		req, err := httpxclient.NewRequest(http.MethodHead, formedURL)
 		if err != nil {
@@ -39,7 +63,7 @@ type inputLivenessChecker struct {
 	client *httpx.HTTPX
 }
 
-// ProbeURL probes the scheme for a URL. first HTTPS is tried
+// ProbeURL probes the scheme for a URL.
 func (i *inputLivenessChecker) ProbeURL(input string) (string, error) {
 	return ProbeURL(input, i.client), nil
 }
diff --git a/pkg/utils/json/doc.go b/pkg/utils/json/doc.go
index 6cee2e74..56367ebf 100644
--- a/pkg/utils/json/doc.go
+++ b/pkg/utils/json/doc.go
@@ -6,7 +6,7 @@
 // implementation.
 //
 // This package acts as a wrapper around the underlying JSON APIs, offering
-// standard operations such as marshaling, unmarshaling, and working with JSON
+// standard operations such as marshaling, unmarshalling, and working with JSON
 // encoders/decoders. It maintains compatibility with the standard encoding/json
 // interfaces while delivering improved performance when possible.
 //



Test patch:
diff --git a/pkg/catalog/loader/loader_bench_test.go b/pkg/catalog/loader/loader_bench_test.go
new file mode 100644
index 00000000..079e928a
--- /dev/null
+++ b/pkg/catalog/loader/loader_bench_test.go
@@ -0,0 +1,43 @@
+package loader_test
+
+import (
+	"testing"
+
+	"github.com/projectdiscovery/gologger"
+	"github.com/projectdiscovery/nuclei/v3/pkg/catalog/config"
+	"github.com/projectdiscovery/nuclei/v3/pkg/catalog/disk"
+	"github.com/projectdiscovery/nuclei/v3/pkg/catalog/loader"
+	"github.com/projectdiscovery/nuclei/v3/pkg/loader/workflow"
+	"github.com/projectdiscovery/nuclei/v3/pkg/templates"
+	"github.com/projectdiscovery/nuclei/v3/pkg/testutils"
+)
+
+func BenchmarkStoreValidateTemplates(b *testing.B) {
+	options := testutils.DefaultOptions.Copy()
+	options.Logger = &gologger.Logger{}
+	testutils.Init(options)
+
+	catalog := disk.NewCatalog(config.DefaultConfig.TemplatesDirectory)
+	executerOpts := testutils.NewMockExecuterOptions(options, nil)
+	executerOpts.Parser = templates.NewParser()
+
+	workflowLoader, err := workflow.NewLoader(executerOpts)
+	if err != nil {
+		b.Fatalf("could not create workflow loader: %s", err)
+	}
+	executerOpts.WorkflowLoader = workflowLoader
+
+	loaderCfg := loader.NewConfig(options, catalog, executerOpts)
+
+	store, err := loader.New(loaderCfg)
+	if err != nil {
+		b.Fatalf("could not create store: %s", err)
+	}
+
+	b.ResetTimer()
+	b.ReportAllocs()
+
+	for b.Loop() {
+		_ = store.ValidateTemplates()
+	}
+}
diff --git a/pkg/input/formats/testdata/openapi.yaml b/pkg/input/formats/testdata/openapi.yaml
index 93a37df7..ab095f7e 100644
--- a/pkg/input/formats/testdata/openapi.yaml
+++ b/pkg/input/formats/testdata/openapi.yaml
@@ -131,7 +131,7 @@ paths:
         required: true
       responses:
         '200':
-          description: Sucessfully created user
+          description: Successfully created user
           content:
             application/json:
               schema:
@@ -170,7 +170,7 @@ paths:
         required: true
       responses:
         '200':
-          description: Sucessfully logged in user
+          description: Successfully logged in user
           content:
             application/json:
                 schema:
@@ -262,7 +262,7 @@ paths:
             example: 'name1'
       responses:
         '200':
-          description: Sucessfully deleted user
+          description: Successfully deleted user
           content:
             application/json:
               schema:
@@ -331,7 +331,7 @@ paths:
         required: true
       responses:
         '204':
-          description: Sucessfully updated user email
+          description: Successfully updated user email
           content: {}
         '400':
           description: Invalid request
@@ -389,7 +389,7 @@ paths:
         required: true
       responses:
         '204':
-          description: Sucessfully updated users password
+          description: Successfully updated users password
           content: {}
         '400':
           description: Invalid request
@@ -475,7 +475,7 @@ paths:
         required: true
       responses:
         '200':
-          description: Sucessfully added a book
+          description: Successfully added a book
           content:
             application/json:
               schema:
diff --git a/pkg/protocols/headless/engine/page_actions_test.go b/pkg/protocols/headless/engine/page_actions_test.go
index ec16b9ed..88440a2d 100644
--- a/pkg/protocols/headless/engine/page_actions_test.go
+++ b/pkg/protocols/headless/engine/page_actions_test.go
@@ -645,7 +645,7 @@ func testHeadless(t *testing.T, actions []*Action, timeout time.Duration, handle
 	t.Helper()
 
 	lfa := envutil.GetEnvOrDefault("LOCAL_FILE_ACCESS", true)
-	rna := envutil.GetEnvOrDefault("RESTRICED_LOCAL_NETWORK_ACCESS", false)
+	rna := envutil.GetEnvOrDefault("RESTRICTED_LOCAL_NETWORK_ACCESS", false)
 
 	opts := &types.Options{AllowLocalFileAccess: lfa, RestrictLocalNetworkAccess: rna}
 
@@ -736,9 +736,9 @@ func TestBlockedHeadlessURLS(t *testing.T) {
 		"fTP://example.com:21\r\n",
 		"ftp://example.com:21",
 		"chrome://settings",
-		"	chROme://version",
+		"	chRSome://version",
 		"chrome-extension://version\r",
-		"	chrOme-EXTension://settings",
+		"	chrSome-EXTension://settings",
 		"view-source:file:/etc/hosts",
 	}
 
diff --git a/pkg/templates/compile_bench_test.go b/pkg/templates/compile_bench_test.go
new file mode 100644
index 00000000..041dc92d
--- /dev/null
+++ b/pkg/templates/compile_bench_test.go
@@ -0,0 +1,70 @@
+package templates_test
+
+import (
+	"bytes"
+	"io"
+	"os"
+	"testing"
+
+	"github.com/projectdiscovery/nuclei/v3/pkg/templates"
+)
+
+func BenchmarkParse(b *testing.B) {
+	filePath := "tests/match-1.yaml"
+
+	setup()
+	b.ResetTimer()
+	b.ReportAllocs()
+
+	for b.Loop() {
+		_, err := templates.Parse(filePath, nil, executerOpts)
+		if err != nil {
+			b.Fatalf("could not parse template: %s", err)
+		}
+	}
+}
+
+func BenchmarkParseTemplateFromReader(b *testing.B) {
+	filePath := "tests/match-1.yaml"
+
+	file, err := os.Open(filePath)
+	if err != nil {
+		b.Fatalf("could not open template file: %s", err)
+	}
+	defer func() {
+		_ = file.Close()
+	}()
+
+	content, err := io.ReadAll(file)
+	if err != nil {
+		b.Fatalf("could not read template file: %s", err)
+	}
+
+	setup()
+
+	// Prepare the options with template path set.
+	//
+	// TODO(dwisiswant0): ParseTemplateFromReader should ideally work with just
+	// a reader without requiring path information, making it more flexible for
+	// in-memory templates or templates from non-file sources, the function
+	// unnecessarily couples the parsing logic to filepath info when it should
+	// primarily care about the content because it only needs a reader, but it
+	// actually requires path information in the options.
+	//
+	// The current implementation fails with a confusing error about template
+	// format detection, "no template name field provided", rather than
+	// explicitly stating that a path is required.
+	opts := executerOpts.Copy()
+	opts.TemplatePath = filePath
+
+	b.ResetTimer()
+	b.ReportAllocs()
+
+	for b.Loop() {
+		reader := bytes.NewReader(content)
+		_, err := templates.ParseTemplateFromReader(reader, nil, opts)
+		if err != nil {
+			b.Fatalf("could not parse template from reader: %s", err)
+		}
+	}
+}
diff --git a/pkg/testutils/testutils.go b/pkg/testutils/testutils.go
index 521654c4..49b79e64 100644
--- a/pkg/testutils/testutils.go
+++ b/pkg/testutils/testutils.go
@@ -94,9 +94,6 @@ type TemplateInfo struct {
 func NewMockExecuterOptions(options *types.Options, info *TemplateInfo) *protocols.ExecutorOptions {
 	progressImpl, _ := progress.NewStatsTicker(0, false, false, false, 0)
 	executerOpts := &protocols.ExecutorOptions{
-		TemplateID:   info.ID,
-		TemplateInfo: info.Info,
-		TemplatePath: info.Path,
 		Output:       NewMockOutputWriter(options.OmitTemplate),
 		Options:      options,
 		Progress:     progressImpl,
@@ -106,7 +103,15 @@ func NewMockExecuterOptions(options *types.Options, info *TemplateInfo) *protoco
 		Catalog:      disk.NewCatalog(config.DefaultConfig.TemplatesDirectory),
 		RateLimiter:  ratelimit.New(context.Background(), uint(options.RateLimit), time.Second),
 	}
+
+	if info != nil {
+		executerOpts.TemplateInfo = info.Info
+		executerOpts.TemplateID = info.ID
+		executerOpts.TemplatePath = info.Path
+	}
+
 	executerOpts.CreateTemplateCtxStore()
+
 	return executerOpts
 }
 
diff --git a/pkg/utils/http_probe_test.go b/pkg/utils/http_probe_test.go
new file mode 100644
index 00000000..f000a8a8
--- /dev/null
+++ b/pkg/utils/http_probe_test.go
@@ -0,0 +1,37 @@
+package utils
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/require"
+)
+
+func TestDetermineSchemeOrder(t *testing.T) {
+	type testCase struct {
+		input    string
+		expected []string
+	}
+
+	tests := []testCase{
+		// No port or uncommon ports should return https first
+		{"example.com", []string{"https", "http"}},
+		{"example.com:443", []string{"https", "http"}},
+		{"127.0.0.1", []string{"https", "http"}},
+		{"[fe80::1]:443", []string{"https", "http"}},
+		// Common HTTP ports should return http first
+		{"example.com:80", []string{"http", "https"}},
+		{"example.com:8080", []string{"http", "https"}},
+		{"127.0.0.1:80", []string{"http", "https"}},
+		{"127.0.0.1:8080", []string{"http", "https"}},
+		{"fe80::1", []string{"https", "http"}},
+		{"[fe80::1]:80", []string{"http", "https"}},
+		{"[fe80::1]:8080", []string{"http", "https"}},
+	}
+
+	for _, tc := range tests {
+		t.Run(tc.input, func(t *testing.T) {
+			actual := determineSchemeOrder(tc.input)
+			require.Equal(t, tc.expected, actual)
+		})
+	}
+}