mirror of
https://github.com/projectdiscovery/nuclei.git
synced 2026-11-07 17:43:04 -10:00
Compare commits
17
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
53b167064a | ||
|
|
078284936c | ||
|
|
434f6d32fc | ||
|
|
0c510253d2 | ||
|
|
dfcc38adb7 | ||
|
|
3feb011459 | ||
|
|
3951816686 | ||
|
|
84b84b6ade | ||
|
|
9e040516f2 | ||
|
|
5cb038fb33 | ||
|
|
0c7bade615 | ||
|
|
1bafeca614 | ||
|
|
3be2eb7cf2 | ||
|
|
58d874f291 | ||
|
|
9d0886d267 | ||
|
|
5094c0cf17 | ||
|
|
aaf09431ff |
No files matched your search
@@ -24,7 +24,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: projectdiscovery/actions/setup/go@v1
|
||||
- uses: projectdiscovery/actions/golangci-lint/v2@v1
|
||||
- uses: projectdiscovery/actions/golangci-lint@v1
|
||||
|
||||
tests:
|
||||
name: "Tests"
|
||||
|
||||
@@ -146,14 +146,5 @@ dsl-docs:
|
||||
template-validate: build
|
||||
template-validate:
|
||||
./bin/nuclei -ut
|
||||
./bin/nuclei -validate \
|
||||
-et .github/ \
|
||||
-et helpers/payloads/ \
|
||||
-et http/technologies \
|
||||
-ept code
|
||||
./bin/nuclei -validate \
|
||||
-w workflows \
|
||||
-et .github/ \
|
||||
-et helpers/payloads/ \
|
||||
-et http/technologies \
|
||||
-ept code
|
||||
./bin/nuclei -validate -et http/technologies
|
||||
./bin/nuclei -validate -w workflows -et http/technologies
|
||||
@@ -757,3 +757,10 @@ func findProfilePathById(profileId, templatesDir string) string {
|
||||
}
|
||||
return profilePath
|
||||
}
|
||||
|
||||
func init() {
|
||||
// print stacktrace of errors in debug mode
|
||||
if strings.EqualFold(os.Getenv("DEBUG"), "true") {
|
||||
errorutil.ShowStackTrace = true
|
||||
}
|
||||
}
|
||||
@@ -20,12 +20,12 @@ require (
|
||||
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.4
|
||||
github.com/projectdiscovery/hmap v0.0.92
|
||||
github.com/projectdiscovery/fastdialer v0.4.1
|
||||
github.com/projectdiscovery/hmap v0.0.91
|
||||
github.com/projectdiscovery/interactsh v1.2.4
|
||||
github.com/projectdiscovery/rawhttp v0.1.90
|
||||
github.com/projectdiscovery/retryabledns v1.0.105
|
||||
github.com/projectdiscovery/retryablehttp-go v1.0.119
|
||||
github.com/projectdiscovery/retryabledns v1.0.103
|
||||
github.com/projectdiscovery/retryablehttp-go v1.0.117
|
||||
github.com/projectdiscovery/yamldoc-go v1.0.6
|
||||
github.com/remeh/sizedwaitgroup v1.0.0
|
||||
github.com/rs/xid v1.6.0
|
||||
@@ -35,7 +35,7 @@ require (
|
||||
github.com/spf13/cast v1.9.2
|
||||
github.com/syndtr/goleveldb v1.0.0
|
||||
github.com/valyala/fasttemplate v1.2.2
|
||||
github.com/weppos/publicsuffix-go v0.40.3-0.20250408071509-6074bbe7fd39
|
||||
github.com/weppos/publicsuffix-go v0.40.3-0.20250311103038-7794c8c0723b
|
||||
go.uber.org/multierr v1.11.0
|
||||
golang.org/x/net v0.41.0
|
||||
golang.org/x/oauth2 v0.30.0
|
||||
@@ -98,14 +98,14 @@ require (
|
||||
github.com/projectdiscovery/httpx v1.7.0
|
||||
github.com/projectdiscovery/mapcidr v1.1.34
|
||||
github.com/projectdiscovery/n3iwf v0.0.0-20230523120440-b8cd232ff1f5
|
||||
github.com/projectdiscovery/networkpolicy v0.1.18
|
||||
github.com/projectdiscovery/ratelimit v0.0.82-0.20250819165347-d56e782c656d
|
||||
github.com/projectdiscovery/networkpolicy v0.1.17
|
||||
github.com/projectdiscovery/ratelimit v0.0.81
|
||||
github.com/projectdiscovery/rdap v0.9.0
|
||||
github.com/projectdiscovery/sarif v0.0.1
|
||||
github.com/projectdiscovery/tlsx v1.1.9
|
||||
github.com/projectdiscovery/uncover v1.1.0
|
||||
github.com/projectdiscovery/useragent v0.0.101
|
||||
github.com/projectdiscovery/utils v0.4.23
|
||||
github.com/projectdiscovery/utils v0.4.21
|
||||
github.com/projectdiscovery/wappalyzergo v0.2.36
|
||||
github.com/redis/go-redis/v9 v9.11.0
|
||||
github.com/seh-msft/burpxml v1.0.1
|
||||
@@ -191,7 +191,7 @@ require (
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/dlclark/regexp2 v1.11.5 // indirect
|
||||
github.com/docker/cli v27.4.1+incompatible // indirect
|
||||
github.com/docker/docker v28.0.0+incompatible // indirect
|
||||
github.com/docker/docker v27.1.1+incompatible // indirect
|
||||
github.com/docker/go-connections v0.5.0 // indirect
|
||||
github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 // indirect
|
||||
github.com/emirpasic/gods v1.18.1 // indirect
|
||||
@@ -199,7 +199,7 @@ require (
|
||||
github.com/felixge/fgprof v0.9.5 // indirect
|
||||
github.com/free5gc/util v1.0.5-0.20230511064842-2e120956883b // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
|
||||
github.com/gaissmai/bart v0.20.5 // indirect
|
||||
github.com/gaissmai/bart v0.20.4 // indirect
|
||||
github.com/geoffgarside/ber v1.1.0 // indirect
|
||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||
github.com/gin-gonic/gin v1.9.1 // indirect
|
||||
@@ -213,7 +213,7 @@ require (
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-sourcemap/sourcemap v2.1.4+incompatible // indirect
|
||||
github.com/go-viper/mapstructure/v2 v2.3.0 // indirect
|
||||
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2 // indirect
|
||||
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect
|
||||
@@ -298,7 +298,7 @@ require (
|
||||
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
|
||||
github.com/refraction-networking/utls v1.7.1 // indirect
|
||||
github.com/refraction-networking/utls v1.7.0 // indirect
|
||||
github.com/sashabaranov/go-openai v1.37.0 // indirect
|
||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible // indirect
|
||||
|
||||
@@ -297,8 +297,8 @@ github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZ
|
||||
github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
||||
github.com/docker/cli v27.4.1+incompatible h1:VzPiUlRJ/xh+otB75gva3r05isHMo5wXDfPRi5/b4hI=
|
||||
github.com/docker/cli v27.4.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/docker v28.0.0+incompatible h1:Olh0KS820sJ7nPsBKChVhk5pzqcwDR15fumfAd/p9hM=
|
||||
github.com/docker/docker v28.0.0+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker v27.1.1+incompatible h1:hO/M4MtV36kzKldqnA37IWhebRA+LnqqcqDja6kVaKY=
|
||||
github.com/docker/docker v27.1.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
|
||||
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
|
||||
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
||||
@@ -332,8 +332,8 @@ github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4
|
||||
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
|
||||
github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
|
||||
github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
|
||||
github.com/gaissmai/bart v0.20.5 h1:ehoWZWQ7j//qt0K0Zs4i9hpoPpbgqsMQiR8W2QPJh+c=
|
||||
github.com/gaissmai/bart v0.20.5/go.mod h1:cEed+ge8dalcbpi8wtS9x9m2hn/fNJH5suhdGQOHnYk=
|
||||
github.com/gaissmai/bart v0.20.4 h1:Ik47r1fy3jRVU+1eYzKSW3ho2UgBVTVnUS8O993584U=
|
||||
github.com/gaissmai/bart v0.20.4/go.mod h1:cEed+ge8dalcbpi8wtS9x9m2hn/fNJH5suhdGQOHnYk=
|
||||
github.com/geoffgarside/ber v1.1.0 h1:qTmFG4jJbwiSzSXoNJeHcOprVzZ8Ulde2Rrrifu5U9w=
|
||||
github.com/geoffgarside/ber v1.1.0/go.mod h1:jVPKeCbj6MvQZhwLYsGwaGI52oUorHoHKNecGT85ZCc=
|
||||
github.com/getkin/kin-openapi v0.132.0 h1:3ISeLMsQzcb5v26yeJrBcdTCEQTag36ZjaGk7MIRUwk=
|
||||
@@ -397,8 +397,8 @@ github.com/go-sql-driver/mysql v1.9.3/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI6
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM=
|
||||
github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
|
||||
github.com/go-viper/mapstructure/v2 v2.3.0 h1:27XbWsHIqhbdR5TIC911OfYvgSaW93HM+dX7970Q7jk=
|
||||
github.com/go-viper/mapstructure/v2 v2.3.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||
github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss=
|
||||
github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||
github.com/goburrow/cache v0.1.4 h1:As4KzO3hgmzPlnaMniZU9+VmoNYseUhuELbxy9mRBfw=
|
||||
github.com/goburrow/cache v0.1.4/go.mod h1:cDFesZDnIlrHoNlMYqqMpCRawuXulgx+y7mXU8HZ+/c=
|
||||
github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
|
||||
@@ -769,8 +769,8 @@ github.com/projectdiscovery/clistats v0.1.1 h1:8mwbdbwTU4aT88TJvwIzTpiNeow3XnAB7
|
||||
github.com/projectdiscovery/clistats v0.1.1/go.mod h1:4LtTC9Oy//RiuT1+76MfTg8Hqs7FQp1JIGBM3nHK6a0=
|
||||
github.com/projectdiscovery/dsl v0.5.0 h1:3HHY14FNmdwWXq3pi9dd8JjUHQzskZjLD/pZKVx5Vi4=
|
||||
github.com/projectdiscovery/dsl v0.5.0/go.mod h1:Fr+zIQJfMNy+RTj5KFgozfvDaiQQEKMyrKXl75aGgxY=
|
||||
github.com/projectdiscovery/fastdialer v0.4.4 h1:QeVbOnTMPhc/IOkkj2AP2q9hu5E1oCBPiLwEvPSR6A8=
|
||||
github.com/projectdiscovery/fastdialer v0.4.4/go.mod h1:a0FNUOcmW6g6JhjaJ2+YkCpFFkQeCbetq/d9Zo4G3rQ=
|
||||
github.com/projectdiscovery/fastdialer v0.4.1 h1:kp6Q0odo0VZ0vZIGOn+q9aLgBSk6uYoD1MsjCAH8+h4=
|
||||
github.com/projectdiscovery/fastdialer v0.4.1/go.mod h1:875Wlggf0JAz+fDIPwUQeeBqEF6nJA71XVrjuTZCV7I=
|
||||
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=
|
||||
@@ -787,8 +787,8 @@ github.com/projectdiscovery/gostruct v0.0.2 h1:s8gP8ApugGM4go1pA+sVlPDXaWqNP5BBD
|
||||
github.com/projectdiscovery/gostruct v0.0.2/go.mod h1:H86peL4HKwMXcQQtEa6lmC8FuD9XFt6gkNR0B/Mu5PE=
|
||||
github.com/projectdiscovery/gozero v0.0.3 h1:tsYkrSvWw4WdIUJyisd4MB1vRiw1X57TuVVk3p8Z3G8=
|
||||
github.com/projectdiscovery/gozero v0.0.3/go.mod h1:MpJ37Dsh94gy2EKqaemdeh+CzduGVB2SDfhr6Upsjew=
|
||||
github.com/projectdiscovery/hmap v0.0.92 h1:NHGDFVJzc7b8bDuIjss7SxX5LJla9py/RxC4lri+uBo=
|
||||
github.com/projectdiscovery/hmap v0.0.92/go.mod h1:IKezuOhPPwrmPusmhLuwuGsD8+fniyy6jx4gFTOZOnI=
|
||||
github.com/projectdiscovery/hmap v0.0.91 h1:8vSTU+3hmMfA5Qd14ceq4j7wnUVUJcXdqQgqbsFBea0=
|
||||
github.com/projectdiscovery/hmap v0.0.91/go.mod h1:BxEg8WXqxqaOADPZ+xp2X6BY+znfV8dusCSGSFnsU3c=
|
||||
github.com/projectdiscovery/httpx v1.7.0 h1:s7ZgF2ZAt9pQYkBuY5F6SjyNYbYrl7eiIzOm/6hBZ/E=
|
||||
github.com/projectdiscovery/httpx v1.7.0/go.mod h1:D0HLzSy+/G6w01FtRORGyfwVwWlUPAFIc8wyEj/lcVg=
|
||||
github.com/projectdiscovery/interactsh v1.2.4 h1:WUSj+fxbcV53J64oIAhbYzCKD1w/IyenyRBhkI5jiqI=
|
||||
@@ -801,24 +801,18 @@ github.com/projectdiscovery/mapcidr v1.1.34 h1:udr83vQ7oz3kEOwlsU6NC6o08leJzSDQt
|
||||
github.com/projectdiscovery/mapcidr v1.1.34/go.mod h1:1+1R6OkKSAKtWDXE9RvxXtXPoajXTYX0eiEdkqlhQqQ=
|
||||
github.com/projectdiscovery/n3iwf v0.0.0-20230523120440-b8cd232ff1f5 h1:L/e8z8yw1pfT6bg35NiN7yd1XKtJap5Nk6lMwQ0RNi8=
|
||||
github.com/projectdiscovery/n3iwf v0.0.0-20230523120440-b8cd232ff1f5/go.mod h1:pGW2ncnTxTxHtP9wzcIJAB+3/NMp6IiuQWd2NK7K+oc=
|
||||
github.com/projectdiscovery/networkpolicy v0.1.18 h1:DAeP73SvcuT4evaohNS7BPELw+VtvcVt4PaTK3fC1qA=
|
||||
github.com/projectdiscovery/networkpolicy v0.1.18/go.mod h1:2yWanKsU2oBZ75ch94IsEQy6hByFp+3oTiSyC6ew3TE=
|
||||
github.com/projectdiscovery/networkpolicy v0.1.17 h1:A/axsarHnVgv8bPB2vuI/7Hg0PrFBL+KGFSurJlDzx0=
|
||||
github.com/projectdiscovery/networkpolicy v0.1.17/go.mod h1:Bwgfqbb2RAMIQ0OvfVofoFQFV3DitnXZZX5DkQMnjx8=
|
||||
github.com/projectdiscovery/ratelimit v0.0.81 h1:u6lW+rAhS/UO0amHTYmYLipPK8NEotA9521hdojBtgI=
|
||||
github.com/projectdiscovery/ratelimit v0.0.81/go.mod h1:tK04WXHuC4i6AsFkByInODSNf45gd9sfaMHzmy2bAsA=
|
||||
github.com/projectdiscovery/ratelimit v0.0.82-0.20250819014026-b6ac32486d12 h1:oS/0Oe6tv7SG2zoFBofwvoB3mfDb5Yk76np4zU0Mcg8=
|
||||
github.com/projectdiscovery/ratelimit v0.0.82-0.20250819014026-b6ac32486d12/go.mod h1:z076BrLkBb5yS7uhHNoCTf8X/BvFSGRxwQ8EzEL9afM=
|
||||
github.com/projectdiscovery/ratelimit v0.0.82-0.20250819164203-5e0837ee74a5 h1:tulP7aVzZsWlXbWo6W78nVFqJ05c6zSS8dsos/cBaSY=
|
||||
github.com/projectdiscovery/ratelimit v0.0.82-0.20250819164203-5e0837ee74a5/go.mod h1:z076BrLkBb5yS7uhHNoCTf8X/BvFSGRxwQ8EzEL9afM=
|
||||
github.com/projectdiscovery/ratelimit v0.0.82-0.20250819165347-d56e782c656d h1:zUptoE5gh4gyJsbcHfNUEKgdoieyAHW2hCfWXZ/Zye4=
|
||||
github.com/projectdiscovery/ratelimit v0.0.82-0.20250819165347-d56e782c656d/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.105 h1:G8ln01igkNTQ5xvMY5K4cx5XIfKGTwGH6aZxWxBKMqc=
|
||||
github.com/projectdiscovery/retryabledns v1.0.105/go.mod h1:3EZKhRL1rokqYR4q5qKK1eLBEe8mSzgtzkMOJilO1Ok=
|
||||
github.com/projectdiscovery/retryablehttp-go v1.0.119 h1:Lpjb6gCWpIvCCX8GultM8zlaQEmFOci1dS33k9Ll4gw=
|
||||
github.com/projectdiscovery/retryablehttp-go v1.0.119/go.mod h1:x29gqkLERRzw0znJDu5ORhphBaVin8FtK0+jCvCx4os=
|
||||
github.com/projectdiscovery/retryabledns v1.0.103 h1:rPnoMTK+CXLbO8kT7ODtwbhyQGAUpJsqhVq8AAvu1bs=
|
||||
github.com/projectdiscovery/retryabledns v1.0.103/go.mod h1:sfu91YrZkb8Ccvij8YDTV96cQt69IPqnfa+OEFUke1o=
|
||||
github.com/projectdiscovery/retryablehttp-go v1.0.117 h1:xU9H2ONb9iG25Sm4eCinDhb4kt/s542BomUZAx4CGEs=
|
||||
github.com/projectdiscovery/retryablehttp-go v1.0.117/go.mod h1:pAQWFh6lg9Gmno5zrQxbfuAbc9OvIugl5P9kaoXztgM=
|
||||
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=
|
||||
@@ -829,8 +823,8 @@ github.com/projectdiscovery/uncover v1.1.0 h1:UDp/qLZn78YZb6VPoOrfyP1vz+ojEx8VrT
|
||||
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.4.23 h1:fi6AVPIh2laomWO+Yy6G8YhvM4c2fDmQ/Viio6VZgyw=
|
||||
github.com/projectdiscovery/utils v0.4.23/go.mod h1:2K2ymMPnp4/Zao5QulCDJzKjxdyZPsucQm6Fyo09JlA=
|
||||
github.com/projectdiscovery/utils v0.4.21 h1:yAothTUSF6NwZ9yoC4iGe5gSBrovqKR9JwwW3msxk3Q=
|
||||
github.com/projectdiscovery/utils v0.4.21/go.mod h1:HJuJFqjB6EmVaDl0ilFPKvLoMaX2GyE6Il2TqKXNs8I=
|
||||
github.com/projectdiscovery/wappalyzergo v0.2.36 h1:g/E2gatdYcmLKk9R81vrkq4RdpACpYgN1fuyY3041eE=
|
||||
github.com/projectdiscovery/wappalyzergo v0.2.36/go.mod h1:L4P6SZuaEgEE2eXbpf4OnSGxjWj9vn6xM15SD78niLA=
|
||||
github.com/projectdiscovery/yamldoc-go v1.0.6 h1:GCEdIRlQjDux28xTXKszM7n3jlMf152d5nqVpVoetas=
|
||||
@@ -861,8 +855,8 @@ github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0ua
|
||||
github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY=
|
||||
github.com/redis/go-redis/v9 v9.11.0 h1:E3S08Gl/nJNn5vkxd2i78wZxWAPNZgUNTp8WIJUAiIs=
|
||||
github.com/redis/go-redis/v9 v9.11.0/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw=
|
||||
github.com/refraction-networking/utls v1.7.1 h1:dxg+jla3uocgN8HtX+ccwDr68uCBBO3qLrkZUbqkcw0=
|
||||
github.com/refraction-networking/utls v1.7.1/go.mod h1:TUhh27RHMGtQvjQq+RyO11P6ZNQNBb3N0v7wsEjKAIQ=
|
||||
github.com/refraction-networking/utls v1.7.0 h1:9JTnze/Md74uS3ZWiRAabityY0un69rOLXsBf8LGgTs=
|
||||
github.com/refraction-networking/utls v1.7.0/go.mod h1:lV0Gwc1/Fi+HYH8hOtgFRdHfKo4FKSn6+FdyOz9hRms=
|
||||
github.com/remeh/sizedwaitgroup v1.0.0 h1:VNGGFwNo/R5+MJBf6yrsr110p0m4/OX4S3DCy7Kyl5E=
|
||||
github.com/remeh/sizedwaitgroup v1.0.0/go.mod h1:3j2R4OIe/SeS6YDhICBy22RWjJC5eNCJ1V+9+NVNYlo=
|
||||
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
@@ -982,8 +976,8 @@ github.com/weppos/publicsuffix-go v0.12.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8L
|
||||
github.com/weppos/publicsuffix-go v0.13.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k=
|
||||
github.com/weppos/publicsuffix-go v0.30.0/go.mod h1:kBi8zwYnR0zrbm8RcuN1o9Fzgpnnn+btVN8uWPMyXAY=
|
||||
github.com/weppos/publicsuffix-go v0.30.2/go.mod h1:/hGscit36Yt+wammfBBwdMdxBT8btsTt6KvwO9OvMyM=
|
||||
github.com/weppos/publicsuffix-go v0.40.3-0.20250408071509-6074bbe7fd39 h1:Bz/zVM/LoGZ9IztGBHrq2zlFQQbEG8dBYnxb4hamIHM=
|
||||
github.com/weppos/publicsuffix-go v0.40.3-0.20250408071509-6074bbe7fd39/go.mod h1:2oFzEwGYI7lhiqG0YkkcKa6VcpjVinQbWxaPzytDmLA=
|
||||
github.com/weppos/publicsuffix-go v0.40.3-0.20250311103038-7794c8c0723b h1:PFOWooJRLwIuZk9i3ihzKzZffPrAVyOCzPInvLbn140=
|
||||
github.com/weppos/publicsuffix-go v0.40.3-0.20250311103038-7794c8c0723b/go.mod h1:EACzvcFHnxqmDapI/oqMjtpXz+mtjNzJe7r1zhRczZ0=
|
||||
github.com/weppos/publicsuffix-go/publicsuffix/generator v0.0.0-20220927085643-dc0d00c92642/go.mod h1:GHfoeIdZLdZmLjMlzBftbTDntahTttUMWjxZwQJhULE=
|
||||
github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc=
|
||||
github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw=
|
||||
|
||||
@@ -87,7 +87,7 @@ type Runner struct {
|
||||
colorizer aurora.Aurora
|
||||
issuesClient reporting.Client
|
||||
browser *engine.Browser
|
||||
rateLimiter *ratelimit.AutoLimiter
|
||||
rateLimiter *ratelimit.Limiter
|
||||
hostErrors hosterrorscache.CacheInterface
|
||||
resumeCfg *types.ResumeCfg
|
||||
pprofServer *pprofutil.PprofServer
|
||||
@@ -125,14 +125,6 @@ func New(options *types.Options) (*Runner, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// if template list or template display is enabled, enable all templates
|
||||
if options.TemplateList || options.TemplateDisplay {
|
||||
options.EnableCodeTemplates = true
|
||||
options.EnableFileTemplates = true
|
||||
options.EnableSelfContainedTemplates = true
|
||||
options.EnableGlobalMatchersTemplates = true
|
||||
}
|
||||
|
||||
// check for custom template updates and update if available
|
||||
ctm, err := customtemplates.NewCustomTemplatesManager(options)
|
||||
if err != nil {
|
||||
@@ -384,17 +376,11 @@ func New(options *types.Options) (*Runner, error) {
|
||||
if options.RateLimit > 0 && options.RateLimitDuration == 0 {
|
||||
options.RateLimitDuration = time.Second
|
||||
}
|
||||
var ratelimiter *ratelimit.AutoLimiter
|
||||
if options.RateLimit == 0 && options.RateLimitDuration == 0 {
|
||||
ratelimiter = ratelimit.NewAutoLimiter(context.Background(), ratelimit.WithUnlimited())
|
||||
runner.rateLimiter = ratelimit.NewUnlimited(context.Background())
|
||||
} else {
|
||||
ratelimiter = ratelimit.NewAutoLimiter(
|
||||
context.Background(),
|
||||
ratelimit.WithMaxCount(uint(options.RateLimit)),
|
||||
ratelimit.WithDuration(options.RateLimitDuration),
|
||||
)
|
||||
runner.rateLimiter = ratelimit.New(context.Background(), uint(options.RateLimit), options.RateLimitDuration)
|
||||
}
|
||||
runner.rateLimiter = ratelimiter
|
||||
|
||||
if tmpDir, err := os.MkdirTemp("", "nuclei-tmp-*"); err == nil {
|
||||
runner.tmpDir = tmpDir
|
||||
|
||||
@@ -50,7 +50,7 @@ type NucleiExecutorOptions struct {
|
||||
Progress progress.Progress
|
||||
Catalog catalog.Catalog
|
||||
IssuesClient reporting.Client
|
||||
RateLimiter *ratelimit.AutoLimiter
|
||||
RateLimiter *ratelimit.Limiter
|
||||
Interactsh *interactsh.Client
|
||||
ProjectFile *projectfile.ProjectFile
|
||||
Browser *browserEngine.Browser
|
||||
|
||||
@@ -31,7 +31,7 @@ const (
|
||||
CLIConfigFileName = "config.yaml"
|
||||
ReportingConfigFilename = "reporting-config.yaml"
|
||||
// Version is the current version of nuclei
|
||||
Version = `v3.4.8`
|
||||
Version = `v3.4.7`
|
||||
// Directory Names of custom templates
|
||||
CustomS3TemplatesDirName = "s3"
|
||||
CustomGitHubTemplatesDirName = "github"
|
||||
@@ -46,21 +46,18 @@ const (
|
||||
// if the current version is outdated
|
||||
func IsOutdatedVersion(current, latest string) bool {
|
||||
if latest == "" {
|
||||
// NOTE(dwisiswant0): if PDTM API call failed or returned empty, we
|
||||
// cannot determine if templates are outdated w/o additional checks
|
||||
// return false to avoid unnecessary updates.
|
||||
return false
|
||||
// if pdtm api call failed it's assumed that the current version is outdated
|
||||
// and it will be confirmed while updating from GitHub
|
||||
// this fixes `version string empty` errors
|
||||
return true
|
||||
}
|
||||
|
||||
current = trimDevIfExists(current)
|
||||
currentVer, _ := semver.NewVersion(current)
|
||||
newVer, _ := semver.NewVersion(latest)
|
||||
|
||||
if currentVer == nil || newVer == nil {
|
||||
// fallback to naive comparison - return true only if they are different
|
||||
return current != latest
|
||||
// fallback to naive comparison
|
||||
return current == latest
|
||||
}
|
||||
|
||||
return newVer.GreaterThan(currentVer)
|
||||
}
|
||||
|
||||
|
||||
+5
-65
@@ -14,7 +14,6 @@ import (
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/contextargs"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/expressions"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/generators"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/marker"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/utils/json"
|
||||
"github.com/projectdiscovery/retryablehttp-go"
|
||||
errorutil "github.com/projectdiscovery/utils/errors"
|
||||
@@ -24,7 +23,7 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
ErrRuleNotApplicable = errorutil.NewWithFmt("rule not applicable: %v")
|
||||
ErrRuleNotApplicable = errorutil.NewWithFmt("rule not applicable : %v")
|
||||
)
|
||||
|
||||
// IsErrRuleNotApplicable checks if an error is due to rule not applicable
|
||||
@@ -190,33 +189,6 @@ mainLoop:
|
||||
return nil
|
||||
}
|
||||
|
||||
// evaluateVars evaluates variables in a string using available executor options
|
||||
func (rule *Rule) evaluateVars(input string) (string, error) {
|
||||
if rule.options == nil {
|
||||
return input, nil
|
||||
}
|
||||
|
||||
data := generators.MergeMaps(
|
||||
rule.options.Variables.GetAll(),
|
||||
rule.options.Constants,
|
||||
rule.options.Options.Vars.AsMap(),
|
||||
)
|
||||
|
||||
exprs := expressions.FindExpressions(input, marker.ParenthesisOpen, marker.ParenthesisClose, data)
|
||||
|
||||
err := expressions.ContainsUnresolvedVariables(exprs...)
|
||||
if err != nil {
|
||||
return input, err
|
||||
}
|
||||
|
||||
eval, err := expressions.Evaluate(input, data)
|
||||
if err != nil {
|
||||
return input, err
|
||||
}
|
||||
|
||||
return eval, nil
|
||||
}
|
||||
|
||||
// evaluateVarsWithInteractsh evaluates the variables with Interactsh URLs and updates them accordingly.
|
||||
func (rule *Rule) evaluateVarsWithInteractsh(data map[string]interface{}, interactshUrls []string) (map[string]interface{}, []string) {
|
||||
// Check if Interactsh options are configured
|
||||
@@ -369,47 +341,23 @@ func (rule *Rule) Compile(generator *generators.PayloadGenerator, options *proto
|
||||
if len(rule.Keys) > 0 {
|
||||
rule.keysMap = make(map[string]struct{})
|
||||
}
|
||||
|
||||
// eval vars in "keys"
|
||||
for _, key := range rule.Keys {
|
||||
evaluatedKey, err := rule.evaluateVars(key)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not evaluate key")
|
||||
}
|
||||
|
||||
rule.keysMap[strings.ToLower(evaluatedKey)] = struct{}{}
|
||||
rule.keysMap[strings.ToLower(key)] = struct{}{}
|
||||
}
|
||||
|
||||
// eval vars in "values"
|
||||
for _, value := range rule.ValuesRegex {
|
||||
evaluatedValue, err := rule.evaluateVars(value)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not evaluate value regex")
|
||||
}
|
||||
|
||||
compiled, err := regexp.Compile(evaluatedValue)
|
||||
compiled, err := regexp.Compile(value)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not compile value regex")
|
||||
}
|
||||
|
||||
rule.valuesRegex = append(rule.valuesRegex, compiled)
|
||||
}
|
||||
|
||||
// eval vars in "keys-regex"
|
||||
for _, value := range rule.KeysRegex {
|
||||
evaluatedValue, err := rule.evaluateVars(value)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not evaluate key regex")
|
||||
}
|
||||
|
||||
compiled, err := regexp.Compile(evaluatedValue)
|
||||
compiled, err := regexp.Compile(value)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not compile key regex")
|
||||
}
|
||||
|
||||
rule.keysRegex = append(rule.keysRegex, compiled)
|
||||
}
|
||||
|
||||
if rule.ruleType != replaceRegexRuleType {
|
||||
if rule.ReplaceRegex != "" {
|
||||
return errors.Errorf("replace-regex is only applicable for replace and replace-regex rule types")
|
||||
@@ -418,19 +366,11 @@ func (rule *Rule) Compile(generator *generators.PayloadGenerator, options *proto
|
||||
if rule.ReplaceRegex == "" {
|
||||
return errors.Errorf("replace-regex is required for replace-regex rule type")
|
||||
}
|
||||
|
||||
evalReplaceRegex, err := rule.evaluateVars(rule.ReplaceRegex)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not evaluate replace regex")
|
||||
}
|
||||
|
||||
compiled, err := regexp.Compile(evalReplaceRegex)
|
||||
compiled, err := regexp.Compile(rule.ReplaceRegex)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not compile replace regex")
|
||||
}
|
||||
|
||||
rule.replaceRegex = compiled
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -3,11 +3,6 @@ package fuzz
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/projectdiscovery/goflags"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/protocols"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/variables"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/types"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/utils"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
@@ -42,219 +37,3 @@ func TestRuleMatchKeyOrValue(t *testing.T) {
|
||||
require.False(t, result, "could not get correct result")
|
||||
})
|
||||
}
|
||||
|
||||
func TestEvaluateVariables(t *testing.T) {
|
||||
t.Run("keys", func(t *testing.T) {
|
||||
rule := &Rule{
|
||||
Keys: []string{"{{foo_var}}"},
|
||||
Part: "query",
|
||||
}
|
||||
|
||||
// mock
|
||||
templateVars := variables.Variable{
|
||||
InsertionOrderedStringMap: *utils.NewEmptyInsertionOrderedStringMap(1),
|
||||
}
|
||||
templateVars.Set("foo_var", "foo_var_value")
|
||||
|
||||
constants := map[string]interface{}{
|
||||
"const_key": "const_value",
|
||||
}
|
||||
|
||||
options := &types.Options{}
|
||||
|
||||
// runtime vars (to simulate CLI)
|
||||
runtimeVars := goflags.RuntimeMap{}
|
||||
_ = runtimeVars.Set("runtime_key=runtime_value")
|
||||
options.Vars = runtimeVars
|
||||
|
||||
executorOpts := &protocols.ExecutorOptions{
|
||||
Variables: templateVars,
|
||||
Constants: constants,
|
||||
Options: options,
|
||||
}
|
||||
|
||||
err := rule.Compile(nil, executorOpts)
|
||||
require.NoError(t, err, "could not compile rule")
|
||||
|
||||
result := rule.matchKeyOrValue("foo_var_value", "test_value")
|
||||
require.True(t, result, "should match evaluated variable key")
|
||||
|
||||
result = rule.matchKeyOrValue("{{foo_var}}", "test_value")
|
||||
require.False(t, result, "should not match unevaluated variable key")
|
||||
})
|
||||
|
||||
t.Run("keys-regex", func(t *testing.T) {
|
||||
rule := &Rule{
|
||||
KeysRegex: []string{"^{{foo_var}}"},
|
||||
Part: "query",
|
||||
}
|
||||
|
||||
templateVars := variables.Variable{
|
||||
InsertionOrderedStringMap: *utils.NewEmptyInsertionOrderedStringMap(1),
|
||||
}
|
||||
templateVars.Set("foo_var", "foo_var_value")
|
||||
|
||||
executorOpts := &protocols.ExecutorOptions{
|
||||
Variables: templateVars,
|
||||
Constants: map[string]interface{}{},
|
||||
Options: &types.Options{},
|
||||
}
|
||||
|
||||
err := rule.Compile(nil, executorOpts)
|
||||
require.NoError(t, err, "could not compile rule")
|
||||
|
||||
result := rule.matchKeyOrValue("foo_var_value", "test_value")
|
||||
require.True(t, result, "should match evaluated variable in regex")
|
||||
|
||||
result = rule.matchKeyOrValue("other_key", "test_value")
|
||||
require.False(t, result, "should not match non-matching key")
|
||||
})
|
||||
|
||||
t.Run("values-regex", func(t *testing.T) {
|
||||
rule := &Rule{
|
||||
ValuesRegex: []string{"{{foo_var}}"},
|
||||
Part: "query",
|
||||
}
|
||||
|
||||
templateVars := variables.Variable{
|
||||
InsertionOrderedStringMap: *utils.NewEmptyInsertionOrderedStringMap(1),
|
||||
}
|
||||
templateVars.Set("foo_var", "test_pattern")
|
||||
|
||||
executorOpts := &protocols.ExecutorOptions{
|
||||
Variables: templateVars,
|
||||
Constants: map[string]interface{}{},
|
||||
Options: &types.Options{},
|
||||
}
|
||||
|
||||
err := rule.Compile(nil, executorOpts)
|
||||
require.NoError(t, err, "could not compile rule")
|
||||
|
||||
result := rule.matchKeyOrValue("test_key", "test_pattern")
|
||||
require.True(t, result, "should match evaluated variable in values regex")
|
||||
|
||||
result = rule.matchKeyOrValue("test_key", "other_value")
|
||||
require.False(t, result, "should not match non-matching value")
|
||||
})
|
||||
|
||||
// complex vars w/ consts and runtime vars
|
||||
t.Run("complex-variables", func(t *testing.T) {
|
||||
rule := &Rule{
|
||||
Keys: []string{"{{template_var}}", "{{const_key}}", "{{runtime_key}}"},
|
||||
Part: "query",
|
||||
}
|
||||
|
||||
templateVars := variables.Variable{
|
||||
InsertionOrderedStringMap: *utils.NewEmptyInsertionOrderedStringMap(1),
|
||||
}
|
||||
templateVars.Set("template_var", "template_value")
|
||||
|
||||
constants := map[string]interface{}{
|
||||
"const_key": "const_value",
|
||||
}
|
||||
|
||||
options := &types.Options{}
|
||||
runtimeVars := goflags.RuntimeMap{}
|
||||
_ = runtimeVars.Set("runtime_key=runtime_value")
|
||||
options.Vars = runtimeVars
|
||||
|
||||
executorOpts := &protocols.ExecutorOptions{
|
||||
Variables: templateVars,
|
||||
Constants: constants,
|
||||
Options: options,
|
||||
}
|
||||
|
||||
err := rule.Compile(nil, executorOpts)
|
||||
require.NoError(t, err, "could not compile rule")
|
||||
|
||||
result := rule.matchKeyOrValue("template_value", "test")
|
||||
require.True(t, result, "should match template variable")
|
||||
|
||||
result = rule.matchKeyOrValue("const_value", "test")
|
||||
require.True(t, result, "should match constant")
|
||||
|
||||
result = rule.matchKeyOrValue("runtime_value", "test")
|
||||
require.True(t, result, "should match runtime variable")
|
||||
|
||||
result = rule.matchKeyOrValue("{{template_var}}", "test")
|
||||
require.False(t, result, "should not match unevaluated template variable")
|
||||
})
|
||||
|
||||
t.Run("invalid-variables", func(t *testing.T) {
|
||||
rule := &Rule{
|
||||
Keys: []string{"{{nonexistent_var}}"},
|
||||
Part: "query",
|
||||
}
|
||||
|
||||
executorOpts := &protocols.ExecutorOptions{
|
||||
Variables: variables.Variable{
|
||||
InsertionOrderedStringMap: *utils.NewEmptyInsertionOrderedStringMap(0),
|
||||
},
|
||||
Constants: map[string]interface{}{},
|
||||
Options: &types.Options{},
|
||||
}
|
||||
|
||||
err := rule.Compile(nil, executorOpts)
|
||||
if err != nil {
|
||||
require.Contains(t, err.Error(), "unresolved", "error should mention unresolved variables")
|
||||
} else {
|
||||
result := rule.matchKeyOrValue("some_key", "some_value")
|
||||
require.False(t, result, "should not match when variables are unresolved")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("evaluateVars-function", func(t *testing.T) {
|
||||
rule := &Rule{}
|
||||
|
||||
templateVars := variables.Variable{
|
||||
InsertionOrderedStringMap: *utils.NewEmptyInsertionOrderedStringMap(1),
|
||||
}
|
||||
templateVars.Set("test_var", "test_value")
|
||||
|
||||
constants := map[string]interface{}{
|
||||
"const_var": "const_value",
|
||||
}
|
||||
|
||||
options := &types.Options{}
|
||||
runtimeVars := goflags.RuntimeMap{}
|
||||
_ = runtimeVars.Set("runtime_var=runtime_value")
|
||||
options.Vars = runtimeVars
|
||||
|
||||
executorOpts := &protocols.ExecutorOptions{
|
||||
Variables: templateVars,
|
||||
Constants: constants,
|
||||
Options: options,
|
||||
}
|
||||
|
||||
rule.options = executorOpts
|
||||
|
||||
// Test simple var substitution
|
||||
result, err := rule.evaluateVars("{{test_var}}")
|
||||
require.NoError(t, err, "should evaluate template variable")
|
||||
require.Equal(t, "test_value", result, "should return evaluated value")
|
||||
|
||||
// Test constant substitution
|
||||
result, err = rule.evaluateVars("{{const_var}}")
|
||||
require.NoError(t, err, "should evaluate constant")
|
||||
require.Equal(t, "const_value", result, "should return constant value")
|
||||
|
||||
// Test runtime var substitution
|
||||
result, err = rule.evaluateVars("{{runtime_var}}")
|
||||
require.NoError(t, err, "should evaluate runtime variable")
|
||||
require.Equal(t, "runtime_value", result, "should return runtime value")
|
||||
|
||||
// Test mixed content
|
||||
result, err = rule.evaluateVars("prefix-{{test_var}}-suffix")
|
||||
require.NoError(t, err, "should evaluate mixed content")
|
||||
require.Equal(t, "prefix-test_value-suffix", result, "should return mixed evaluated content")
|
||||
|
||||
// Test unresolved var - should either fail during evaluation or return original string
|
||||
result2, err := rule.evaluateVars("{{nonexistent}}")
|
||||
if err != nil {
|
||||
require.Contains(t, err.Error(), "unresolved", "should fail for unresolved variable")
|
||||
} else {
|
||||
// If no error, it should return the original unresolved variable
|
||||
require.Equal(t, "{{nonexistent}}", result2, "should return original string for unresolved variable")
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -94,24 +94,7 @@ func (t *TemplateManager) UpdateIfOutdated() error {
|
||||
if !fileutil.FolderExists(config.DefaultConfig.TemplatesDirectory) {
|
||||
return t.FreshInstallIfNotExists()
|
||||
}
|
||||
|
||||
needsUpdate := config.DefaultConfig.NeedsTemplateUpdate()
|
||||
|
||||
// NOTE(dwisiswant0): if PDTM API data is not available
|
||||
// (LatestNucleiTemplatesVersion is empty) but we have a current template
|
||||
// version, so we MUST verify against GitHub directly.
|
||||
if !needsUpdate && config.DefaultConfig.LatestNucleiTemplatesVersion == "" && config.DefaultConfig.TemplateVersion != "" {
|
||||
ghrd, err := updateutils.NewghReleaseDownloader(config.OfficialNucleiTemplatesRepoName)
|
||||
if err == nil {
|
||||
latestVersion := ghrd.Latest.GetTagName()
|
||||
if config.IsOutdatedVersion(config.DefaultConfig.TemplateVersion, latestVersion) {
|
||||
needsUpdate = true
|
||||
gologger.Debug().Msgf("PDTM API unavailable, verified update needed via GitHub API: %s -> %s", config.DefaultConfig.TemplateVersion, latestVersion)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if needsUpdate {
|
||||
if config.DefaultConfig.NeedsTemplateUpdate() {
|
||||
return t.updateTemplatesAt(config.DefaultConfig.TemplatesDirectory)
|
||||
}
|
||||
return nil
|
||||
@@ -159,14 +142,7 @@ func (t *TemplateManager) updateTemplatesAt(dir string) error {
|
||||
return errorutil.NewWithErr(err).Msgf("failed to install templates at %s", dir)
|
||||
}
|
||||
|
||||
latestVersion := ghrd.Latest.GetTagName()
|
||||
currentVersion := config.DefaultConfig.TemplateVersion
|
||||
|
||||
if config.IsOutdatedVersion(currentVersion, latestVersion) {
|
||||
gologger.Info().Msgf("Your current nuclei-templates %s are outdated. Latest is %s\n", currentVersion, latestVersion)
|
||||
} else {
|
||||
gologger.Debug().Msgf("Updating nuclei-templates from %s to %s (forced update)\n", currentVersion, latestVersion)
|
||||
}
|
||||
gologger.Info().Msgf("Your current nuclei-templates %s are outdated. Latest is %s\n", config.DefaultConfig.TemplateVersion, ghrd.Latest.GetTagName())
|
||||
|
||||
// write templates to disk
|
||||
if err := t.writeTemplatesToDisk(ghrd, dir); err != nil {
|
||||
|
||||
@@ -59,42 +59,3 @@ func TestTemplateInstallation(t *testing.T) {
|
||||
require.FileExists(t, config.DefaultConfig.GetIgnoreFilePath())
|
||||
t.Logf("Installed %d templates", counter)
|
||||
}
|
||||
|
||||
func TestIsOutdatedVersion(t *testing.T) {
|
||||
testCases := []struct {
|
||||
current string
|
||||
latest string
|
||||
expected bool
|
||||
desc string
|
||||
}{
|
||||
// Test the empty latest version case (main bug fix)
|
||||
{"v10.2.7", "", false, "Empty latest version should not trigger update"},
|
||||
|
||||
// Test same versions
|
||||
{"v10.2.7", "v10.2.7", false, "Same versions should not trigger update"},
|
||||
|
||||
// Test outdated version
|
||||
{"v10.2.6", "v10.2.7", true, "Older version should trigger update"},
|
||||
|
||||
// Test newer current version (edge case)
|
||||
{"v10.2.8", "v10.2.7", false, "Newer current version should not trigger update"},
|
||||
|
||||
// Test dev versions
|
||||
{"v10.2.7-dev", "v10.2.7", false, "Dev version matching release should not trigger update"},
|
||||
{"v10.2.6-dev", "v10.2.7", true, "Outdated dev version should trigger update"},
|
||||
|
||||
// Test invalid semver fallback
|
||||
{"invalid-version", "v10.2.7", true, "Invalid current version should trigger update (fallback)"},
|
||||
{"v10.2.7", "invalid-version", true, "Invalid latest version should trigger update (fallback)"},
|
||||
{"same-invalid", "same-invalid", false, "Same invalid versions should not trigger update (fallback)"},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
result := config.IsOutdatedVersion(tc.current, tc.latest)
|
||||
require.Equal(t, tc.expected, result,
|
||||
"IsOutdatedVersion(%q, %q) = %t, expected %t",
|
||||
tc.current, tc.latest, result, tc.expected)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -53,12 +53,8 @@ func NewWafDetector() *WafDetector {
|
||||
}
|
||||
|
||||
func (d *WafDetector) DetectWAF(content string) (string, bool) {
|
||||
if d == nil || d.regexCache == nil {
|
||||
return "", false
|
||||
}
|
||||
|
||||
for id, regex := range d.regexCache {
|
||||
if regex != nil && regex.MatchString(content) {
|
||||
if regex.MatchString(content) {
|
||||
return id, true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
package waf
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"testing"
|
||||
)
|
||||
import "testing"
|
||||
|
||||
func TestWAFDetection(t *testing.T) {
|
||||
detector := NewWafDetector()
|
||||
@@ -61,61 +58,3 @@ func TestWAFDetection(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestWAFDetectionNilPointerSafety(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
detector *WafDetector
|
||||
content string
|
||||
}{
|
||||
{
|
||||
name: "nil detector",
|
||||
detector: nil,
|
||||
content: "test content",
|
||||
},
|
||||
{
|
||||
name: "nil regexCache",
|
||||
detector: &WafDetector{
|
||||
wafs: make(map[string]waf),
|
||||
regexCache: nil,
|
||||
},
|
||||
content: "test content",
|
||||
},
|
||||
{
|
||||
name: "regexCache with nil regex",
|
||||
detector: &WafDetector{
|
||||
wafs: make(map[string]waf),
|
||||
regexCache: map[string]*regexp.Regexp{
|
||||
"test": nil,
|
||||
},
|
||||
},
|
||||
content: "test content",
|
||||
},
|
||||
{
|
||||
name: "empty regexCache",
|
||||
detector: &WafDetector{
|
||||
wafs: make(map[string]waf),
|
||||
regexCache: make(map[string]*regexp.Regexp),
|
||||
},
|
||||
content: "test content",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
t.Errorf("DetectWAF panicked with nil pointer: %v", r)
|
||||
}
|
||||
}()
|
||||
|
||||
waf, matched := tt.detector.DetectWAF(tt.content)
|
||||
if matched {
|
||||
t.Errorf("expected no match for nil pointer case, got match=true, waf=%s", waf)
|
||||
}
|
||||
if waf != "" {
|
||||
t.Errorf("expected empty WAF string for nil pointer case, got waf=%s", waf)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -151,7 +151,7 @@ func (request *Request) execute(input *contextargs.Context, domain string, metad
|
||||
}
|
||||
}
|
||||
|
||||
request.options.RateLimitTake(input)
|
||||
request.options.RateLimitTake()
|
||||
|
||||
// Send the request to the target servers
|
||||
response, err := dnsClient.Do(compiledRequest)
|
||||
|
||||
@@ -20,13 +20,12 @@ import (
|
||||
|
||||
// Browser is a browser structure for nuclei headless module
|
||||
type Browser struct {
|
||||
customAgent string
|
||||
defaultHeaders map[string]string
|
||||
tempDir string
|
||||
previousPIDs map[int32]struct{} // track already running PIDs
|
||||
engine *rod.Browser
|
||||
options *types.Options
|
||||
launcher *launcher.Launcher
|
||||
customAgent string
|
||||
tempDir string
|
||||
previousPIDs map[int32]struct{} // track already running PIDs
|
||||
engine *rod.Browser
|
||||
options *types.Options
|
||||
launcher *launcher.Launcher
|
||||
|
||||
// use getHTTPClient to get the http client
|
||||
httpClient *http.Client
|
||||
@@ -96,7 +95,6 @@ func New(options *types.Options) (*Browser, error) {
|
||||
if browserErr := browser.Connect(); browserErr != nil {
|
||||
return nil, browserErr
|
||||
}
|
||||
defaultHeaders := make(map[string]string)
|
||||
customAgent := ""
|
||||
for _, option := range options.CustomHeaders {
|
||||
parts := strings.SplitN(option, ":", 2)
|
||||
@@ -105,20 +103,12 @@ func New(options *types.Options) (*Browser, error) {
|
||||
}
|
||||
if strings.EqualFold(parts[0], "User-Agent") {
|
||||
customAgent = parts[1]
|
||||
} else {
|
||||
k := strings.TrimSpace(parts[0])
|
||||
v := strings.TrimSpace(parts[1])
|
||||
if k == "" || v == "" {
|
||||
continue
|
||||
}
|
||||
defaultHeaders[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
engine := &Browser{
|
||||
tempDir: dataStore,
|
||||
customAgent: customAgent,
|
||||
defaultHeaders: defaultHeaders,
|
||||
engine: browser,
|
||||
options: options,
|
||||
httpClientOnce: &sync.Once{},
|
||||
@@ -145,30 +135,6 @@ func (b *Browser) UserAgent() string {
|
||||
return b.customAgent
|
||||
}
|
||||
|
||||
// applyDefaultHeaders setsheaders passed via cli -H flag
|
||||
func (b *Browser) applyDefaultHeaders(p *rod.Page) error {
|
||||
pairs := make([]string, 0, len(b.defaultHeaders)*2+2)
|
||||
|
||||
hasAcceptLanguage := false
|
||||
for k := range b.defaultHeaders {
|
||||
if strings.EqualFold(k, "Accept-Language") {
|
||||
hasAcceptLanguage = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !hasAcceptLanguage {
|
||||
pairs = append(pairs, "Accept-Language", "en, en-GB, en-us;")
|
||||
}
|
||||
for k, v := range b.defaultHeaders {
|
||||
pairs = append(pairs, k, v)
|
||||
}
|
||||
if len(pairs) == 0 {
|
||||
return nil
|
||||
}
|
||||
_, err := p.SetExtraHeaders(pairs)
|
||||
return err
|
||||
}
|
||||
|
||||
func (b *Browser) getHTTPClient() (*http.Client, error) {
|
||||
var err error
|
||||
b.httpClientOnce.Do(func() {
|
||||
@@ -181,6 +147,6 @@ func (b *Browser) getHTTPClient() (*http.Client, error) {
|
||||
func (b *Browser) Close() {
|
||||
_ = b.engine.Close()
|
||||
b.launcher.Kill()
|
||||
_ = os.RemoveAll(b.tempDir)
|
||||
os.RemoveAll(b.tempDir)
|
||||
processutil.CloseProcesses(processutil.IsChromeProcess, b.previousPIDs)
|
||||
}
|
||||
@@ -61,10 +61,6 @@ func (i *Instance) Run(ctx *contextargs.Context, actions []*Action, payloads map
|
||||
}
|
||||
page = page.Timeout(options.Timeout)
|
||||
|
||||
if err = i.browser.applyDefaultHeaders(page); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if i.browser.customAgent != "" {
|
||||
if userAgentErr := page.SetUserAgent(&proto.NetworkSetUserAgentOverride{UserAgent: i.browser.customAgent}); userAgentErr != nil {
|
||||
return nil, nil, userAgentErr
|
||||
@@ -134,6 +130,10 @@ func (i *Instance) Run(ctx *contextargs.Context, actions []*Action, payloads map
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if _, err := page.SetExtraHeaders([]string{"Accept-Language", "en, en-GB, en-us;"}); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// inject cookies
|
||||
// each http request is performed via the native go http client
|
||||
// we first inject the shared cookies
|
||||
|
||||
@@ -291,7 +291,7 @@ func (request *Request) executeParallelHTTP(input *contextargs.Context, dynamicV
|
||||
return
|
||||
}
|
||||
// putting ratelimiter here prevents any unnecessary waiting if any
|
||||
request.options.RateLimitTake(input)
|
||||
request.options.RateLimitTake()
|
||||
|
||||
// after ratelimit take, check if we need to stop
|
||||
if spmHandler.FoundFirstMatch() || request.isUnresponsiveAddress(updatedInput) || spmHandler.Cancelled() {
|
||||
@@ -470,7 +470,7 @@ func (request *Request) ExecuteWithResults(input *contextargs.Context, dynamicVa
|
||||
executeFunc := func(data string, payloads, dynamicValue map[string]interface{}) (bool, error) {
|
||||
hasInteractMatchers := interactsh.HasMatchers(request.CompiledOperators)
|
||||
|
||||
request.options.RateLimitTake(input)
|
||||
request.options.RateLimitTake()
|
||||
|
||||
ctx := request.newContext(input)
|
||||
ctxWithTimeout, cancel := context.WithTimeoutCause(ctx, request.options.Options.GetTimeouts().HttpTimeout, ErrHttpEngineRequestDeadline)
|
||||
|
||||
@@ -76,7 +76,7 @@ func (request *Request) executeFuzzingRule(input *contextargs.Context, previous
|
||||
if errors.Is(err, ErrMissingVars) {
|
||||
return err
|
||||
}
|
||||
gologger.Verbose().Msgf("[%s] fuzz: payload request execution failed: %s\n", request.options.TemplateID, err)
|
||||
gologger.Verbose().Msgf("[%s] fuzz: payload request execution failed : %s\n", request.options.TemplateID, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -103,13 +103,13 @@ func (request *Request) executeFuzzingRule(input *contextargs.Context, previous
|
||||
// in case of any error, return it
|
||||
if fuzz.IsErrRuleNotApplicable(err) {
|
||||
// log and fail silently
|
||||
gologger.Verbose().Msgf("[%s] fuzz: %s\n", request.options.TemplateID, err)
|
||||
gologger.Verbose().Msgf("[%s] fuzz: rule not applicable : %s\n", request.options.TemplateID, err)
|
||||
return nil
|
||||
}
|
||||
if errors.Is(err, ErrMissingVars) {
|
||||
return err
|
||||
}
|
||||
gologger.Verbose().Msgf("[%s] fuzz: payload request execution failed: %s\n", request.options.TemplateID, err)
|
||||
gologger.Verbose().Msgf("[%s] fuzz: payload request execution failed : %s\n", request.options.TemplateID, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -158,7 +158,7 @@ func (request *Request) executeAllFuzzingRules(input *contextargs.Context, value
|
||||
continue
|
||||
}
|
||||
if fuzz.IsErrRuleNotApplicable(err) {
|
||||
gologger.Verbose().Msgf("[%s] fuzz: %s\n", request.options.TemplateID, err)
|
||||
gologger.Verbose().Msgf("[%s] fuzz: rule not applicable : %s\n", request.options.TemplateID, err)
|
||||
continue
|
||||
}
|
||||
if err == types.ErrNoMoreRequests {
|
||||
@@ -168,9 +168,8 @@ func (request *Request) executeAllFuzzingRules(input *contextargs.Context, value
|
||||
}
|
||||
|
||||
if !applicable {
|
||||
return fmt.Errorf("no rule was applicable for this request: %v", input.MetaInput.Input)
|
||||
return fuzz.ErrRuleNotApplicable.Msgf(fmt.Sprintf("no rule was applicable for this request: %v", input.MetaInput.Input))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -181,7 +180,7 @@ func (request *Request) executeGeneratedFuzzingRequest(gr fuzz.GeneratedRequest,
|
||||
if request.options.HostErrorsCache != nil && request.options.HostErrorsCache.Check(request.options.ProtocolType.String(), input) {
|
||||
return false
|
||||
}
|
||||
request.options.RateLimitTake(input)
|
||||
request.options.RateLimitTake()
|
||||
req := &generatedRequest{
|
||||
request: gr.Request,
|
||||
dynamicValues: gr.DynamicValues,
|
||||
|
||||
@@ -78,7 +78,7 @@ type ExecutorOptions struct {
|
||||
// Progress is a progress client for scan reporting
|
||||
Progress progress.Progress
|
||||
// RateLimiter is a rate-limiter for limiting sent number of requests.
|
||||
RateLimiter *ratelimit.AutoLimiter
|
||||
RateLimiter *ratelimit.Limiter
|
||||
// Catalog is a template catalog implementation for nuclei
|
||||
Catalog catalog.Catalog
|
||||
// ProjectFile is the project file for nuclei
|
||||
@@ -143,7 +143,7 @@ type ExecutorOptions struct {
|
||||
// todo: centralizing components is not feasible with current clogged architecture
|
||||
// a possible approach could be an internal event bus with pub-subs? This would be less invasive than
|
||||
// reworking dep injection from scratch
|
||||
func (e *ExecutorOptions) RateLimitTake(ctx *contextargs.Context) {
|
||||
func (e *ExecutorOptions) RateLimitTake() {
|
||||
// The code below can race and there isn't a great way to fix this without adding an idempotent
|
||||
// function to the rate limiter implementation. For now, stick with whatever rate is already set.
|
||||
/*
|
||||
@@ -152,11 +152,8 @@ func (e *ExecutorOptions) RateLimitTake(ctx *contextargs.Context) {
|
||||
e.RateLimiter.SetDuration(e.Options.RateLimitDuration)
|
||||
}
|
||||
*/
|
||||
if hostErrorCache, ok := e.HostErrorsCache.(*hosterrorscache.Cache); ok {
|
||||
key := hostErrorCache.GetKeyFromContext(ctx, nil)
|
||||
if e.RateLimiter != nil {
|
||||
e.RateLimiter.Take(key)
|
||||
}
|
||||
if e.RateLimiter != nil {
|
||||
e.RateLimiter.Take()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ type Options struct {
|
||||
|
||||
// New creates a new issue tracker integration client based on options.
|
||||
func New(options *Options) (*Integration, error) {
|
||||
var transport = http.DefaultTransport
|
||||
var transport http.RoundTripper = http.DefaultTransport
|
||||
if options.HttpClient != nil && options.HttpClient.HTTPClient.Transport != nil {
|
||||
transport = options.HttpClient.HTTPClient.Transport
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ type ScanStatsWorker struct {
|
||||
m *sync.Mutex
|
||||
directory string
|
||||
file *os.File
|
||||
enc json.Encoder
|
||||
enc *json.Encoder
|
||||
}
|
||||
|
||||
// Init initializes the scan stats worker
|
||||
|
||||
@@ -88,11 +88,6 @@ type TemplateInfo struct {
|
||||
// NewMockExecuterOptions creates a new mock executeroptions struct
|
||||
func NewMockExecuterOptions(options *types.Options, info *TemplateInfo) *protocols.ExecutorOptions {
|
||||
progressImpl, _ := progress.NewStatsTicker(0, false, false, false, 0)
|
||||
rateLimiter := ratelimit.NewAutoLimiter(
|
||||
context.Background(),
|
||||
ratelimit.WithMaxCount(uint(options.RateLimit)),
|
||||
ratelimit.WithDuration(time.Second),
|
||||
)
|
||||
executerOpts := &protocols.ExecutorOptions{
|
||||
TemplateID: info.ID,
|
||||
TemplateInfo: info.Info,
|
||||
@@ -104,7 +99,7 @@ func NewMockExecuterOptions(options *types.Options, info *TemplateInfo) *protoco
|
||||
IssuesClient: nil,
|
||||
Browser: nil,
|
||||
Catalog: disk.NewCatalog(config.DefaultConfig.TemplatesDirectory),
|
||||
RateLimiter: rateLimiter,
|
||||
RateLimiter: ratelimit.New(context.Background(), uint(options.RateLimit), time.Second),
|
||||
}
|
||||
executerOpts.CreateTemplateCtxStore()
|
||||
return executerOpts
|
||||
|
||||
Reference in new issue
Block a user