diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 000000000..bcd49f4c6 --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,35 @@ +{ + "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/DISCUSSION_TEMPLATE.md b/.github/DISCUSSION_TEMPLATE.md new file mode 100644 index 000000000..4c1367265 --- /dev/null +++ b/.github/DISCUSSION_TEMPLATE.md @@ -0,0 +1,76 @@ +# Nuclei Discussion Guidelines + +## Before Creating a Discussion + +1. **Search existing discussions and issues** to avoid duplicates +2. **Check the documentation** and README first +3. **Browse the FAQ** and common questions + +## Bug Reports in Discussions + +When reporting a bug in [Q&A Discussions](https://github.com/projectdiscovery/nuclei/discussions/categories/q-a), please include: + +### Required Information: +- **Clear title** with `[BUG]` prefix (e.g., "[BUG] Nuclei crashes when...") +- **Current behavior** - What's happening now? +- **Expected behavior** - What should happen instead? +- **Steps to reproduce** - Commands or actions that trigger the issue +- **Environment details**: + - OS and version + - Nuclei version (`nuclei -version`) + - Go version (if installed via `go install`) +- **Log output** - Run with `-verbose` or `-debug` for detailed logs +- **Redact sensitive information** - Remove target URLs, credentials, etc. + +### After Discussion: +- Maintainers will review and validate the bug report +- Valid bugs will be converted to issues with proper labels and tracking +- Questions and misconfigurations will be resolved in the discussion + +## Feature Requests in Discussions + +When requesting a feature in [Ideas Discussions](https://github.com/projectdiscovery/nuclei/discussions/categories/ideas), please include: + +### Required Information: +- **Clear title** with `[FEATURE]` prefix (e.g., "[FEATURE] Add support for...") +- **Feature description** - What do you want to be added? +- **Use case** - Why is this feature needed? What problem does it solve? +- **Implementation ideas** - If you have suggestions on how it could work +- **Alternatives considered** - What other solutions have you thought about? + +### After Discussion: +- Community and maintainers will discuss the feasibility +- Popular and viable features will be converted to issues +- Similar features may be grouped together +- Rejected features will be explained in the discussion + +## Getting Help + +For general questions, troubleshooting, and "how-to" topics: +- Use [Q&A Discussions](https://github.com/projectdiscovery/nuclei/discussions/categories/q-a) +- Join the [Discord server](https://discord.gg/projectdiscovery) #nuclei channel +- Check existing discussions for similar questions + +## Discussion to Issue Conversion Process + +Only maintainers can convert discussions to issues. The process: + +1. **Validation** - Maintainers review the discussion for completeness and validity +2. **Classification** - Determine if it's a bug, feature, enhancement, etc. +3. **Issue creation** - Create a properly formatted issue with appropriate labels +4. **Linking** - Link the issue back to the original discussion +5. **Resolution** - Mark the discussion as resolved or close it + +This process ensures: +- High-quality issues that are actionable +- Proper triage and labeling +- Reduced noise in the issue tracker +- Community involvement in the validation process + +## Why This Process? + +- **Better organization** - Issues contain only validated, actionable items +- **Community input** - Discussions allow for community feedback before escalation +- **Quality control** - Maintainers ensure proper formatting and information +- **Reduced maintenance** - Fewer invalid or duplicate issues to manage +- **Clear separation** - Questions vs. actual bugs/features are clearly distinguished diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index d849b1032..4a0c58e23 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -2,14 +2,22 @@ blank_issues_enabled: false contact_links: - - name: Ask an question / advise on using nuclei - url: https://github.com/projectdiscovery/nuclei/discussions/categories/q-a - about: Ask a question or request support for using nuclei + - 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: Share idea / feature to discuss for nuclei - url: https://github.com/projectdiscovery/nuclei/discussions/categories/ideas - about: Share idea / feature to discuss for nuclei + - 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. - - name: Connect with PD Team (Discord) + - name: โ Ask Questions / Get Help + url: https://github.com/orgs/projectdiscovery/discussions + about: Get help and ask questions about using Nuclei. Many questions don't require issues. + + - name: ๐ Browse Existing Issues + url: https://github.com/projectdiscovery/nuclei/issues + about: Check existing issues to see if your problem has already been reported or is being worked on. + + - name: ๐ฌ Connect with PD Team (Discord) url: https://discord.gg/projectdiscovery - about: Connect with PD Team for direct communication \ No newline at end of file + about: Join our Discord for real-time discussions and community support on the #nuclei channel. \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/reference-templates/README.md b/.github/ISSUE_TEMPLATE/reference-templates/README.md new file mode 100644 index 000000000..c170ea1c7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/reference-templates/README.md @@ -0,0 +1,45 @@ +# Issue Template References + +## Overview + +This folder contains the preserved issue templates that are **not** directly accessible to users. These templates serve as references for maintainers when converting discussions to issues. + +## New Workflow + +### For Users: +1. **All reports start in Discussions** - Users cannot create issues directly +2. Bug reports go to [Q&A Discussions](https://github.com/projectdiscovery/nuclei/discussions/categories/q-a) +3. Feature requests go to [Ideas Discussions](https://github.com/projectdiscovery/nuclei/discussions/categories/ideas) +4. This helps filter out duplicate questions, invalid reports, and ensures proper triage + +### For Maintainers: +1. **Review discussions** in both Q&A and Ideas categories +2. **Validate the reports** - ensure they're actual bugs/valid feature requests +3. **Use reference templates** when converting discussions to issues: + - Copy content from `bug-report-reference.yml` or `feature-request-reference.yml` + - Create a new issue manually with the appropriate template structure + - Link back to the original discussion + - Close the discussion or mark it as resolved + +## Benefits + +- **Better triage**: Avoid cluttering issues with questions and invalid reports +- **Community involvement**: Discussions allow for community input before creating issues +- **Quality control**: Maintainers can ensure issues follow proper format and contain necessary information +- **Reduced noise**: Only validated, actionable items become issues + +## Reference Templates + +- `bug-report-reference.yml` - Use when converting bug reports from discussions to issues +- `feature-request-reference.yml` - Use when converting feature requests from discussions to issues + +## Converting a Discussion to Issue + +1. Identify a valid discussion that needs to become an issue +2. Go to the main repository's Issues tab +3. Click "New Issue" +4. Manually create the issue using the reference template structure +5. Include all relevant information from the discussion +6. Add a comment linking back to the original discussion +7. Apply appropriate labels +8. Close or mark the discussion as resolved with a link to the created issue diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/reference-templates/bug-report-reference.yml similarity index 100% rename from .github/ISSUE_TEMPLATE/bug-report.yml rename to .github/ISSUE_TEMPLATE/reference-templates/bug-report-reference.yml diff --git a/.github/ISSUE_TEMPLATE/feature-request.yml b/.github/ISSUE_TEMPLATE/reference-templates/feature-request-reference.yml similarity index 100% rename from .github/ISSUE_TEMPLATE/feature-request.yml rename to .github/ISSUE_TEMPLATE/reference-templates/feature-request-reference.yml diff --git a/.github/auto_assign.yml b/.github/auto_assign.yml index 3d6642fc5..273b6ac02 100644 --- a/.github/auto_assign.yml +++ b/.github/auto_assign.yml @@ -2,6 +2,7 @@ addReviewers: true reviewers: - dogancanbakir - dwisiswant0 + - mzack9999 numberOfReviewers: 1 skipKeywords: diff --git a/.github/stale.yml b/.github/stale.yml deleted file mode 100644 index 75d7ee029..000000000 --- a/.github/stale.yml +++ /dev/null @@ -1,27 +0,0 @@ -# Number of days of inactivity before an issue becomes stale -daysUntilStale: 7 - -# Number of days of inactivity before a stale issue is closed -daysUntilClose: 7 - -# Issues with these labels will never be considered stale -# exemptLabels: -# - pinned -# - security - -# Only issues or pull requests with all of these labels are check if stale. -onlyLabels: - - "Status: Abandoned" - - "Type: Question" - -# Label to use when marking as stale -staleLabel: stale - -# Comment to post when marking an issue as stale. Set to `false` to disable -markComment: > - This issue has been automatically marked as stale because it has not had - recent activity. It will be closed if no further activity occurs. Thank you - for your contributions. - -# Comment to post when closing a stale issue. Set to `false` to disable -closeComment: false \ No newline at end of file diff --git a/.github/workflows/auto-merge.yaml b/.github/workflows/auto-merge.yaml index 0ff3098e6..ad2890dda 100644 --- a/.github/workflows/auto-merge.yaml +++ b/.github/workflows/auto-merge.yaml @@ -18,7 +18,7 @@ jobs: runs-on: ubuntu-latest if: github.actor == 'dependabot[bot]' steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 with: token: ${{ secrets.DEPENDABOT_PAT }} diff --git a/.github/workflows/compat-checks.yaml b/.github/workflows/compat-checks.yaml index 589b9a2f1..8a9080b90 100644 --- a/.github/workflows/compat-checks.yaml +++ b/.github/workflows/compat-checks.yaml @@ -13,7 +13,7 @@ jobs: permissions: contents: write steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: projectdiscovery/actions/setup/go/compat-checks@v1 with: release-test: true diff --git a/.github/workflows/generate-docs.yaml b/.github/workflows/generate-docs.yaml index 939b9bc69..a68ff7d97 100644 --- a/.github/workflows/generate-docs.yaml +++ b/.github/workflows/generate-docs.yaml @@ -11,7 +11,7 @@ jobs: if: "${{ !endsWith(github.actor, '[bot]') }}" runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: projectdiscovery/actions/setup/go@v1 - uses: projectdiscovery/actions/setup/git@v1 - run: make syntax-docs diff --git a/.github/workflows/generate-pgo.yaml b/.github/workflows/generate-pgo.yaml index 463e7d686..c10743b98 100644 --- a/.github/workflows/generate-pgo.yaml +++ b/.github/workflows/generate-pgo.yaml @@ -28,7 +28,7 @@ jobs: LIST_FILE: "/tmp/targets-${{ matrix.targets }}.txt" PROFILE_MEM: "/tmp/nuclei-profile-${{ matrix.targets }}-targets" steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: projectdiscovery/actions/setup/git@v1 - uses: projectdiscovery/actions/setup/go@v1 - name: Generate list diff --git a/.github/workflows/govulncheck.yaml b/.github/workflows/govulncheck.yaml index 1a116fa8f..9796b709e 100644 --- a/.github/workflows/govulncheck.yaml +++ b/.github/workflows/govulncheck.yaml @@ -16,7 +16,7 @@ jobs: env: OUTPUT: "/tmp/results.sarif" steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: projectdiscovery/actions/setup/go@v1 - run: go install golang.org/x/vuln/cmd/govulncheck@latest - run: govulncheck -scan package -format sarif ./... > $OUTPUT diff --git a/.github/workflows/perf-regression.yaml b/.github/workflows/perf-regression.yaml index 090f722eb..8e7e7eed5 100644 --- a/.github/workflows/perf-regression.yaml +++ b/.github/workflows/perf-regression.yaml @@ -11,7 +11,7 @@ jobs: env: BENCH_OUT: "/tmp/bench.out" steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: projectdiscovery/actions/setup/go@v1 - run: make build-test - run: ./bin/nuclei.test -test.run - -test.bench=. -test.benchmem ./cmd/nuclei/ | tee $BENCH_OUT diff --git a/.github/workflows/perf-test.yaml b/.github/workflows/perf-test.yaml index 94dec5cbd..4ee8408c9 100644 --- a/.github/workflows/perf-test.yaml +++ b/.github/workflows/perf-test.yaml @@ -16,7 +16,7 @@ jobs: LIST_FILE: "/tmp/targets-${{ matrix.count }}.txt" PROFILE_MEM: "/tmp/nuclei-perf-test-${{ matrix.count }}" steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: projectdiscovery/actions/setup/go@v1 - run: make verify - name: Generate list diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 3eb36e7e2..4d9d412dd 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -10,7 +10,7 @@ jobs: release: runs-on: ubuntu-latest-16-cores steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 with: fetch-depth: 0 - uses: projectdiscovery/actions/setup/go@v1 diff --git a/.github/workflows/stale.yaml b/.github/workflows/stale.yaml new file mode 100644 index 000000000..efa88506d --- /dev/null +++ b/.github/workflows/stale.yaml @@ -0,0 +1,41 @@ +name: ๐ค Stale + +on: + schedule: + - cron: '0 0 * * 0' # Weekly + +jobs: + stale: + runs-on: ubuntu-latest + permissions: + actions: write + contents: write # only for delete-branch option + issues: write + pull-requests: write + steps: + - uses: actions/stale@v10 + with: + days-before-stale: 90 + days-before-close: 7 + stale-issue-label: "Status: Stale" + stale-pr-label: "Status: Stale" + stale-issue-message: > + This issue has been automatically marked as stale because it has not + had recent activity. It will be closed in 7 days if no further + activity occurs. Thank you for your contributions! + stale-pr-message: > + This pull request has been automatically marked as stale due to + inactivity. It will be closed in 7 days if no further activity + occurs. Please update if you wish to keep it open. + close-issue-message: > + This issue has been automatically closed due to inactivity. If you + think this is a mistake or would like to continue the discussion, + please comment or feel free to reopen it. + close-pr-message: > + This pull request has been automatically closed due to inactivity. + If you think this is a mistake or would like to continue working on + it, please comment or feel free to reopen it. + close-issue-label: "Status: Abandoned" + close-pr-label: "Status: Abandoned" + exempt-issue-labels: "Status: Abandoned" + exempt-pr-labels: "Status: Abandoned" diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index af6ad9d7e..cc7f7b989 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -22,9 +22,9 @@ jobs: if: "${{ !endsWith(github.actor, '[bot]') }}" runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: projectdiscovery/actions/setup/go@v1 - - uses: projectdiscovery/actions/golangci-lint@v1 + - uses: projectdiscovery/actions/golangci-lint/v2@v1 tests: name: "Tests" @@ -35,7 +35,7 @@ jobs: os: [ubuntu-latest, windows-latest, macOS-latest] runs-on: "${{ matrix.os }}" steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: projectdiscovery/actions/setup/go@v1 - run: make vet - run: make build @@ -52,16 +52,18 @@ jobs: needs: ["tests"] runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: projectdiscovery/actions/setup/go@v1 - name: "Simple" run: go run . working-directory: examples/simple/ # - run: go run . # Temporarily disabled very flaky in github actions # working-directory: examples/advanced/ - - name: "with Speed Control" - run: go run . - working-directory: examples/with_speed_control/ + + # TODO: FIX with ExecutionID (ref: https://github.com/projectdiscovery/nuclei/pull/6296) + # - name: "with Speed Control" + # run: go run . + # working-directory: examples/with_speed_control/ integration: name: "Integration tests" @@ -72,7 +74,7 @@ jobs: os: [ubuntu-latest, windows-latest, macOS-latest] runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: projectdiscovery/actions/setup/go@v1 - uses: projectdiscovery/actions/setup/python@v1 - run: bash run.sh "${{ matrix.os }}" @@ -91,10 +93,10 @@ jobs: os: [ubuntu-latest, windows-latest, macOS-latest] runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: projectdiscovery/actions/setup/go@v1 - uses: projectdiscovery/actions/setup/python@v1 - - run: bash run.sh "${{ matrix.os }}" + - run: bash run.sh env: GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" working-directory: cmd/functional-test/ @@ -104,7 +106,7 @@ jobs: needs: ["tests"] runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: projectdiscovery/actions/setup/go@v1 - run: make template-validate @@ -117,7 +119,7 @@ jobs: contents: read security-events: write steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: github/codeql-action/init@v3 with: languages: 'go' @@ -129,7 +131,7 @@ jobs: needs: ["tests"] runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: projectdiscovery/actions/setup/go@v1 - uses: projectdiscovery/actions/goreleaser@v1 @@ -141,7 +143,7 @@ jobs: TARGET_URL: "http://scanme.sh/a/?b=c" runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - run: make build - name: "Setup environment (push)" if: ${{ github.event_name == 'push' }} diff --git a/.gitignore b/.gitignore index f5153fe0f..8e4f9d93e 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,8 @@ /scrapefunc /scrapefuncs /tsgen +/integration_tests/integration-test +/integration_tests/nuclei # Templates /*.yaml diff --git a/.goreleaser.yml b/.goreleaser.yml index d33aabc1f..2d2f61379 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -38,9 +38,9 @@ builds: # goarch: [amd64] archives: - - format: zip + - formats: [zip] id: nuclei - builds: [nuclei-cli] + ids: [nuclei-cli] name_template: '{{ .ProjectName }}_{{ .Version }}_{{ if eq .Os "darwin" }}macOS{{ else }}{{ .Os }}{{ end }}_{{ .Arch }}' checksum: diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 000000000..ba6e226f6 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,83 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +Nuclei is a modern, high-performance vulnerability scanner built in Go that leverages YAML-based templates for customizable vulnerability detection. It supports multiple protocols (HTTP, DNS, TCP, SSL, WebSocket, WHOIS, JavaScript, Code) and is designed for zero false positives through real-world condition simulation. + +## Development Commands + +### Building and Testing +- `make build` - Build the main nuclei binary to ./bin/nuclei +- `make test` - Run unit tests with race detection +- `make integration` - Run integration tests (builds and runs test suite) +- `make functional` - Run functional tests +- `make vet` - Run go vet for code analysis +- `make tidy` - Clean up go modules + +### Validation and Linting +- `make template-validate` - Validate nuclei templates using the built binary +- `go fmt ./...` - Format Go code +- `go vet ./...` - Static analysis + +### Development Tools +- `make devtools-all` - Build all development tools (bindgen, tsgen, scrapefuncs) +- `make jsupdate-all` - Update JavaScript bindings and TypeScript definitions +- `make docs` - Generate documentation +- `make memogen` - Generate memoization code for JavaScript libraries + +### Testing Specific Components +- Run single test: `go test -v ./pkg/path/to/package -run TestName` +- Integration tests are in `integration_tests/` and can be run via `make integration` + +## Architecture Overview + +### Core Components +- **cmd/nuclei** - Main CLI entry point with flag parsing and configuration +- **internal/runner** - Core runner that orchestrates the entire scanning process +- **pkg/core** - Execution engine with work pools and template clustering +- **pkg/templates** - Template parsing, compilation, and management +- **pkg/protocols** - Protocol implementations (HTTP, DNS, Network, etc.) +- **pkg/operators** - Matching and extraction logic (matchers/extractors) +- **pkg/catalog** - Template discovery and loading from disk/remote sources + +### Protocol Architecture +Each protocol (HTTP, DNS, Network, etc.) implements: +- Request interface with Compile(), ExecuteWithResults(), Match(), Extract() methods +- Operators embedding for matching/extraction functionality +- Protocol-specific request building and execution logic + +### Template System +- Templates are YAML files defining vulnerability detection logic +- Compiled into executable requests with operators (matchers/extractors) +- Support for workflows (multi-step template execution) +- Template clustering optimizes identical requests across multiple templates + +### Key Execution Flow +1. Template loading and compilation via pkg/catalog/loader +2. Input provider setup for targets +3. Engine creation with work pools for concurrency +4. Template execution with result collection via operators +5. Output writing and reporting integration + +### JavaScript Integration +- Custom JavaScript runtime for code protocol templates +- Auto-generated bindings in pkg/js/generated/ +- Library implementations in pkg/js/libs/ +- Development tools for binding generation in pkg/js/devtools/ + +## Template Development +- Templates located in separate nuclei-templates repository +- YAML format with info, requests, and operators sections +- Support for multiple protocol types in single template +- Built-in DSL functions for dynamic content generation +- Template validation available via `make template-validate` + +## Key Directories +- **lib/** - SDK for embedding nuclei as a library +- **examples/** - Usage examples for different scenarios +- **integration_tests/** - Integration test suite with protocol-specific tests +- **pkg/fuzz/** - Fuzzing engine and DAST capabilities +- **pkg/input/** - Input processing for various formats (Burp, OpenAPI, etc.) +- **pkg/reporting/** - Result export and issue tracking integrations \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 9d7a780c7..eebc24add 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Build -FROM golang:1.22-alpine AS builder +FROM golang:1.24-alpine AS builder RUN apk add build-base WORKDIR /app @@ -13,4 +13,4 @@ FROM alpine:latest RUN apk add --no-cache bind-tools chromium ca-certificates COPY --from=builder /app/bin/nuclei /usr/local/bin/ -ENTRYPOINT ["nuclei"] \ No newline at end of file +ENTRYPOINT ["nuclei"] diff --git a/Makefile b/Makefile index 0c3ab083b..bfb0b5a64 100644 --- a/Makefile +++ b/Makefile @@ -15,8 +15,8 @@ ifneq ($(shell go env GOOS),darwin) endif .PHONY: all build build-stats clean devtools-all devtools-bindgen devtools-scrapefuncs -.PHONY: devtools-tsgen docs docgen dsl-docs functional fuzzplayground go-build syntax-docs -.PHONY: integration jsupdate-all jsupdate-bindgen jsupdate-tsgen memogen scan-charts test +.PHONY: devtools-tsgen docs docgen dsl-docs functional fuzzplayground go-build lint lint-strict syntax-docs +.PHONY: integration jsupdate-all jsupdate-bindgen jsupdate-tsgen memogen scan-charts test test-with-lint .PHONY: tidy ts verify download vet template-validate all: build @@ -146,5 +146,18 @@ dsl-docs: template-validate: build template-validate: ./bin/nuclei -ut - ./bin/nuclei -validate -et http/technologies - ./bin/nuclei -validate -w workflows -et http/technologies \ No newline at end of file + ./bin/nuclei -validate \ + -et .github/ \ + -et helpers/payloads/ \ + -et http/technologies \ + -t dns \ + -t ssl \ + -t network \ + -t http/exposures \ + -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 fa76e3695..490b60709 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ `Korean` โข `Indonesia` โข `Spanish` โข - `ๆฅๆฌ่ช` + `ๆฅๆฌ่ช` โข `Portuguese` @@ -111,7 +111,7 @@ Browse the full Nuclei [**`documentation here`**](https://docs.projectdiscovery. ### Installation -`nuclei` requires **go1.22** to install successfully. Run the following command to get the repo: +`nuclei` requires **go1.23** to install successfully. Run the following command to get the repo: ```sh go install -v github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest @@ -356,6 +356,7 @@ CLOUD: AUTHENTICATION: -sf, -secret-file string[] path to config file containing secrets for nuclei authenticated scan -ps, -prefetch-secrets prefetch secrets from the secrets file + # NOTE: Headers in secrets files preserve exact casing (useful for case-sensitive APIs) EXAMPLES: diff --git a/README_CN.md b/README_CN.md index f09622d65..99f150e6e 100644 --- a/README_CN.md +++ b/README_CN.md @@ -33,7 +33,7 @@ ไธญๆ โข Korean โข Indonesia โข - Spanish + Spanish โข Portuguese
diff --git a/README_ES.md b/README_ES.md index 527ca7cdc..27f60ee8b 100644 --- a/README_ES.md +++ b/README_ES.md @@ -31,7 +31,7 @@ ไธญๆ โข Korean โข Indonesia โข - Spanish + Spanish โข Portuguese diff --git a/README_ID.md b/README_ID.md index 1180c2ee8..05c163c23 100644 --- a/README_ID.md +++ b/README_ID.md @@ -33,7 +33,7 @@ ไธญๆ โข Korean โข Indonesia โข - Spanish + Spanish โข Portuguese diff --git a/README_JP.md b/README_JP.md index a7fc7a0ac..d80fb4dfc 100644 --- a/README_JP.md +++ b/README_JP.md @@ -30,7 +30,7 @@ ไธญๅฝ่ช โข ้ๅฝ่ช โข ใคใณใใใทใข่ช โข - ในใใคใณ่ช + ในใใคใณ่ช โข ใใซใใฌใซ่ช diff --git a/README_KR.md b/README_KR.md index f1a27f00e..6181c866b 100644 --- a/README_KR.md +++ b/README_KR.md @@ -31,7 +31,7 @@ English โข ไธญๆ โข ํ๊ตญ์ด โข - ์คํ์ธ์ด + ์คํ์ธ์ด โข ํฌ๋ฅดํฌ๊ฐ์ด @@ -341,7 +341,7 @@ Nuclei๋ฅผ ์ฌ์ฉํ๋ฉด ์์ฒด ๊ฒ์ฌ ๋ชจ์์ผ๋ก ํ ์คํธ ์ ๊ทผ ๋ฐฉ์์ ์ฌ - ๋ช ๋ถ ์์ ์์ฒ ๊ฐ์ ํธ์คํธ๋ฅผ ์ฒ๋ฆฌํ ์ ์์. - ๊ฐ๋จํ YAML DSL๋ก ์ฌ์ฉ์ ์ง์ ํ ์คํธ ์ ๊ทผ ๋ฐฉ์์ ์ฝ๊ฒ ์๋ํํ ์ ์์. -๋ฒ๊ทธ ๋ฐ์ดํฐ ์ํฌํ๋ก์ ๋ง๋ ๋ค๋ฅธ ์คํ ์์ค ํ๋ก์ ํธ๋ฅผ ํ์ธํ ์ ์์ต๋๋ค.: [github.com/projectdiscovery](http://github.com/projectdiscovery), ๋ํ, ์ฐ๋ฆฌ๋ ๋งค์ผ [Chaos์์ DNS ๋ฐ์ดํฐ๋ฅผ ๊ฐฑ์ ํด ํธ์คํ ํฉ๋๋ค.](http://chaos.projectdiscovery.io). +๋ฒ๊ทธ ๋ฐ์ดํฐ ์ํฌํ๋ก์ ๋ง๋ ๋ค๋ฅธ ์คํ ์์ค ํ๋ก์ ํธ๋ฅผ ํ์ธํ ์ ์์ต๋๋ค.: [github.com/projectdiscovery](http://github.com/projectdiscovery), ๋ํ, ์ฐ๋ฆฌ๋ ๋งค์ผ [Chaos์์ DNS ๋ฐ์ดํฐ๋ฅผ ๊ฐฑ์ ํด ํธ์คํ ํฉ๋๋ค](http://chaos.projectdiscovery.io). diff --git a/README_PT-BR.md b/README_PT-BR.md index cff85180f..012f878f7 100644 --- a/README_PT-BR.md +++ b/README_PT-BR.md @@ -31,7 +31,7 @@ ไธญๆ โข Korean โข Indonesia โข - Spanish + Spanish โข Portuguese diff --git a/cmd/docgen/docgen.go b/cmd/docgen/docgen.go index 51c2a195d..ca075a19c 100644 --- a/cmd/docgen/docgen.go +++ b/cmd/docgen/docgen.go @@ -19,7 +19,9 @@ func writeToFile(filename string, data []byte) { if err != nil { log.Fatalf("Could not create file %s: %s\n", filename, err) } - defer file.Close() + defer func() { + _ = file.Close() + }() _, err = file.Write(data) if err != nil { diff --git a/cmd/functional-test/main.go b/cmd/functional-test/main.go index 8a5cebc59..caab15f2a 100644 --- a/cmd/functional-test/main.go +++ b/cmd/functional-test/main.go @@ -27,7 +27,7 @@ var ( func main() { flag.Parse() - debug := os.Getenv("DEBUG") == "true" + debug := os.Getenv("DEBUG") == "true" || os.Getenv("RUNNER_DEBUG") == "1" if err, errored := runFunctionalTests(debug); err != nil { log.Fatalf("Could not run functional tests: %s\n", err) @@ -41,7 +41,9 @@ func runFunctionalTests(debug bool) (error, bool) { if err != nil { return errors.Wrap(err, "could not open test cases"), true } - defer file.Close() + defer func() { + _ = file.Close() + }() errored, failedTestCases := runTestCases(file, debug) diff --git a/cmd/functional-test/run.sh b/cmd/functional-test/run.sh index a3caf7222..a955ad8a7 100755 --- a/cmd/functional-test/run.sh +++ b/cmd/functional-test/run.sh @@ -1,27 +1,43 @@ #!/bin/bash -# reading os type from arguments -CURRENT_OS=$1 +if [ "${RUNNER_OS}" == "Windows" ]; then + EXT=".exe" +elif [ "${RUNNER_OS}" == "macOS" ]; then + if [ "${CI}" == "true" ]; then + sudo sysctl -w kern.maxfiles{,perproc}=524288 + sudo launchctl limit maxfiles 65536 524288 + fi -if [ "${CURRENT_OS}" == "windows-latest" ];then - extension=.exe + ORIGINAL_ULIMIT="$(ulimit -n)" + ulimit -n 65536 || true fi +mkdir -p .nuclei-config/nuclei/ +touch .nuclei-config/nuclei/.nuclei-ignore + echo "::group::Building functional-test binary" -go build -o functional-test$extension +go build -o "functional-test${EXT}" echo "::endgroup::" echo "::group::Building Nuclei binary from current branch" -go build -o nuclei_dev$extension ../nuclei -echo "::endgroup::" - -echo "::group::Installing nuclei templates" -./nuclei_dev$extension -update-templates +go build -o "nuclei-dev${EXT}" ../nuclei echo "::endgroup::" echo "::group::Building latest release of nuclei" -go build -o nuclei$extension -v github.com/projectdiscovery/nuclei/v3/cmd/nuclei +go build -o "nuclei${EXT}" -v github.com/projectdiscovery/nuclei/v3/cmd/nuclei echo "::endgroup::" -echo 'Starting Nuclei functional test' -./functional-test$extension -main ./nuclei$extension -dev ./nuclei_dev$extension -testcases testcases.txt +echo "::group::Installing nuclei templates" +eval "./nuclei-dev${EXT} -update-templates" +echo "::endgroup::" + +echo "::group::Validating templates" +eval "./nuclei-dev${EXT} -validate" +echo "::endgroup::" + +echo "Starting Nuclei functional test" +eval "./functional-test${EXT} -main ./nuclei${EXT} -dev ./nuclei-dev${EXT} -testcases testcases.txt" + +if [ "${RUNNER_OS}" == "macOS" ]; then + ulimit -n "${ORIGINAL_ULIMIT}" || true +fi diff --git a/cmd/generate-checksum/main.go b/cmd/generate-checksum/main.go index a381387fa..9a3e7b8ed 100644 --- a/cmd/generate-checksum/main.go +++ b/cmd/generate-checksum/main.go @@ -23,7 +23,9 @@ func main() { if err != nil { log.Fatalf("Could not create file: %s\n", err) } - defer file.Close() + defer func() { + _ = file.Close() + }() err = filepath.WalkDir(templatesDirectory, func(path string, d fs.DirEntry, err error) error { if err != nil || d.IsDir() { diff --git a/cmd/integration-test/custom-dir.go b/cmd/integration-test/custom-dir.go index 550027f06..b1ea83cc6 100644 --- a/cmd/integration-test/custom-dir.go +++ b/cmd/integration-test/custom-dir.go @@ -18,7 +18,9 @@ func (h *customConfigDirTest) Execute(filePath string) error { if err != nil { return err } - defer os.RemoveAll(customTempDirectory) + defer func() { + _ = os.RemoveAll(customTempDirectory) + }() results, err := testutils.RunNucleiBareArgsAndGetResults(debug, []string{"NUCLEI_CONFIG_DIR=" + customTempDirectory}, "-t", filePath, "-u", "8x8exch02.8x8.com") if err != nil { return err diff --git a/cmd/integration-test/dsl.go b/cmd/integration-test/dsl.go index 4e4a275ef..c311b8292 100644 --- a/cmd/integration-test/dsl.go +++ b/cmd/integration-test/dsl.go @@ -21,7 +21,7 @@ type dslVersionWarning struct{} func (d *dslVersionWarning) Execute(templatePath string) error { router := httprouter.New() router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { - fmt.Fprintf(w, "DSL version parsing warning test") + _, _ = fmt.Fprintf(w, "DSL version parsing warning test") }) ts := httptest.NewServer(router) defer ts.Close() @@ -37,7 +37,7 @@ type dslShowVersionWarning struct{} func (d *dslShowVersionWarning) Execute(templatePath string) error { router := httprouter.New() router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { - fmt.Fprintf(w, "DSL version parsing warning test") + _, _ = fmt.Fprintf(w, "DSL version parsing warning test") }) ts := httptest.NewServer(router) defer ts.Close() diff --git a/cmd/integration-test/exporters.go b/cmd/integration-test/exporters.go new file mode 100644 index 000000000..7890734f4 --- /dev/null +++ b/cmd/integration-test/exporters.go @@ -0,0 +1,104 @@ +package main + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/projectdiscovery/nuclei/v3/pkg/output" + "github.com/projectdiscovery/nuclei/v3/pkg/reporting/exporters/mongo" + "github.com/testcontainers/testcontainers-go" + mongocontainer "github.com/testcontainers/testcontainers-go/modules/mongodb" + + osutil "github.com/projectdiscovery/utils/os" + mongoclient "go.mongodb.org/mongo-driver/mongo" + mongooptions "go.mongodb.org/mongo-driver/mongo/options" +) + +const ( + dbName = "test" + dbImage = "mongo:8" +) + +var exportersTestCases = []TestCaseInfo{ + {Path: "exporters/mongo", TestCase: &mongoExporter{}, DisableOn: func() bool { + return osutil.IsWindows() || osutil.IsOSX() + }}, +} + +type mongoExporter struct{} + +func (m *mongoExporter) Execute(filepath string) error { + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute) + defer cancel() + + // Start a MongoDB container + mongodbContainer, err := mongocontainer.Run(ctx, dbImage) + defer func() { + if err := testcontainers.TerminateContainer(mongodbContainer); err != nil { + log.Printf("failed to terminate container: %s", err) + } + }() + if err != nil { + return fmt.Errorf("failed to start container: %w", err) + } + + connString, err := mongodbContainer.ConnectionString(ctx) + if err != nil { + return fmt.Errorf("failed to get connection string for MongoDB container: %s", err) + } + connString = connString + dbName + + // Create a MongoDB exporter and write a test result to the database + opts := mongo.Options{ + ConnectionString: connString, + CollectionName: "test", + BatchSize: 1, // Ensure we write the result immediately + } + + exporter, err := mongo.New(&opts) + if err != nil { + return fmt.Errorf("failed to create MongoDB exporter: %s", err) + } + defer func() { + if err := exporter.Close(); err != nil { + fmt.Printf("failed to close exporter: %s\n", err) + } + }() + + res := &output.ResultEvent{ + Request: "test request", + Response: "test response", + } + + err = exporter.Export(res) + if err != nil { + return fmt.Errorf("failed to export result event to MongoDB: %s", err) + } + + // Verify that the result was written to the database + clientOptions := mongooptions.Client().ApplyURI(connString) + client, err := mongoclient.Connect(ctx, clientOptions) + if err != nil { + return fmt.Errorf("error creating MongoDB client: %s", err) + } + defer func() { + if err := client.Disconnect(ctx); err != nil { + fmt.Printf("failed to disconnect from MongoDB: %s\n", err) + } + }() + + collection := client.Database(dbName).Collection(opts.CollectionName) + var actualRes output.ResultEvent + err = collection.FindOne(ctx, map[string]interface{}{"request": res.Request}).Decode(&actualRes) + if err != nil { + return fmt.Errorf("failed to find document in MongoDB: %s", err) + } + + if actualRes.Request != res.Request || actualRes.Response != res.Response { + return fmt.Errorf("exported result does not match expected result: got %v, want %v", actualRes, res) + } + + return nil +} diff --git a/cmd/integration-test/flow.go b/cmd/integration-test/flow.go index 46ae7cf5f..1c103b95a 100644 --- a/cmd/integration-test/flow.go +++ b/cmd/integration-test/flow.go @@ -49,7 +49,7 @@ func (t *iterateValuesFlow) Execute(filePath string) error { } router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { w.WriteHeader(http.StatusOK) - _, _ = w.Write([]byte(fmt.Sprint(testemails))) + _, _ = fmt.Fprint(w, testemails) }) router.GET("/user/"+getBase64(testemails[0]), func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { w.WriteHeader(http.StatusOK) diff --git a/cmd/integration-test/fuzz.go b/cmd/integration-test/fuzz.go index 230fff031..c2c4bee3a 100644 --- a/cmd/integration-test/fuzz.go +++ b/cmd/integration-test/fuzz.go @@ -55,7 +55,7 @@ func (h *httpFuzzQuery) Execute(filePath string) error { router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { w.Header().Set("Content-Type", "text/html") value := r.URL.Query().Get("id") - fmt.Fprintf(w, "This is test matcher text: %v", value) + _, _ = fmt.Fprintf(w, "This is test matcher text: %v", value) }) ts := httptest.NewTLSServer(router) defer ts.Close() @@ -75,7 +75,7 @@ func (h *fuzzModeOverride) Execute(filePath string) error { router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { w.Header().Set("Content-Type", "text/html") value := r.URL.Query().Get("id") - fmt.Fprintf(w, "This is test matcher text: %v", value) + _, _ = fmt.Fprintf(w, "This is test matcher text: %v", value) }) ts := httptest.NewTLSServer(router) defer ts.Close() @@ -120,7 +120,7 @@ func (h *fuzzTypeOverride) Execute(filePath string) error { router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { w.Header().Set("Content-Type", "text/html") value := r.URL.Query().Get("id") - fmt.Fprintf(w, "This is test matcher text: %v", value) + _, _ = fmt.Fprintf(w, "This is test matcher text: %v", value) }) ts := httptest.NewTLSServer(router) defer ts.Close() @@ -164,7 +164,7 @@ func (h *HeadlessFuzzingQuery) Execute(filePath string) error { router := httprouter.New() router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { resp := fmt.Sprintf("%s", r.URL.Query().Get("url")) - fmt.Fprint(w, resp) + _, _ = fmt.Fprint(w, resp) }) ts := httptest.NewTLSServer(router) defer ts.Close() @@ -190,7 +190,7 @@ func (h *fuzzMultipleMode) Execute(filePath string) error { } w.Header().Set("Content-Type", "text/html") resp := fmt.Sprintf("