├── .github ├── ISSUE_TEMPLATE │ ├── config.yml │ ├── feature_request.md │ └── issue-report.md ├── dependabot.yml ├── release.yml └── workflows │ ├── build-test.yml │ ├── codeql-analysis.yml │ ├── dep-auto-merge.yml │ ├── dockerhub-push.yml │ ├── lint-test.yml │ ├── release-binary.yml │ └── release-test.yml ├── .gitignore ├── .goreleaser.yml ├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── cmd ├── cvemap │ └── main.go └── integration-test │ ├── main.go │ ├── run.sh │ ├── server.go │ └── test-data.json ├── go.mod ├── go.sum ├── pkg ├── runner │ ├── banner.go │ ├── options.go │ ├── runner.go │ └── util.go ├── service │ └── cvemap.go ├── testutils │ └── util.go └── types │ └── types.go └── static └── cvemap.png /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | 3 | contact_links: 4 | - name: Ask an question / advise on using cvemap 5 | url: https://github.com/projectdiscovery/cvemap/discussions/categories/q-a 6 | about: Ask a question or request support for using cvemap 7 | 8 | - name: Share idea / feature to discuss for cvemap 9 | url: https://github.com/projectdiscovery/cvemap/discussions/categories/ideas 10 | about: Share idea / feature to discuss for cvemap 11 | 12 | - name: Connect with PD Team (Discord) 13 | url: https://discord.gg/projectdiscovery 14 | about: Connect with PD Team for direct communication -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Request feature to implement in this project 4 | labels: 'Type: Enhancement' 5 | --- 6 | 7 | 13 | 14 | ### Please describe your feature request: 15 | 16 | 17 | ### Describe the use case of this feature: 18 | 19 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/issue-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Issue report 3 | about: Create a report to help us to improve the project 4 | labels: 'Type: Bug' 5 | 6 | --- 7 | 8 | 13 | 14 | 15 | 16 | ### cvemap version: 17 | 18 | 19 | 20 | 21 | ### Current Behavior: 22 | 23 | 24 | ### Expected Behavior: 25 | 26 | 27 | ### Steps To Reproduce: 28 | 33 | 34 | 35 | ### Anything else: 36 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | 9 | # Maintain dependencies for go modules 10 | - package-ecosystem: "gomod" 11 | directory: "/" 12 | schedule: 13 | interval: "weekly" 14 | target-branch: "main" 15 | commit-message: 16 | prefix: "chore" 17 | include: "scope" 18 | labels: 19 | - "Type: Maintenance" 20 | groups: 21 | modules: 22 | patterns: ["github.com/projectdiscovery/*"] 23 | 24 | # # Maintain dependencies for docker 25 | # - package-ecosystem: "docker" 26 | # directory: "/" 27 | # schedule: 28 | # interval: "weekly" 29 | # target-branch: "dev" 30 | # commit-message: 31 | # prefix: "chore" 32 | # include: "scope" 33 | # labels: 34 | # - "Type: Maintenance" 35 | # 36 | # # Maintain dependencies for GitHub Actions 37 | # - package-ecosystem: "github-actions" 38 | # directory: "/" 39 | # schedule: 40 | # interval: "weekly" 41 | # target-branch: "dev" 42 | # commit-message: 43 | # prefix: "chore" 44 | # include: "scope" 45 | # labels: 46 | # - "Type: Maintenance" 47 | -------------------------------------------------------------------------------- /.github/release.yml: -------------------------------------------------------------------------------- 1 | changelog: 2 | exclude: 3 | authors: 4 | - dependabot 5 | categories: 6 | - title: 🎉 New Features 7 | labels: 8 | - "Type: Enhancement" 9 | - title: 🐞 Bugs Fixes 10 | labels: 11 | - "Type: Bug" 12 | - title: 🔨 Maintenance 13 | labels: 14 | - "Type: Maintenance" 15 | - title: Other Changes 16 | labels: 17 | - "*" -------------------------------------------------------------------------------- /.github/workflows/build-test.yml: -------------------------------------------------------------------------------- 1 | name: 🔨 Build Test 2 | 3 | on: 4 | pull_request: 5 | paths: 6 | - '**.go' 7 | - '**.mod' 8 | workflow_dispatch: 9 | 10 | jobs: 11 | build: 12 | name: Test Builds 13 | runs-on: ${{ matrix.os }} 14 | strategy: 15 | matrix: 16 | os: [ubuntu-latest, windows-latest, macOS-latest] 17 | go-version: [1.21.x] 18 | steps: 19 | - name: Set up Go 20 | uses: actions/setup-go@v4 21 | with: 22 | go-version: ${{ matrix.go-version }} 23 | 24 | - name: Check out code 25 | uses: actions/checkout@v3 26 | 27 | - name: Build 28 | run: go build . 29 | working-directory: cmd/cvemap/ 30 | 31 | - name: Test 32 | run: go test ./... 33 | working-directory: . 34 | 35 | - name: Integration Tests Linux, macOS 36 | if: runner.os == 'Linux' || runner.os == 'macOS' 37 | env: 38 | GH_ACTION: true 39 | run: bash run.sh 40 | working-directory: cmd/integration-test/ 41 | 42 | - name: Integration Tests Windows 43 | if: runner.os == 'Windows' 44 | env: 45 | GH_ACTION: true 46 | MSYS_NO_PATHCONV: true 47 | run: bash run.sh 48 | working-directory: cmd/integration-test/ 49 | 50 | - name: Race Condition Tests 51 | if: github.actor != 'dependabot[bot]' 52 | run: go run -race . -id CVE-1999-0027 53 | working-directory: cmd/cvemap/ 54 | env: 55 | PDCP_API_KEY: "${{ secrets.PDCP_API_KEY }}" 56 | PDCP_API_SERVER: https://api.projectdiscovery.io 57 | DEBUG: true 58 | 59 | # - name: Test Example Code 60 | # run: go run . 61 | # working-directory: examples/ 62 | 63 | 64 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | name: 🚨 CodeQL Analysis 2 | 3 | on: 4 | workflow_dispatch: 5 | pull_request: 6 | branches: 7 | - dev 8 | 9 | jobs: 10 | analyze: 11 | name: Analyze 12 | runs-on: ubuntu-latest 13 | permissions: 14 | actions: read 15 | contents: read 16 | security-events: write 17 | 18 | strategy: 19 | fail-fast: false 20 | matrix: 21 | language: [ 'go' ] 22 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] 23 | 24 | steps: 25 | - name: Checkout repository 26 | uses: actions/checkout@v3 27 | 28 | # Initializes the CodeQL tools for scanning. 29 | - name: Initialize CodeQL 30 | uses: github/codeql-action/init@v2 31 | with: 32 | languages: ${{ matrix.language }} 33 | 34 | - name: Autobuild 35 | uses: github/codeql-action/autobuild@v2 36 | 37 | - name: Perform CodeQL Analysis 38 | uses: github/codeql-action/analyze@v2 -------------------------------------------------------------------------------- /.github/workflows/dep-auto-merge.yml: -------------------------------------------------------------------------------- 1 | name: 🤖 dep auto merge 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - main 7 | workflow_dispatch: 8 | 9 | permissions: 10 | pull-requests: write 11 | issues: write 12 | repository-projects: write 13 | 14 | jobs: 15 | automerge: 16 | runs-on: ubuntu-latest 17 | if: github.actor == 'dependabot[bot]' 18 | steps: 19 | - uses: actions/checkout@v3 20 | with: 21 | token: ${{ secrets.DEPENDABOT_PAT }} 22 | 23 | - uses: ahmadnassri/action-dependabot-auto-merge@v2 24 | with: 25 | github-token: ${{ secrets.DEPENDABOT_PAT }} 26 | target: all -------------------------------------------------------------------------------- /.github/workflows/dockerhub-push.yml: -------------------------------------------------------------------------------- 1 | name: 🌥 Docker Push 2 | 3 | on: 4 | workflow_run: 5 | workflows: ["🎉 Release Binary"] 6 | types: 7 | - completed 8 | workflow_dispatch: 9 | 10 | jobs: 11 | docker: 12 | runs-on: ubuntu-latest-16-cores 13 | steps: 14 | - name: Git Checkout 15 | uses: actions/checkout@v3 16 | 17 | - name: Get Github tag 18 | id: meta 19 | run: | 20 | curl --silent "https://api.github.com/repos/projectdiscovery/cvemap/releases/latest" | jq -r .tag_name | xargs -I {} echo TAG={} >> $GITHUB_OUTPUT 21 | 22 | - name: Set up QEMU 23 | uses: docker/setup-qemu-action@v2 24 | 25 | - name: Set up Docker Buildx 26 | uses: docker/setup-buildx-action@v2 27 | 28 | - name: Login to DockerHub 29 | uses: docker/login-action@v2 30 | with: 31 | username: ${{ secrets.DOCKER_USERNAME }} 32 | password: ${{ secrets.DOCKER_TOKEN }} 33 | 34 | - name: Build and push 35 | uses: docker/build-push-action@v4 36 | with: 37 | context: . 38 | platforms: linux/amd64,linux/arm64,linux/arm 39 | push: true 40 | tags: projectdiscovery/cvemap:latest,projectdiscovery/cvemap:${{ steps.meta.outputs.TAG }} -------------------------------------------------------------------------------- /.github/workflows/lint-test.yml: -------------------------------------------------------------------------------- 1 | name: 🙏🏻 Lint Test 2 | 3 | on: 4 | pull_request: 5 | paths: 6 | - '**.go' 7 | - '**.mod' 8 | workflow_dispatch: 9 | 10 | jobs: 11 | lint: 12 | name: Lint Test 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Checkout code 16 | uses: actions/checkout@v3 17 | 18 | - name: "Set up Go" 19 | uses: actions/setup-go@v4 20 | with: 21 | go-version: 1.21.x 22 | 23 | - name: Run golangci-lint 24 | uses: golangci/golangci-lint-action@v3.6.0 25 | with: 26 | version: latest 27 | args: --timeout 5m 28 | working-directory: . -------------------------------------------------------------------------------- /.github/workflows/release-binary.yml: -------------------------------------------------------------------------------- 1 | name: 🎉 Release Binary 2 | on: 3 | push: 4 | tags: 5 | - '*' 6 | workflow_dispatch: 7 | 8 | jobs: 9 | release: 10 | runs-on: ubuntu-latest-16-cores 11 | steps: 12 | - name: "Check out code" 13 | uses: actions/checkout@v3 14 | with: 15 | fetch-depth: 0 16 | 17 | - name: "Set up Go" 18 | uses: actions/setup-go@v4 19 | with: 20 | go-version: 1.21.x 21 | 22 | - name: "Create release on GitHub" 23 | uses: goreleaser/goreleaser-action@v4 24 | with: 25 | args: "release --clean" 26 | version: latest 27 | workdir: . 28 | env: 29 | GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" 30 | SLACK_WEBHOOK: "${{ secrets.RELEASE_SLACK_WEBHOOK }}" 31 | DISCORD_WEBHOOK_ID: "${{ secrets.DISCORD_WEBHOOK_ID }}" 32 | DISCORD_WEBHOOK_TOKEN: "${{ secrets.DISCORD_WEBHOOK_TOKEN }}" -------------------------------------------------------------------------------- /.github/workflows/release-test.yml: -------------------------------------------------------------------------------- 1 | name: 🔨 Release Test 2 | 3 | on: 4 | pull_request: 5 | paths: 6 | - '**.go' 7 | - '**.mod' 8 | - '**.yml' 9 | workflow_dispatch: 10 | 11 | jobs: 12 | release-test: 13 | runs-on: ubuntu-latest-16-cores 14 | steps: 15 | - name: "Check out code" 16 | uses: actions/checkout@v3 17 | with: 18 | fetch-depth: 0 19 | 20 | - name: Set up Go 21 | uses: actions/setup-go@v4 22 | with: 23 | go-version: 1.21.x 24 | 25 | - name: release test 26 | uses: goreleaser/goreleaser-action@v4 27 | with: 28 | args: "release --clean --snapshot" 29 | version: latest 30 | workdir: . -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # If you prefer the allow list template instead of the deny list, see community template: 2 | # https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore 3 | # 4 | # Binaries for programs and plugins 5 | *.exe 6 | *.exe~ 7 | *.dll 8 | *.so 9 | *.dylib 10 | 11 | # Test binary, built with `go test -c` 12 | *.test 13 | 14 | # Output of the go coverage tool, specifically when used with LiteIDE 15 | *.out 16 | 17 | # Dependency directories (remove the comment below to include it) 18 | # vendor/ 19 | 20 | # Go workspace file 21 | go.work 22 | /cvemap 23 | /cmd/cvemap/cvemap 24 | -------------------------------------------------------------------------------- /.goreleaser.yml: -------------------------------------------------------------------------------- 1 | before: 2 | hooks: 3 | - go mod tidy 4 | 5 | builds: 6 | - env: 7 | - CGO_ENABLED=0 8 | goos: 9 | - windows 10 | - linux 11 | - darwin 12 | goarch: 13 | - amd64 14 | - 386 15 | - arm 16 | - arm64 17 | 18 | ignore: 19 | - goos: darwin 20 | goarch: '386' 21 | - goos: windows 22 | goarch: 'arm' 23 | - goos: windows 24 | goarch: 'arm64' 25 | 26 | binary: '{{ .ProjectName }}' 27 | main: cmd/cvemap/main.go 28 | 29 | archives: 30 | - format: zip 31 | name_template: '{{ .ProjectName }}_{{ .Version }}_{{ if eq .Os "darwin" }}macOS{{ else }}{{ .Os }}{{ end }}_{{ .Arch }}' 32 | 33 | checksum: 34 | algorithm: sha256 35 | 36 | announce: 37 | slack: 38 | enabled: true 39 | channel: '#release' 40 | username: GoReleaser 41 | message_template: 'New Release: {{ .ProjectName }} {{.Tag}} is published! Check it out at {{ .ReleaseURL }}' 42 | 43 | discord: 44 | enabled: true 45 | message_template: '**New Release: {{ .ProjectName }} {{.Tag}}** is published! Check it out at {{ .ReleaseURL }}' -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Base 2 | FROM golang:1.22.5-alpine AS builder 3 | RUN apk add --no-cache build-base 4 | WORKDIR /app 5 | COPY . /app 6 | RUN go mod download 7 | RUN go build ./cmd/cvemap 8 | 9 | # Release 10 | FROM alpine:3.18.2 11 | RUN apk -U upgrade --no-cache \ 12 | && apk add --no-cache bind-tools ca-certificates 13 | COPY --from=builder /app/cvemap /usr/local/bin/ 14 | 15 | ENTRYPOINT ["cvemap"] 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 ProjectDiscovery 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Go parameters 2 | GOCMD=go 3 | GOBUILD=$(GOCMD) build 4 | GOMOD=$(GOCMD) mod 5 | GOTEST=$(GOCMD) test 6 | GOFLAGS := -v 7 | # This should be disabled if the binary uses pprof 8 | LDFLAGS := -s -w 9 | 10 | ifneq ($(shell go env GOOS),darwin) 11 | LDFLAGS := -extldflags "-static" 12 | endif 13 | 14 | all: build 15 | build: 16 | $(GOBUILD) $(GOFLAGS) -ldflags '$(LDFLAGS)' -o "cvemap" cmd/cvemap/main.go 17 | integration: 18 | cd cmd/integration-test; bash run.sh 19 | tidy: 20 | $(GOMOD) tidy 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

CVEMap

2 | 3 |

4 | 5 | 6 | 7 | 8 | 9 | 10 |

11 |

12 | Features • 13 | Installation • 14 | Usage • 15 | Example • 16 | Join Discord 17 |

18 | 19 | Navigate the Common Vulnerabilities and Exposures (CVE) jungle with ease using CVEMAP, a command-line interface (CLI) tool designed to provide a structured and easily navigable interface to various vulnerability databases. 20 | 21 | 22 | # Features 23 | 24 | ![image](static/cvemap.png) 25 | 26 | - **CVE Dataset Search & Query** 27 | - **CVE to EPSS Mapping** 28 | - **CVE to KEV Mapping** 29 | - **CVE to CPE Mapping** 30 | - **CVE to GitHub POCs Mapping** 31 | - **CVE to Nuclei Template Mapping** 32 | - **CVE to HackerOne report Mapping** 33 | - Customizable Filters on CVE data 34 | - STDIN Input / JSONL Output 35 | 36 | 37 | ## Installation 38 | 39 | cvemap requires **Go 1.21** to install successfully. To install, just run the below command or download pre-compiled binary from [release page](https://github.com/projectdiscovery/cvemap/releases). 40 | 41 | ```console 42 | go install github.com/projectdiscovery/cvemap/cmd/cvemap@latest 43 | ``` 44 | 45 | ## Usage 46 | ```console 47 | cvemap -h 48 | ``` 49 | This will display help for the tool. Here are all the switches it supports. 50 | 51 | ```console 52 | Usage: 53 | cvemap [flags] 54 | 55 | Flags: 56 | CONFIG: 57 | -auth configure projectdiscovery cloud (pdcp) api key (default true) 58 | 59 | OPTIONS: 60 | -id string[] cve to list for given id 61 | -cwe, -cwe-id string[] cve to list for given cwe id 62 | -v, -vendor string[] cve to list for given vendor 63 | -p, -product string[] cve to list for given product 64 | -eproduct string[] cves to exclude based on products 65 | -s, -severity string[] cve to list for given severity 66 | -cs, -cvss-score string[] cve to list for given cvss score 67 | -c, -cpe string cve to list for given cpe 68 | -es, -epss-score string cve to list for given epss score 69 | -ep, -epss-percentile string[] cve to list for given epss percentile 70 | -age string cve to list published by given age in days 71 | -a, -assignee string[] cve to list for given publisher assignee 72 | -vs, -vstatus value cve to list for given vulnerability status in cli output. supported: new, confirmed, unconfirmed, modified, rejected, unknown 73 | 74 | UPDATE: 75 | -up, -update update cvemap to latest version 76 | -duc, -disable-update-check disable automatic cvemap update check 77 | 78 | FILTER: 79 | -q, -search string search in cve data 80 | -k, -kev display cves marked as exploitable vulnerabilities by cisa (default true) 81 | -t, -template display cves that has public nuclei templates (default true) 82 | -poc display cves that has public published poc (default true) 83 | -h1, -hackerone display cves reported on hackerone (default true) 84 | -re, -remote display remotely exploitable cves (AV:N & PR:N | PR:L) (default true) 85 | 86 | OUTPUT: 87 | -f, -field value fields to display in cli output. supported: product, vendor, assignee, age, poc, cwe, epss, vstatus, kev, template 88 | -fe, -exclude value fields to exclude from cli output. supported: product, vendor, assignee, age, poc, cwe, epss, vstatus, kev, template 89 | -lsi, -list-id list only the cve ids in the output 90 | -l, -limit int limit the number of results to display (default 50) 91 | -offset int offset the results to display 92 | -j, -json return output in json format 93 | -epk, -enable-page-keys enable page keys to navigate results 94 | 95 | DEBUG: 96 | -version Version 97 | -silent Silent 98 | -verbose Verbose 99 | -debug Debug 100 | -hc, -health-check run diagnostic check up 101 | ``` 102 | 103 | ## Configuring CVEMap CLI 104 | 105 | CVEMap CLI is built on top of the CVEMap API that requires API Token from [ProjectDiscovery Cloud Platform](https://cloud.projectdiscovery.io/?ref=api_key) that can be configured using environment variable named `PDCP_API_KEY` or using interactive `-auth` option as shown below. 106 | 107 | ### Using environment variable 108 | 109 | ```console 110 | export PDCP_API_KEY=************* 111 | ``` 112 | 113 | ### Using auth option 114 | 115 | ```console 116 | cvemap -auth 117 | 118 | 119 | ______ _____ ____ ___ ____ ____ 120 | / ___/ | / / _ \/ __ \__ \/ __ \/ __ \ 121 | / /__ | |/ / __/ / / / / / /_/ / /_/ / 122 | \___/ |___/\___/_/ /_/ /_/\__,_/ .___/ 123 | /_/ 124 | 125 | 126 | projectdiscovery.io 127 | 128 | [INF] Get your free api key by signing up at https://cloud.projectdiscovery.io 129 | [*] Enter PDCP API Key (exit to abort): ************* 130 | [INF] Successfully logged in as (@user) 131 | ``` 132 | 133 | ## Running CVEMap 134 | 135 | For details about running cvemap, see https://docs.projectdiscovery.io/tools/cvemap/running. 136 | 137 | 138 | ## Note 139 | 140 | - CVE dataset gets updated in every 6 hours. 141 | 142 | ## References 143 | 144 | - **[National Vulnerability Database (NVD)](https://nvd.nist.gov/developers)**: Comprehensive CVE vulnerability data. 145 | - **[Known Exploited Vulnerabilities Catalog (KEV)](https://www.cisa.gov/known-exploited-vulnerabilities-catalog)**: Exploited vulnerabilities catalog. 146 | - **[Exploit Prediction Scoring System (EPSS)](https://www.first.org/epss/data_stats)**: Exploit prediction scores. 147 | - **[HackerOne](https://hackerone.com/hacktivity/cve_discovery)**: CVE discoveries disclosure. 148 | - **[Nuclei Templates](https://github.com/projectdiscovery/nuclei-templates)**: Vulnerability validation templates. 149 | - **[Trickest CVE](https://github.com/trickest/cve) / [PoC-in-GitHub](https://github.com/nomi-sec/PoC-in-GitHub/)** GitHub Repository: Vulnerability PoCs references. 150 | -------- 151 | 152 |
153 | 154 | **cvemap** is made with ❤️ by the [projectdiscovery](https://projectdiscovery.io) team and distributed under [MIT License](LICENSE). 155 | 156 | 157 | Join Discord -------------------------------------------------------------------------------- /cmd/cvemap/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/projectdiscovery/cvemap/pkg/runner" 5 | "github.com/projectdiscovery/gologger" 6 | ) 7 | 8 | func main() { 9 | options := runner.ParseOptions() 10 | runner, err := runner.New(options) 11 | if err != nil { 12 | gologger.Fatal().Msgf("Could not create runner: %s\n", err) 13 | } 14 | runner.Run() 15 | } 16 | -------------------------------------------------------------------------------- /cmd/integration-test/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "os" 7 | "strings" 8 | 9 | "github.com/logrusorgru/aurora" 10 | "github.com/pkg/errors" 11 | "github.com/projectdiscovery/cvemap/pkg/testutils" 12 | ) 13 | 14 | var ( 15 | xPDCPHeaderTestKey = "test-67291d9a-0aa6-49b1-b249-2b9d4b45bcea" 16 | debug = os.Getenv("DEBUG") == "true" 17 | success = aurora.Green("[✓]").String() 18 | failed = aurora.Red("[✘]").String() 19 | currentCvemapBinary = flag.String("current", "", "Current Branch Cvemap Binary") 20 | ) 21 | 22 | func main() { 23 | flag.Parse() 24 | SetupMockServer() 25 | os.Setenv("CVEMAP_API_URL", "http://localhost:8080/api/v1") 26 | os.Setenv("PDCP_API_KEY", xPDCPHeaderTestKey) 27 | if err := runIntegrationTests(); err != nil { 28 | fmt.Println("Error running integration tests:", err) 29 | } 30 | } 31 | 32 | var testCases = map[string]testutils.TestCase{ 33 | "Get By cve_id": &CveIDTestCase{}, 34 | } 35 | 36 | type CveIDTestCase struct{} 37 | 38 | func (c *CveIDTestCase) Execute() error { 39 | currentOutput, err := testutils.RunCvemapBinaryAndGetResults(*currentCvemapBinary, debug, []string{"-id", "CVE-1999-0027", "-j", "-silent"}) 40 | if err != nil { 41 | return errors.Wrap(err, "could not run cvemap test") 42 | } 43 | if len(currentOutput) == 0 { 44 | return errors.New("no output from cvemap") 45 | } 46 | if strings.Contains(strings.Join(currentOutput, ""), `"cve_id": "CVE-1999-0027"`) { 47 | return nil 48 | } 49 | return errors.New("cve_id not found in output") 50 | } 51 | 52 | func runIntegrationTests() error { 53 | 54 | for testName, testcase := range testCases { 55 | if err := testcase.Execute(); err != nil { 56 | fmt.Fprintf(os.Stderr, "%s Test \"%s\" failed: %s\n", failed, testName, err) 57 | } else { 58 | fmt.Printf("%s Test \"%s\" passed!\n", success, testName) 59 | } 60 | } 61 | return nil 62 | } 63 | -------------------------------------------------------------------------------- /cmd/integration-test/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # reading os type from arguments 4 | CURRENT_OS=$1 5 | 6 | if [ "${CURRENT_OS}" == "windows-latest" ];then 7 | extension=.exe 8 | fi 9 | 10 | echo "::group::Building integration-test binary" 11 | go build -o integration-test$extension 12 | echo "::endgroup::" 13 | 14 | echo "::group::Building cvemap binary from current branch" 15 | go build -o cvemap$extension ../cvemap 16 | echo "::endgroup::" 17 | 18 | 19 | echo 'Starting cvemap integration test' 20 | ./integration-test$extension -current cvemap$extension 21 | -------------------------------------------------------------------------------- /cmd/integration-test/server.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "net/http" 7 | "os" 8 | 9 | "github.com/projectdiscovery/cvemap/pkg/types" 10 | ) 11 | 12 | var cveData *types.CVEBulkData 13 | 14 | func SetupMockServer() { 15 | var err error 16 | // Load data from the JSON file 17 | cveData, err = loadData("test-data.json") 18 | if err != nil { 19 | fmt.Println("Error loading data:", err) 20 | return 21 | } 22 | // Setup HTTP server 23 | http.HandleFunc("/api/v1/cves", RequireAPIKey(http.HandlerFunc(handleRequest))) 24 | 25 | go func() { 26 | // Start the server on port 8080 27 | fmt.Println("Cvemap test server listening on 8080...") 28 | if err := http.ListenAndServe(":8080", nil); err != nil { 29 | fmt.Println("Error starting server:", err) 30 | } 31 | }() 32 | } 33 | 34 | // RequireAPIKey is a middleware that checks for the X-PDCP-Key header. 35 | func RequireAPIKey(next http.HandlerFunc) http.HandlerFunc { 36 | return func(w http.ResponseWriter, r *http.Request) { 37 | apiKey := r.Header.Get("X-PDCP-Key") 38 | if apiKey != xPDCPHeaderTestKey { 39 | http.Error(w, "Unauthorized: X-PDCP-Key header is required", http.StatusUnauthorized) 40 | return 41 | } 42 | next(w, r) 43 | } 44 | } 45 | 46 | // handleRequest handles HTTP requests. 47 | func handleRequest(w http.ResponseWriter, r *http.Request) { 48 | // Handle the case where "cve_id" is a query parameter 49 | cveID := r.URL.Query().Get("cve_id") 50 | if cveID == "" { 51 | http.NotFound(w, r) 52 | } 53 | for _, data := range cveData.Cves { 54 | if data.CveID == cveID { 55 | // Return the data corresponding to the given CVE ID 56 | if err := json.NewEncoder(w).Encode(cveData); err != nil { 57 | http.Error(w, err.Error(), http.StatusInternalServerError) 58 | } 59 | return 60 | } 61 | } 62 | http.NotFound(w, r) 63 | } 64 | 65 | // LoadData loads data from a JSON file into a slice of CVEData. 66 | func loadData(filename string) (*types.CVEBulkData, error) { 67 | file, err := os.Open(filename) 68 | if err != nil { 69 | return nil, err 70 | } 71 | defer file.Close() 72 | 73 | var data types.CVEBulkData 74 | decoder := json.NewDecoder(file) 75 | if err := decoder.Decode(&data); err != nil { 76 | return nil, err 77 | } 78 | 79 | return &data, nil 80 | } 81 | -------------------------------------------------------------------------------- /cmd/integration-test/test-data.json: -------------------------------------------------------------------------------- 1 | { 2 | "result_count": 1, 3 | "total_results": 1, 4 | "cves": [ 5 | { 6 | "cpe": { 7 | "cpe": "cpe:2.3:o:sgi:irix:*:*:*:*:*:*:*:*", 8 | "vendor": "sgi", 9 | "product": "irix" 10 | }, 11 | "epss": { 12 | "epss_score": 0.00064, 13 | "epss_percentile": 0.26181 14 | }, 15 | "cve_id": "CVE-1999-0027", 16 | "is_oss": false, 17 | "is_poc": false, 18 | "assignee": "cve@mitre.org", 19 | "severity": "high", 20 | "hackerone": { 21 | "rank": 6320, 22 | "count": 0 23 | }, 24 | "is_remote": false, 25 | "reference": [ 26 | "https://exchange.xforce.ibmcloud.com/vulnerabilities/CVE-1999-0027", 27 | "https://github.com/Kuromesi/Py4CSKG" 28 | ], 29 | "cvss_score": 7.2, 30 | "updated_at": "2022-08-17T07:15:08.580", 31 | "weaknesses": [ 32 | { 33 | "cwe_id": "CWE-119", 34 | "cwe_name": "Improper Restriction of Operations within the Bounds of a Memory Buffer" 35 | } 36 | ], 37 | "age_in_days": 9682, 38 | "is_template": false, 39 | "vuln_status": "modified", 40 | "cvss_metrics": { 41 | "cvss2": { 42 | "score": 7.2, 43 | "vector": "CVSS:2.0/AV:L/AC:L/Au:N/C:C/I:C/A:C", 44 | "severity": "high" 45 | } 46 | }, 47 | "is_exploited": false, 48 | "published_at": "1997-07-16T04:00:00.000", 49 | "vulnerable_cpe": [ 50 | "cpe:2.3:o:sgi:irix:*:*:*:*:*:*:*:*" 51 | ], 52 | "cve_description": "root privileges via buffer overflow in eject command on SGI IRIX systems.", 53 | "vendor_advisory": "" 54 | } 55 | ] 56 | } -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/projectdiscovery/cvemap 2 | 3 | go 1.21 4 | 5 | require ( 6 | github.com/eiannone/keyboard v0.0.0-20220611211555-0d226195f203 7 | github.com/jedib0t/go-pretty/v6 v6.6.7 8 | github.com/logrusorgru/aurora v2.0.3+incompatible 9 | github.com/pkg/errors v0.9.1 10 | github.com/projectdiscovery/goflags v0.1.71 11 | github.com/projectdiscovery/gologger v1.1.43 12 | github.com/projectdiscovery/retryablehttp-go v1.0.98 13 | github.com/projectdiscovery/utils v0.4.9 14 | ) 15 | 16 | require ( 17 | aead.dev/minisign v0.2.1 // indirect 18 | github.com/Masterminds/semver/v3 v3.2.1 // indirect 19 | github.com/Mzack9999/gcache v0.0.0-20230410081825-519e28eab057 // indirect 20 | github.com/Mzack9999/go-http-digest-auth-client v0.6.1-0.20220414142836-eb8883508809 // indirect 21 | github.com/VividCortex/ewma v1.2.0 // indirect 22 | github.com/akrylysov/pogreb v0.10.2 // indirect 23 | github.com/alecthomas/chroma/v2 v2.14.0 // indirect 24 | github.com/andybalholm/brotli v1.1.0 // indirect 25 | github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect 26 | github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect 27 | github.com/aymerick/douceur v0.2.0 // indirect 28 | github.com/bits-and-blooms/bitset v1.13.0 // indirect 29 | github.com/bits-and-blooms/bloom/v3 v3.6.0 // indirect 30 | github.com/charmbracelet/glamour v0.8.0 // indirect 31 | github.com/charmbracelet/lipgloss v0.13.0 // indirect 32 | github.com/charmbracelet/x/ansi v0.3.2 // indirect 33 | github.com/cheggaaa/pb/v3 v3.1.5 // indirect 34 | github.com/cloudflare/circl v1.3.7 // indirect 35 | github.com/cnf/structhash v0.0.0-20201127153200-e1b16c1ebc08 // indirect 36 | github.com/dimchansky/utfbom v1.1.1 // indirect 37 | github.com/dlclark/regexp2 v1.11.4 // indirect 38 | github.com/docker/go-units v0.5.0 // indirect 39 | github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 // indirect 40 | github.com/fatih/color v1.16.0 // indirect 41 | github.com/gaissmai/bart v0.9.5 // indirect 42 | github.com/go-ole/go-ole v1.2.6 // indirect 43 | github.com/golang/protobuf v1.5.3 // indirect 44 | github.com/golang/snappy v0.0.4 // indirect 45 | github.com/google/go-github/v30 v30.1.0 // indirect 46 | github.com/google/go-querystring v1.1.0 // indirect 47 | github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect 48 | github.com/google/uuid v1.3.1 // indirect 49 | github.com/gorilla/css v1.0.1 // indirect 50 | github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect 51 | github.com/json-iterator/go v1.1.12 // indirect 52 | github.com/klauspost/compress v1.17.5 // indirect 53 | github.com/klauspost/pgzip v1.2.6 // indirect 54 | github.com/lucasb-eyer/go-colorful v1.2.0 // indirect 55 | github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect 56 | github.com/mattn/go-colorable v0.1.13 // indirect 57 | github.com/mattn/go-isatty v0.0.20 // indirect 58 | github.com/mattn/go-runewidth v0.0.16 // indirect 59 | github.com/mholt/archiver/v3 v3.5.1 // indirect 60 | github.com/microcosm-cc/bluemonday v1.0.27 // indirect 61 | github.com/miekg/dns v1.1.58 // indirect 62 | github.com/minio/selfupdate v0.6.1-0.20230907112617-f11e74f84ca7 // indirect 63 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 64 | github.com/modern-go/reflect2 v1.0.2 // indirect 65 | github.com/muesli/reflow v0.3.0 // indirect 66 | github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a // indirect 67 | github.com/nwaples/rardecode v1.1.3 // indirect 68 | github.com/pierrec/lz4/v4 v4.1.21 // indirect 69 | github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect 70 | github.com/projectdiscovery/blackrock v0.0.1 // indirect 71 | github.com/projectdiscovery/fastdialer v0.3.0 // indirect 72 | github.com/projectdiscovery/hmap v0.0.77 // indirect 73 | github.com/projectdiscovery/machineid v0.0.0-20240226150047-2e2c51e35983 // indirect 74 | github.com/projectdiscovery/networkpolicy v0.1.1 // indirect 75 | github.com/projectdiscovery/retryabledns v1.0.94 // indirect 76 | github.com/refraction-networking/utls v1.6.7 // indirect 77 | github.com/rivo/uniseg v0.4.7 // indirect 78 | github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d // indirect 79 | github.com/shirou/gopsutil/v3 v3.23.7 // indirect 80 | github.com/shoenig/go-m1cpu v0.1.6 // indirect 81 | github.com/syndtr/goleveldb v1.0.0 // indirect 82 | github.com/tidwall/btree v1.7.0 // indirect 83 | github.com/tidwall/buntdb v1.3.0 // indirect 84 | github.com/tidwall/gjson v1.17.0 // indirect 85 | github.com/tidwall/grect v0.1.4 // indirect 86 | github.com/tidwall/match v1.1.1 // indirect 87 | github.com/tidwall/pretty v1.2.1 // indirect 88 | github.com/tidwall/rtred v0.1.2 // indirect 89 | github.com/tidwall/tinyqueue v0.1.1 // indirect 90 | github.com/tklauser/go-sysconf v0.3.12 // indirect 91 | github.com/tklauser/numcpus v0.6.1 // indirect 92 | github.com/ulikunitz/xz v0.5.11 // indirect 93 | github.com/weppos/publicsuffix-go v0.30.2-0.20230730094716-a20f9abcc222 // indirect 94 | github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect 95 | github.com/yuin/goldmark v1.7.4 // indirect 96 | github.com/yuin/goldmark-emoji v1.0.3 // indirect 97 | github.com/yusufpapurcu/wmi v1.2.4 // indirect 98 | github.com/zcalusic/sysinfo v1.0.2 // indirect 99 | github.com/zmap/rc2 v0.0.0-20190804163417-abaa70531248 // indirect 100 | github.com/zmap/zcrypto v0.0.0-20231219022726-a1f61fb1661c // indirect 101 | go.etcd.io/bbolt v1.3.8 // indirect 102 | go.uber.org/multierr v1.11.0 // indirect 103 | golang.org/x/crypto v0.31.0 // indirect 104 | golang.org/x/exp v0.0.0-20240119083558-1b970713d09a // indirect 105 | golang.org/x/mod v0.17.0 // indirect 106 | golang.org/x/net v0.33.0 // indirect 107 | golang.org/x/oauth2 v0.16.0 // indirect 108 | golang.org/x/sync v0.11.0 // indirect 109 | golang.org/x/sys v0.30.0 // indirect 110 | golang.org/x/term v0.29.0 // indirect 111 | golang.org/x/text v0.22.0 // indirect 112 | golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect 113 | google.golang.org/appengine v1.6.8 // indirect 114 | google.golang.org/protobuf v1.33.0 // indirect 115 | gopkg.in/djherbis/times.v1 v1.3.0 // indirect 116 | gopkg.in/yaml.v3 v3.0.1 // indirect 117 | ) 118 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | aead.dev/minisign v0.2.0/go.mod h1:zdq6LdSd9TbuSxchxwhpA9zEb9YXcVGoE8JakuiGaIQ= 2 | aead.dev/minisign v0.2.1 h1:Z+7HA9dsY/eGycYj6kpWHpcJpHtjAwGiJFvbiuO9o+M= 3 | aead.dev/minisign v0.2.1/go.mod h1:oCOjeA8VQNEbuSCFaaUXKekOusa/mll6WtMoO5JY4M4= 4 | cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= 5 | github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0= 6 | github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= 7 | github.com/Mzack9999/gcache v0.0.0-20230410081825-519e28eab057 h1:KFac3SiGbId8ub47e7kd2PLZeACxc1LkiiNoDOFRClE= 8 | github.com/Mzack9999/gcache v0.0.0-20230410081825-519e28eab057/go.mod h1:iLB2pivrPICvLOuROKmlqURtFIEsoJZaMidQfCG1+D4= 9 | github.com/Mzack9999/go-http-digest-auth-client v0.6.1-0.20220414142836-eb8883508809 h1:ZbFL+BDfBqegi+/Ssh7im5+aQfBRx6it+kHnC7jaDU8= 10 | github.com/Mzack9999/go-http-digest-auth-client v0.6.1-0.20220414142836-eb8883508809/go.mod h1:upgc3Zs45jBDnBT4tVRgRcgm26ABpaP7MoTSdgysca4= 11 | github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8/go.mod h1:I0gYDMZ6Z5GRU7l58bNFSkPTFN6Yl12dsUlAZ8xy98g= 12 | github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow= 13 | github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAUnGx7j5l4= 14 | github.com/akrylysov/pogreb v0.10.2 h1:e6PxmeyEhWyi2AKOBIJzAEi4HkiC+lKyCocRGlnDi78= 15 | github.com/akrylysov/pogreb v0.10.2/go.mod h1:pNs6QmpQ1UlTJKDezuRWmaqkgUE2TuU0YTWyqJZ7+lI= 16 | github.com/alecthomas/assert/v2 v2.7.0 h1:QtqSACNS3tF7oasA8CU6A6sXZSBDqnm7RfpLl9bZqbE= 17 | github.com/alecthomas/assert/v2 v2.7.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= 18 | github.com/alecthomas/chroma/v2 v2.14.0 h1:R3+wzpnUArGcQz7fCETQBzO5n9IMNi13iIs46aU4V9E= 19 | github.com/alecthomas/chroma/v2 v2.14.0/go.mod h1:QolEbTfmUHIMVpBqxeDnNBj2uoeI4EbYP4i6n68SG4I= 20 | github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc= 21 | github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= 22 | github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= 23 | github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= 24 | github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= 25 | github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= 26 | github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= 27 | github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= 28 | github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= 29 | github.com/aymanbagabas/go-udiff v0.2.0 h1:TK0fH4MteXUDspT88n8CKzvK0X9O2xu9yQjWpi6yML8= 30 | github.com/aymanbagabas/go-udiff v0.2.0/go.mod h1:RE4Ex0qsGkTAJoQdQQCA0uG+nAzJO/pI/QwceO5fgrA= 31 | github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= 32 | github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= 33 | github.com/bits-and-blooms/bitset v1.10.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= 34 | github.com/bits-and-blooms/bitset v1.13.0 h1:bAQ9OPNFYbGHV6Nez0tmNI0RiEu7/hxlYJRUA0wFAVE= 35 | github.com/bits-and-blooms/bitset v1.13.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= 36 | github.com/bits-and-blooms/bloom/v3 v3.6.0 h1:dTU0OVLJSoOhz9m68FTXMFfA39nR8U/nTCs1zb26mOI= 37 | github.com/bits-and-blooms/bloom/v3 v3.6.0/go.mod h1:VKlUSvp0lFIYqxJjzdnSsZEw4iHb1kOL2tfHTgyJBHg= 38 | github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= 39 | github.com/charmbracelet/glamour v0.8.0 h1:tPrjL3aRcQbn++7t18wOpgLyl8wrOHUEDS7IZ68QtZs= 40 | github.com/charmbracelet/glamour v0.8.0/go.mod h1:ViRgmKkf3u5S7uakt2czJ272WSg2ZenlYEZXT2x7Bjw= 41 | github.com/charmbracelet/lipgloss v0.13.0 h1:4X3PPeoWEDCMvzDvGmTajSyYPcZM4+y8sCA/SsA3cjw= 42 | github.com/charmbracelet/lipgloss v0.13.0/go.mod h1:nw4zy0SBX/F/eAO1cWdcvy6qnkDUxr8Lw7dvFrAIbbY= 43 | github.com/charmbracelet/x/ansi v0.3.2 h1:wsEwgAN+C9U06l9dCVMX0/L3x7ptvY1qmjMwyfE6USY= 44 | github.com/charmbracelet/x/ansi v0.3.2/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= 45 | github.com/charmbracelet/x/exp/golden v0.0.0-20240806155701-69247e0abc2a h1:G99klV19u0QnhiizODirwVksQB91TJKV/UaTnACcG30= 46 | github.com/charmbracelet/x/exp/golden v0.0.0-20240806155701-69247e0abc2a/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U= 47 | github.com/cheggaaa/pb/v3 v3.1.5 h1:QuuUzeM2WsAqG2gMqtzaWithDJv0i+i6UlnwSCI4QLk= 48 | github.com/cheggaaa/pb/v3 v3.1.5/go.mod h1:CrxkeghYTXi1lQBEI7jSn+3svI3cuc19haAj6jM60XI= 49 | github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I= 50 | github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= 51 | github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= 52 | github.com/cnf/structhash v0.0.0-20201127153200-e1b16c1ebc08 h1:ox2F0PSMlrAAiAdknSRMDrAr8mfxPCfSZolH+/qQnyQ= 53 | github.com/cnf/structhash v0.0.0-20201127153200-e1b16c1ebc08/go.mod h1:pCxVEbcm3AMg7ejXyorUXi6HQCzOIBf7zEDVPtw0/U4= 54 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 55 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 56 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 57 | github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U= 58 | github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE= 59 | github.com/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yAo= 60 | github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= 61 | github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= 62 | github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= 63 | github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 h1:iFaUwBSo5Svw6L7HYpRu/0lE3e0BaElwnNO1qkNQxBY= 64 | github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s= 65 | github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY= 66 | github.com/eiannone/keyboard v0.0.0-20220611211555-0d226195f203 h1:XBBHcIb256gUJtLmY22n99HaZTz+r2Z51xUPi01m3wg= 67 | github.com/eiannone/keyboard v0.0.0-20220611211555-0d226195f203/go.mod h1:E1jcSv8FaEny+OP/5k9UxZVw9YFWGj7eI4KR/iOBqCg= 68 | github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= 69 | github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= 70 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= 71 | github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= 72 | github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= 73 | github.com/gaissmai/bart v0.9.5 h1:vy+r4Px6bjZ+v2QYXAsg63vpz9IfzdW146A8Cn4GPIo= 74 | github.com/gaissmai/bart v0.9.5/go.mod h1:KHeYECXQiBjTzQz/om2tqn3sZF1J7hw9m6z41ftj3fg= 75 | github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= 76 | github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= 77 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 78 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 79 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 80 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 81 | github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= 82 | github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= 83 | github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= 84 | github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 85 | github.com/golang/snappy v0.0.2/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 86 | github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= 87 | github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 88 | github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 89 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 90 | github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 91 | github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 92 | github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 93 | github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= 94 | github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 95 | github.com/google/go-github/v30 v30.1.0 h1:VLDx+UolQICEOKu2m4uAoMti1SxuEBAl7RSEG16L+Oo= 96 | github.com/google/go-github/v30 v30.1.0/go.mod h1:n8jBpHl45a/rlBUtRJMOG4GhNADUQFEufcolZ95JfU8= 97 | github.com/google/go-github/v50 v50.2.0/go.mod h1:VBY8FB6yPIjrtKhozXv4FQupxKLS6H4m6xFZlT43q8Q= 98 | github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= 99 | github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= 100 | github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= 101 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 102 | github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= 103 | github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= 104 | github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= 105 | github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 106 | github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8= 107 | github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0= 108 | github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= 109 | github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= 110 | github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= 111 | github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= 112 | github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= 113 | github.com/jedib0t/go-pretty/v6 v6.6.7 h1:m+LbHpm0aIAPLzLbMfn8dc3Ht8MW7lsSO4MPItz/Uuo= 114 | github.com/jedib0t/go-pretty/v6 v6.6.7/go.mod h1:YwC5CE4fJ1HFUDeivSV1r//AmANFHyqczZk+U6BDALU= 115 | github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= 116 | github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 117 | github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= 118 | github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= 119 | github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= 120 | github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= 121 | github.com/klauspost/compress v1.17.5 h1:d4vBd+7CHydUqpFBgUEKkSdtSugf9YFmSkvUYPquI5E= 122 | github.com/klauspost/compress v1.17.5/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= 123 | github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= 124 | github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= 125 | github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU= 126 | github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= 127 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 128 | github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= 129 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 130 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 131 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 132 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 133 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 134 | github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= 135 | github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= 136 | github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= 137 | github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= 138 | github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= 139 | github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= 140 | github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= 141 | github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= 142 | github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= 143 | github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= 144 | github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 145 | github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= 146 | github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= 147 | github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= 148 | github.com/mholt/archiver/v3 v3.5.1 h1:rDjOBX9JSF5BvoJGvjqK479aL70qh9DIpZCl+k7Clwo= 149 | github.com/mholt/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4= 150 | github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk= 151 | github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA= 152 | github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4= 153 | github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY= 154 | github.com/minio/selfupdate v0.6.1-0.20230907112617-f11e74f84ca7 h1:yRZGarbxsRytL6EGgbqK2mCY+Lk5MWKQYKJT2gEglhc= 155 | github.com/minio/selfupdate v0.6.1-0.20230907112617-f11e74f84ca7/go.mod h1:bO02GTIPCMQFTEvE5h4DjYB58bCoZ35XLeBf0buTDdM= 156 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 157 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= 158 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 159 | github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= 160 | github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= 161 | github.com/mreiferson/go-httpclient v0.0.0-20160630210159-31f0106b4474/go.mod h1:OQA4XLvDbMgS8P0CevmM4m9Q3Jq4phKUzcocxuGJ5m8= 162 | github.com/mreiferson/go-httpclient v0.0.0-20201222173833-5e475fde3a4d/go.mod h1:OQA4XLvDbMgS8P0CevmM4m9Q3Jq4phKUzcocxuGJ5m8= 163 | github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s= 164 | github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8= 165 | github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a h1:2MaM6YC3mGu54x+RKAA6JiFFHlHDY1UbkxqppT7wYOg= 166 | github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a/go.mod h1:hxSnBBYLK21Vtq/PHd0S2FYCxBXzBua8ov5s1RobyRQ= 167 | github.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0= 168 | github.com/nwaples/rardecode v1.1.3 h1:cWCaZwfM5H7nAD6PyEdcVnczzV8i/JtotnyW/dD9lEc= 169 | github.com/nwaples/rardecode v1.1.3/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0= 170 | github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY= 171 | github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc= 172 | github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 173 | github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 174 | github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= 175 | github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= 176 | github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= 177 | github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= 178 | github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg= 179 | github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= 180 | github.com/pierrec/lz4/v4 v4.1.2/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= 181 | github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ= 182 | github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= 183 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 184 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 185 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 186 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 187 | github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= 188 | github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= 189 | github.com/projectdiscovery/blackrock v0.0.1 h1:lHQqhaaEFjgf5WkuItbpeCZv2DUIE45k0VbGJyft6LQ= 190 | github.com/projectdiscovery/blackrock v0.0.1/go.mod h1:ANUtjDfaVrqB453bzToU+YB4cUbvBRpLvEwoWIwlTss= 191 | github.com/projectdiscovery/fastdialer v0.3.0 h1:/wMptjdsrAU/wiaA/U3lSgYGaYCGJH6xm0mLei6oMxk= 192 | github.com/projectdiscovery/fastdialer v0.3.0/go.mod h1:Q0YLArvpx9GAfY/NcTPMCA9qZuVOGnuVoNYWzKBwxdQ= 193 | github.com/projectdiscovery/goflags v0.1.71 h1:CmgHQUEo2VCUOypIsSvIa4YlpzIQSIg2bmfyQXYoe48= 194 | github.com/projectdiscovery/goflags v0.1.71/go.mod h1:ikxJf0Jy7tQe13LpvTp0tanRAnqqYIlQlJaikSHnhY8= 195 | github.com/projectdiscovery/gologger v1.1.43 h1:26DOeBUK2xus/UpM8jzHfNqEU5tWams3VGBtjJtI02I= 196 | github.com/projectdiscovery/gologger v1.1.43/go.mod h1:993FxohnjVo34dSgE3bw+L4TOCDNQfQ5zNbK0YhYrEw= 197 | github.com/projectdiscovery/hmap v0.0.77 h1:pI7pmW+CN19LAkMsSFKC0K1SK1+sonto2hwte/7eOaQ= 198 | github.com/projectdiscovery/hmap v0.0.77/go.mod h1:LkV8r/enq9G9HnY2YzMpU4CCmFz3dstOlhmeaObVQfk= 199 | github.com/projectdiscovery/machineid v0.0.0-20240226150047-2e2c51e35983 h1:ZScLodGSezQVwsQDtBSMFp72WDq0nNN+KE/5DHKY5QE= 200 | github.com/projectdiscovery/machineid v0.0.0-20240226150047-2e2c51e35983/go.mod h1:3G3BRKui7nMuDFAZKR/M2hiOLtaOmyukT20g88qRQjI= 201 | github.com/projectdiscovery/networkpolicy v0.1.1 h1:iv9gECukD5KAZp98KVh+T3TEPTkY6dr3sKsdbh9XyZU= 202 | github.com/projectdiscovery/networkpolicy v0.1.1/go.mod h1:/Hg2ieLewSe/BagFF+UYXAQo3NwmVMq16MSAl492XkU= 203 | github.com/projectdiscovery/retryabledns v1.0.94 h1:MvxtRcmvxhxikxT7p/E40hcYRWRiL5fg/JQ8bpBaz+0= 204 | github.com/projectdiscovery/retryabledns v1.0.94/go.mod h1:croGTyMM4yNlrSWA/X7xNe3c0c7mDmCdbm8goLd8Bak= 205 | github.com/projectdiscovery/retryablehttp-go v1.0.98 h1:7wNj+vmx0z9FaQhtX/YRAMv4/1idj+bmFF07QvvEnIo= 206 | github.com/projectdiscovery/retryablehttp-go v1.0.98/go.mod h1:ZS4sDlqTP2YbydUcjqXECdb3AIFvrT466OvcZjN3GlY= 207 | github.com/projectdiscovery/utils v0.4.9 h1:GzYKy5iiCWEZZPGxrtgTOnRTZYiIAiCditGufp0nhGU= 208 | github.com/projectdiscovery/utils v0.4.9/go.mod h1:/68d0OHGgYF4aW4X7kS1qlFlYOnZxgtFDN85iH732JI= 209 | github.com/refraction-networking/utls v1.6.7 h1:zVJ7sP1dJx/WtVuITug3qYUq034cDq9B2MR1K67ULZM= 210 | github.com/refraction-networking/utls v1.6.7/go.mod h1:BC3O4vQzye5hqpmDTWUqi4P5DDhzJfkV1tdqtawQIH0= 211 | github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= 212 | github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= 213 | github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= 214 | github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= 215 | github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d h1:hrujxIzL1woJ7AwssoOcM/tq5JjjG2yYOc8odClEiXA= 216 | github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d/go.mod h1:uugorj2VCxiV1x+LzaIdVa9b4S4qGAcH6cbhh4qVxOU= 217 | github.com/shirou/gopsutil/v3 v3.23.7 h1:C+fHO8hfIppoJ1WdsVm1RoI0RwXoNdfTK7yWXV0wVj4= 218 | github.com/shirou/gopsutil/v3 v3.23.7/go.mod h1:c4gnmoRC0hQuaLqvxnx1//VXQ0Ms/X9UnJF8pddY5z4= 219 | github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= 220 | github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= 221 | github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= 222 | github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= 223 | github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= 224 | github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= 225 | github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= 226 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 227 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 228 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= 229 | github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= 230 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 231 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 232 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 233 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 234 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 235 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= 236 | github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= 237 | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= 238 | github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 239 | github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= 240 | github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= 241 | github.com/tidwall/assert v0.1.0 h1:aWcKyRBUAdLoVebxo95N7+YZVTFF/ASTr7BN4sLP6XI= 242 | github.com/tidwall/assert v0.1.0/go.mod h1:QLYtGyeqse53vuELQheYl9dngGCJQ+mTtlxcktb+Kj8= 243 | github.com/tidwall/btree v1.7.0 h1:L1fkJH/AuEh5zBnnBbmTwQ5Lt+bRJ5A8EWecslvo9iI= 244 | github.com/tidwall/btree v1.7.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EUQ2cKY= 245 | github.com/tidwall/buntdb v1.3.0 h1:gdhWO+/YwoB2qZMeAU9JcWWsHSYU3OvcieYgFRS0zwA= 246 | github.com/tidwall/buntdb v1.3.0/go.mod h1:lZZrZUWzlyDJKlLQ6DKAy53LnG7m5kHyrEHvvcDmBpU= 247 | github.com/tidwall/gjson v1.12.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= 248 | github.com/tidwall/gjson v1.17.0 h1:/Jocvlh98kcTfpN2+JzGQWQcqrPQwDrVEMApx/M5ZwM= 249 | github.com/tidwall/gjson v1.17.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= 250 | github.com/tidwall/grect v0.1.4 h1:dA3oIgNgWdSspFzn1kS4S/RDpZFLrIxAZOdJKjYapOg= 251 | github.com/tidwall/grect v0.1.4/go.mod h1:9FBsaYRaR0Tcy4UwefBX/UDcDcDy9V5jUcxHzv2jd5Q= 252 | github.com/tidwall/lotsa v1.0.2 h1:dNVBH5MErdaQ/xd9s769R31/n2dXavsQ0Yf4TMEHHw8= 253 | github.com/tidwall/lotsa v1.0.2/go.mod h1:X6NiU+4yHA3fE3Puvpnn1XMDrFZrE9JO2/w+UMuqgR8= 254 | github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= 255 | github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= 256 | github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= 257 | github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= 258 | github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= 259 | github.com/tidwall/rtred v0.1.2 h1:exmoQtOLvDoO8ud++6LwVsAMTu0KPzLTUrMln8u1yu8= 260 | github.com/tidwall/rtred v0.1.2/go.mod h1:hd69WNXQ5RP9vHd7dqekAz+RIdtfBogmglkZSRxCHFQ= 261 | github.com/tidwall/tinyqueue v0.1.1 h1:SpNEvEggbpyN5DIReaJ2/1ndroY8iyEGxPYxoSaymYE= 262 | github.com/tidwall/tinyqueue v0.1.1/go.mod h1:O/QNHwrnjqr6IHItYrzoHAKYhBkLI67Q096fQP5zMYw= 263 | github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI= 264 | github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= 265 | github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= 266 | github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4= 267 | github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= 268 | github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= 269 | github.com/twmb/murmur3 v1.1.6/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ= 270 | github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= 271 | github.com/ulikunitz/xz v0.5.9/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= 272 | github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8= 273 | github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= 274 | github.com/weppos/publicsuffix-go v0.13.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k= 275 | github.com/weppos/publicsuffix-go v0.30.2-0.20230730094716-a20f9abcc222 h1:h2JizvZl9aIj6za9S5AyrkU+OzIS4CetQthH/ejO+lg= 276 | github.com/weppos/publicsuffix-go v0.30.2-0.20230730094716-a20f9abcc222/go.mod h1:s41lQh6dIsDWIC1OWh7ChWJXLH0zkJ9KHZVqA7vHyuQ= 277 | github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo= 278 | github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= 279 | github.com/yl2chen/cidranger v1.0.2 h1:lbOWZVCG1tCRX4u24kuM1Tb4nHqWkDxwLdoS+SevawU= 280 | github.com/yl2chen/cidranger v1.0.2/go.mod h1:9U1yz7WPYDwf0vpNWFaeRh0bjwz5RVgRy/9UEQfHl0g= 281 | github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= 282 | github.com/yuin/goldmark v1.7.1/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= 283 | github.com/yuin/goldmark v1.7.4 h1:BDXOHExt+A7gwPCJgPIIq7ENvceR7we7rOS9TNoLZeg= 284 | github.com/yuin/goldmark v1.7.4/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= 285 | github.com/yuin/goldmark-emoji v1.0.3 h1:aLRkLHOuBR2czCY4R8olwMjID+tENfhyFDMCRhbIQY4= 286 | github.com/yuin/goldmark-emoji v1.0.3/go.mod h1:tTkZEbwu5wkPmgTcitqddVxY9osFZiavD+r4AzQrh1U= 287 | github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= 288 | github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= 289 | github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= 290 | github.com/zcalusic/sysinfo v1.0.2 h1:nwTTo2a+WQ0NXwo0BGRojOJvJ/5XKvQih+2RrtWqfxc= 291 | github.com/zcalusic/sysinfo v1.0.2/go.mod h1:kluzTYflRWo6/tXVMJPdEjShsbPpsFRyy+p1mBQPC30= 292 | github.com/zmap/rc2 v0.0.0-20131011165748-24b9757f5521/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE= 293 | github.com/zmap/rc2 v0.0.0-20190804163417-abaa70531248 h1:Nzukz5fNOBIHOsnP+6I79kPx3QhLv8nBy2mfFhBRq30= 294 | github.com/zmap/rc2 v0.0.0-20190804163417-abaa70531248/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE= 295 | github.com/zmap/zcertificate v0.0.0-20180516150559-0e3d58b1bac4/go.mod h1:5iU54tB79AMBcySS0R2XIyZBAVmeHranShAFELYx7is= 296 | github.com/zmap/zcertificate v0.0.1/go.mod h1:q0dlN54Jm4NVSSuzisusQY0hqDWvu92C+TWveAxiVWk= 297 | github.com/zmap/zcrypto v0.0.0-20201128221613-3719af1573cf/go.mod h1:aPM7r+JOkfL+9qSB4KbYjtoEzJqUK50EXkkJabeNJDQ= 298 | github.com/zmap/zcrypto v0.0.0-20201211161100-e54a5822fb7e/go.mod h1:aPM7r+JOkfL+9qSB4KbYjtoEzJqUK50EXkkJabeNJDQ= 299 | github.com/zmap/zcrypto v0.0.0-20231219022726-a1f61fb1661c h1:U1b4THKcgOpJ+kILupuznNwPiURtwVW3e9alJvji9+s= 300 | github.com/zmap/zcrypto v0.0.0-20231219022726-a1f61fb1661c/go.mod h1:GSDpFDD4TASObxvfZfvpZZ3OWHIUHMlhVWlkOe4ewVk= 301 | github.com/zmap/zlint/v3 v3.0.0/go.mod h1:paGwFySdHIBEMJ61YjoqT4h7Ge+fdYG4sUQhnTb1lJ8= 302 | go.etcd.io/bbolt v1.3.8 h1:xs88BrvEv273UsB79e0hcVrlUWmS0a8upikMFhSyAtA= 303 | go.etcd.io/bbolt v1.3.8/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= 304 | go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= 305 | go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= 306 | golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 307 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 308 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 309 | golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= 310 | golang.org/x/crypto v0.0.0-20201208171446-5f87f3452ae9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= 311 | golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= 312 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 313 | golang.org/x/crypto v0.0.0-20211209193657-4570a0811e8b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= 314 | golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= 315 | golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= 316 | golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= 317 | golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= 318 | golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= 319 | golang.org/x/exp v0.0.0-20240119083558-1b970713d09a h1:Q8/wZp0KX97QFTc2ywcOE0YRjZPVIx+MXInMzdvQqcA= 320 | golang.org/x/exp v0.0.0-20240119083558-1b970713d09a/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08= 321 | golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= 322 | golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= 323 | golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= 324 | golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= 325 | golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 326 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 327 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 328 | golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= 329 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 330 | golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 331 | golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 332 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 333 | golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 334 | golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= 335 | golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= 336 | golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= 337 | golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= 338 | golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= 339 | golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= 340 | golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= 341 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 342 | golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= 343 | golang.org/x/oauth2 v0.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ= 344 | golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o= 345 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 346 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 347 | golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 348 | golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 349 | golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= 350 | golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 351 | golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 352 | golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 353 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 354 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 355 | golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 356 | golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 357 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 358 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 359 | golang.org/x/sys v0.0.0-20201126233918-771906719818/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 360 | golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 361 | golang.org/x/sys v0.0.0-20210228012217-479acdf4ea46/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 362 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 363 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 364 | golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 365 | golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 366 | golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 367 | golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 368 | golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 369 | golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 370 | golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 371 | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 372 | golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 373 | golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 374 | golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 375 | golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 376 | golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= 377 | golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 378 | golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= 379 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 380 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 381 | golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= 382 | golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= 383 | golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= 384 | golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= 385 | golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= 386 | golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU= 387 | golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s= 388 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 389 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 390 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 391 | golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 392 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 393 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 394 | golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= 395 | golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= 396 | golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= 397 | golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= 398 | golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= 399 | golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= 400 | golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= 401 | golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= 402 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 403 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 404 | golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= 405 | golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= 406 | golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= 407 | golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= 408 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 409 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 410 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 411 | google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 412 | google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= 413 | google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= 414 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= 415 | google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= 416 | google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= 417 | google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= 418 | google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= 419 | google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= 420 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 421 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 422 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= 423 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= 424 | gopkg.in/djherbis/times.v1 v1.3.0 h1:uxMS4iMtH6Pwsxog094W0FYldiNnfY/xba00vq6C2+o= 425 | gopkg.in/djherbis/times.v1 v1.3.0/go.mod h1:AQlg6unIsrsCEdQYhTzERy542dz6SFdQFZFv6mUY0P8= 426 | gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= 427 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= 428 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= 429 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 430 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 431 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 432 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 433 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 434 | -------------------------------------------------------------------------------- /pkg/runner/banner.go: -------------------------------------------------------------------------------- 1 | package runner 2 | 3 | import ( 4 | "github.com/projectdiscovery/gologger" 5 | "github.com/projectdiscovery/utils/auth/pdcp" 6 | updateutils "github.com/projectdiscovery/utils/update" 7 | ) 8 | 9 | const banner = ` 10 | 11 | ______ _____ ____ ___ ____ ____ 12 | / ___/ | / / _ \/ __ \__ \/ __ \/ __ \ 13 | / /__ | |/ / __/ / / / / / /_/ / /_/ / 14 | \___/ |___/\___/_/ /_/ /_/\__,_/ .___/ 15 | /_/ 16 | 17 | ` 18 | 19 | // Version is the current version 20 | const Version = `v0.0.7` 21 | 22 | // showBanner is used to show the banner to the user 23 | func showBanner() { 24 | gologger.Print().Msgf("%s\n", banner) 25 | gologger.Print().Msgf("\t\tprojectdiscovery.io\n\n") 26 | } 27 | 28 | // GetUpdateCallback returns a callback function that updates proxify 29 | func GetUpdateCallback() func() { 30 | return func() { 31 | showBanner() 32 | updateutils.GetUpdateToolCallback("cvemap", Version)() 33 | } 34 | } 35 | 36 | // AuthWithPDCP is used to authenticate with PDCP 37 | func AuthWithPDCP() { 38 | showBanner() 39 | pdcp.CheckNValidateCredentials("cvemap") 40 | } 41 | -------------------------------------------------------------------------------- /pkg/runner/options.go: -------------------------------------------------------------------------------- 1 | package runner 2 | 3 | import "github.com/projectdiscovery/goflags" 4 | 5 | type Options struct { 6 | PdcpAuth string 7 | CveIds goflags.StringSlice 8 | CweIds goflags.StringSlice 9 | Vendor goflags.StringSlice 10 | Product goflags.StringSlice 11 | Eproduct goflags.StringSlice 12 | Severity goflags.StringSlice 13 | CvssScore goflags.StringSlice 14 | //cvssMetrics goflags.StringSlice 15 | EpssPercentile goflags.StringSlice 16 | //year goflags.StringSlice 17 | Assignees goflags.StringSlice 18 | Reference goflags.StringSlice 19 | //vulnType goflags.StringSlice 20 | IncludeColumns []string 21 | ExcludeColumns []string 22 | TableHeaders []string 23 | ListId bool 24 | EpssScore string 25 | Cpe string 26 | VulnStatus string 27 | Age string 28 | Kev string 29 | //trending bool 30 | Hackerone string 31 | HasNucleiTemplate string 32 | HasPoc string 33 | Search string 34 | RemotlyExploitable string 35 | EnablePageKeys bool 36 | Json bool 37 | Limit int 38 | Offset int 39 | Version bool 40 | DisableUpdateCheck bool 41 | Silent bool 42 | Verbose bool 43 | Debug bool 44 | HealthCheck bool 45 | HTTPProxy string 46 | Output string 47 | } 48 | -------------------------------------------------------------------------------- /pkg/runner/runner.go: -------------------------------------------------------------------------------- 1 | package runner 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "io" 7 | "net/http" 8 | "net/url" 9 | "os" 10 | "strconv" 11 | "strings" 12 | "sync" 13 | 14 | "github.com/eiannone/keyboard" 15 | "github.com/jedib0t/go-pretty/v6/table" 16 | "github.com/projectdiscovery/cvemap/pkg/service" 17 | "github.com/projectdiscovery/cvemap/pkg/types" 18 | "github.com/projectdiscovery/goflags" 19 | "github.com/projectdiscovery/gologger" 20 | "github.com/projectdiscovery/gologger/levels" 21 | "github.com/projectdiscovery/utils/auth/pdcp" 22 | "github.com/projectdiscovery/utils/env" 23 | fileutil "github.com/projectdiscovery/utils/file" 24 | sliceutil "github.com/projectdiscovery/utils/slice" 25 | updateutils "github.com/projectdiscovery/utils/update" 26 | urlutil "github.com/projectdiscovery/utils/url" 27 | ) 28 | 29 | var ( 30 | PDCPApiKey = "" 31 | DEFAULT_FEILD_CHAR_LIMIT = env.GetEnvOrDefault("DEFAULT_FEILD_CHAR_LIMIT", 20) 32 | ) 33 | 34 | func init() { 35 | pch := pdcp.PDCPCredHandler{} 36 | if os.Getenv("PDCP_API_KEY") != "" { 37 | PDCPApiKey = os.Getenv("PDCP_API_KEY") 38 | } else if creds, err := pch.GetCreds(); err == nil { 39 | PDCPApiKey = creds.APIKey 40 | } 41 | } 42 | 43 | var ( 44 | defaultHeaders = []string{"ID", "CVSS", "Severity", "EPSS", "Product", "Age", "Template"} 45 | 46 | headerMap = map[string]string{ 47 | "id": "id", 48 | "cwe": "cwe", 49 | "epss": "epss", 50 | "cvss": "cvss", 51 | "severity": "severity", 52 | "vendor": "vendor", 53 | "product": "product", 54 | "vstatus": "vstatus", 55 | "assignee": "assignee", 56 | "age": "age", 57 | "kev": "kev", 58 | "template": "template", 59 | "poc": "poc", 60 | "rank": "rank", 61 | "reports": "reports", 62 | } 63 | 64 | allowedHeader = goflags.AllowdTypes{ 65 | "": goflags.EnumVariable(-1), 66 | "cwe": goflags.EnumVariable(0), 67 | "epss": goflags.EnumVariable(1), 68 | "product": goflags.EnumVariable(2), 69 | "vendor": goflags.EnumVariable(3), 70 | "vstatus": goflags.EnumVariable(4), 71 | "assignee": goflags.EnumVariable(5), 72 | "age": goflags.EnumVariable(6), 73 | "kev": goflags.EnumVariable(7), 74 | "template": goflags.EnumVariable(8), 75 | "poc": goflags.EnumVariable(9), 76 | } 77 | allowedHeaderString = allowedHeader.String() 78 | 79 | allowedVstatus = goflags.AllowdTypes{ 80 | "": goflags.EnumVariable(-1), 81 | "new": goflags.EnumVariable(0), 82 | "confirmed": goflags.EnumVariable(1), 83 | "unconfirmed": goflags.EnumVariable(2), 84 | "modified": goflags.EnumVariable(3), 85 | "rejected": goflags.EnumVariable(4), 86 | "unknown": goflags.EnumVariable(5), 87 | } 88 | 89 | maxLimit = 300 90 | ) 91 | 92 | func ParseOptions() *Options { 93 | var options Options 94 | 95 | flagset := goflags.NewFlagSet() 96 | flagset.SetDescription(`Navigate the CVE jungle with ease.`) 97 | 98 | flagset.CreateGroup("config", "Config", 99 | flagset.DynamicVar(&options.PdcpAuth, "auth", "true", "configure projectdiscovery cloud (pdcp) api key"), 100 | flagset.StringVarP(&options.HTTPProxy, "proxy", "http-proxy", "", "http proxy to use (eg http://127.0.0.1:8080)"), 101 | ) 102 | 103 | flagset.CreateGroup("OPTIONS", "options", 104 | // currently only one cve id is supported 105 | flagset.StringSliceVar(&options.CveIds, "id", nil, "cve to list for given id", goflags.FileCommaSeparatedStringSliceOptions), 106 | flagset.StringSliceVarP(&options.CweIds, "cwe-id", "cwe", nil, "cve to list for given cwe id", goflags.CommaSeparatedStringSliceOptions), 107 | flagset.StringSliceVarP(&options.Vendor, "vendor", "v", nil, "cve to list for given vendor", goflags.CommaSeparatedStringSliceOptions), 108 | flagset.StringSliceVarP(&options.Product, "product", "p", nil, "cve to list for given product", goflags.CommaSeparatedStringSliceOptions), 109 | flagset.StringSliceVar(&options.Eproduct, "eproduct", nil, "cves to exclude based on products", goflags.CommaSeparatedStringSliceOptions), 110 | flagset.StringSliceVarP(&options.Severity, "severity", "s", nil, "cve to list for given severity", goflags.CommaSeparatedStringSliceOptions), 111 | flagset.StringSliceVarP(&options.CvssScore, "cvss-score", "cs", nil, "cve to list for given cvss score", goflags.CommaSeparatedStringSliceOptions), 112 | flagset.StringVarP(&options.Cpe, "cpe", "c", "", "cve to list for given cpe"), 113 | flagset.StringVarP(&options.EpssScore, "epss-score", "es", "", "cve to list for given epss score"), 114 | flagset.StringSliceVarP(&options.EpssPercentile, "epss-percentile", "ep", nil, "cve to list for given epss percentile", goflags.CommaSeparatedStringSliceOptions), 115 | flagset.StringVar(&options.Age, "age", "", "cve to list published by given age in days"), 116 | flagset.StringSliceVarP(&options.Assignees, "assignee", "a", nil, "cve to list for given publisher assignee", goflags.CommaSeparatedStringSliceOptions), 117 | //flagset.StringSliceVarP(&options.vulnType, "type", "vt", nil, "cve to list for given vulnerability type", goflags.CommaSeparatedStringSliceOptions), 118 | flagset.EnumVarP(&options.VulnStatus, "vstatus", "vs", goflags.EnumVariable(-1), strings.Replace(fmt.Sprintf("cve to list for given vulnerability status in cli output. supported: %s", allowedVstatus.String()), " ,", "", -1), allowedVstatus), 119 | ) 120 | 121 | flagset.CreateGroup("update", "Update", 122 | flagset.CallbackVarP(GetUpdateCallback(), "update", "up", "update cvemap to latest version"), 123 | flagset.BoolVarP(&options.DisableUpdateCheck, "disable-update-check", "duc", false, "disable automatic cvemap update check"), 124 | ) 125 | 126 | flagset.CreateGroup("FILTER", "filter", 127 | flagset.StringVarP(&options.Search, "search", "q", "", "search in cve data"), 128 | flagset.DynamicVarP(&options.Kev, "kev", "k", "true", "display cves marked as exploitable vulnerabilities by cisa"), 129 | flagset.DynamicVarP(&options.HasNucleiTemplate, "template", "t", "true", "display cves that has public nuclei templates"), 130 | flagset.DynamicVar(&options.HasPoc, "poc", "true", "display cves that has public published poc"), 131 | flagset.DynamicVarP(&options.Hackerone, "hackerone", "h1", "true", "display cves reported on hackerone"), 132 | flagset.DynamicVarP(&options.RemotlyExploitable, "remote", "re", "true", "display remotely exploitable cves (AV:N & PR:N | PR:L)"), 133 | ) 134 | 135 | flagset.CreateGroup("OUTPUT", "output", 136 | flagset.EnumSliceVarP(&options.IncludeColumns, "field", "f", []goflags.EnumVariable{goflags.EnumVariable(-1)}, strings.Replace(fmt.Sprintf("fields to display in cli output. supported: %s", allowedHeaderString), " ,", "", -1), allowedHeader), 137 | flagset.EnumSliceVarP(&options.ExcludeColumns, "exclude", "fe", []goflags.EnumVariable{goflags.EnumVariable(-1)}, strings.Replace(fmt.Sprintf("fields to exclude from cli output. supported: %s", allowedHeaderString), " ,", "", -1), allowedHeader), 138 | flagset.BoolVarP(&options.ListId, "list-id", "lsi", false, "list only the cve ids in the output"), 139 | flagset.IntVarP(&options.Limit, "limit", "l", 50, "limit the number of results to display"), 140 | flagset.IntVar(&options.Offset, "offset", 0, "offset the results to display"), 141 | flagset.BoolVarP(&options.Json, "json", "j", false, "return output in json format"), 142 | flagset.StringVarP(&options.Output, "output", "o", "", "output to file"), 143 | // experimental 144 | flagset.BoolVarP(&options.EnablePageKeys, "enable-page-keys", "epk", false, "enable page keys to navigate results"), 145 | ) 146 | 147 | flagset.CreateGroup("DEBUG", "debug", 148 | flagset.BoolVar(&options.Version, "version", false, "Version"), 149 | flagset.BoolVar(&options.Silent, "silent", false, "Silent"), 150 | flagset.BoolVar(&options.Verbose, "verbose", false, "Verbose"), 151 | flagset.BoolVar(&options.Debug, "debug", false, "Debug"), 152 | flagset.BoolVarP(&options.HealthCheck, "health-check", "hc", false, "run diagnostic check up"), 153 | ) 154 | 155 | if err := flagset.Parse(); err != nil { 156 | gologger.Fatal().Msgf("Error parsing flags: %s\n", err) 157 | } 158 | if !options.Debug { 159 | options.Debug = env.GetEnvOrDefault("DEBUG", false) 160 | } 161 | if options.Version { 162 | gologger.Info().Msgf("Current Version: %s\n", Version) 163 | os.Exit(0) 164 | } 165 | 166 | if options.HealthCheck { 167 | showBanner() 168 | gologger.Print().Msgf("%s\n", DoHealthCheck(options)) 169 | os.Exit(0) 170 | } 171 | 172 | // api key hierarchy: cli flag > env var > .pdcp/credential file 173 | if options.PdcpAuth == "true" { 174 | AuthWithPDCP() 175 | } else if len(options.PdcpAuth) == 36 { 176 | PDCPApiKey = options.PdcpAuth 177 | ph := pdcp.PDCPCredHandler{} 178 | if _, err := ph.GetCreds(); err == pdcp.ErrNoCreds { 179 | apiServer := env.GetEnvOrDefault("PDCP_API_SERVER", pdcp.DefaultApiServer) 180 | if validatedCreds, err := ph.ValidateAPIKey(PDCPApiKey, apiServer, "cvemap"); err == nil { 181 | _ = ph.SaveCreds(validatedCreds) 182 | } 183 | } 184 | } 185 | 186 | if options.Limit > maxLimit { 187 | options.Limit = maxLimit 188 | } 189 | 190 | if fileutil.HasStdin() { 191 | // Read from stdin 192 | bin, err := io.ReadAll(os.Stdin) 193 | if err != nil { 194 | gologger.Fatal().Msgf("couldn't read stdin: %s\n", err) 195 | } 196 | stdinStr := strings.TrimSpace(string(bin)) 197 | if stdinStr != "" { 198 | options.CveIds = append(options.CveIds, strings.Split(stdinStr, "\n")...) 199 | } 200 | } 201 | 202 | // make fields case insensitive 203 | for i, cveId := range options.CveIds { 204 | options.CveIds[i] = strings.ToUpper(cveId) 205 | } 206 | for i, cweId := range options.CweIds { 207 | options.CweIds[i] = strings.ToUpper(cweId) 208 | } 209 | for i, severity := range options.Severity { 210 | options.Severity[i] = strings.ToLower(severity) 211 | } 212 | for i, vendor := range options.Vendor { 213 | options.Vendor[i] = strings.ToLower(vendor) 214 | } 215 | for i, product := range options.Product { 216 | options.Product[i] = strings.ToLower(product) 217 | } 218 | for i, eproduct := range options.Eproduct { 219 | options.Eproduct[i] = strings.ToLower(eproduct) 220 | } 221 | return &options 222 | } 223 | 224 | type Runner struct { 225 | Options *Options 226 | CvemapService *service.Cvemap 227 | } 228 | 229 | func New(options *Options) (*Runner, error) { 230 | serviceOpts := &service.Options{ 231 | ApiKey: PDCPApiKey, 232 | Debug: options.Debug, 233 | } 234 | if options.HTTPProxy != "" { 235 | proxyURL, parseErr := url.Parse(options.HTTPProxy) 236 | if parseErr != nil { 237 | return nil, parseErr 238 | } 239 | serviceOpts.HttpClient = &http.Client{ 240 | Transport: &http.Transport{ 241 | Proxy: http.ProxyURL(proxyURL)}} 242 | } 243 | CvemapService, err := service.NewCvemap(serviceOpts) 244 | if err != nil { 245 | return nil, err 246 | } 247 | r := &Runner{ 248 | Options: options, 249 | CvemapService: CvemapService, 250 | } 251 | return r, nil 252 | } 253 | 254 | func (r *Runner) Run() { 255 | if r.Options.Silent { 256 | gologger.DefaultLogger.SetMaxLevel(levels.LevelSilent) 257 | } else if r.Options.Verbose { 258 | gologger.DefaultLogger.SetMaxLevel(levels.LevelVerbose) 259 | } 260 | 261 | // Show the user the banner 262 | showBanner() 263 | 264 | if !r.Options.DisableUpdateCheck { 265 | latestVersion, err := updateutils.GetToolVersionCallback("cvemap", Version)() 266 | if err != nil { 267 | if r.Options.Verbose { 268 | gologger.Error().Msgf("cvemap version check failed: %v", err.Error()) 269 | } 270 | } else { 271 | gologger.Info().Msgf("Current cvemap version %v %v", Version, updateutils.GetVersionDescription(Version, latestVersion)) 272 | } 273 | } 274 | 275 | // on default, enable kev 276 | if isDefaultRun(r.Options) { 277 | r.Options.Kev = "true" 278 | } 279 | 280 | parseHeaders(r.Options) 281 | 282 | if r.Options.EnablePageKeys && len(r.Options.CveIds) == 0 { 283 | r.processWithPageKeyEvents() 284 | } else { 285 | _ = r.process() 286 | } 287 | } 288 | 289 | func (r *Runner) GetCves() (*types.CVEBulkData, error) { 290 | if len(r.Options.CveIds) > 0 { 291 | return r.CvemapService.GetCvesByIds(r.Options.CveIds) 292 | } 293 | if r.Options.Search != "" { 294 | query := constructQueryByOptions(*r.Options) 295 | if r.Options.Debug { 296 | gologger.Print().Msgf("constructed query: %s\n", query) 297 | } 298 | return r.CvemapService.GetCvesBySearchString(query, r.Options.Limit, r.Options.Offset) 299 | } 300 | return r.CvemapService.GetCvesByFilters(constructQueryParams(r.Options)) 301 | } 302 | 303 | func (r *Runner) process() *types.CVEBulkData { 304 | var cvesResp *types.CVEBulkData 305 | var err error 306 | cvesResp, err = r.GetCves() 307 | if err != nil { 308 | gologger.Fatal().Msgf("Error getting CVEs: %s\n", err) 309 | return nil 310 | } 311 | 312 | if r.Options.Json { 313 | outputJson(cvesResp.Cves) 314 | return cvesResp 315 | } 316 | 317 | if r.Options.Output != "" { 318 | writeToFile(r.Options.Output, cvesResp.Cves) 319 | } 320 | 321 | nPages := cvesResp.TotalResults / r.Options.Limit 322 | if cvesResp.TotalResults%r.Options.Limit > 0 { 323 | nPages++ 324 | } 325 | currentPage := (r.Options.Offset / r.Options.Limit) + 1 326 | if len(r.Options.CveIds) == 0 && (r.Options.Verbose || r.Options.EnablePageKeys) { 327 | gologger.Print().Msgf("\n Limit: %v Page: %v TotalPages: %v TotalResults: %v\n", r.Options.Limit, currentPage, nPages, cvesResp.TotalResults) 328 | } 329 | 330 | if r.Options.ListId { 331 | for _, cve := range cvesResp.Cves { 332 | fmt.Println(cve.CveID) 333 | } 334 | return cvesResp 335 | } 336 | 337 | // limit headers to 10, otherwise it will be too wide 338 | if len(r.Options.TableHeaders) > 10 { 339 | r.Options.TableHeaders = r.Options.TableHeaders[:10] 340 | } 341 | 342 | headers, rows := generateTableData(cvesResp.Cves, r.Options.TableHeaders) 343 | 344 | renderTable(headers, rows) 345 | 346 | if r.Options.EnablePageKeys { 347 | pageString := "" 348 | if currentPage > 1 { 349 | pageString += " ◀ " 350 | } 351 | if currentPage < nPages { 352 | pageString += " ▶" 353 | } 354 | gologger.Print().Msgf("%s", pageString) 355 | } 356 | return cvesResp 357 | } 358 | 359 | func (r *Runner) processWithPageKeyEvents() { 360 | cveResp := r.process() 361 | // wait for user input 362 | err := keyboard.Open() 363 | if err != nil { 364 | panic(err) 365 | } 366 | defer keyboard.Close() 367 | waitGroup := sync.WaitGroup{} 368 | waitGroup.Add(1) 369 | 370 | go func() { 371 | for { 372 | _, key, err := keyboard.GetKey() 373 | if err != nil { 374 | panic(err) 375 | } 376 | 377 | if key == keyboard.KeyEsc || key == keyboard.KeyCtrlC { 378 | waitGroup.Done() 379 | break 380 | } 381 | 382 | switch key { 383 | case keyboard.KeyArrowRight: 384 | if r.Options.Offset+r.Options.Limit < cveResp.TotalResults { 385 | r.Options.Offset += r.Options.Limit 386 | clearScreen() 387 | cveResp = r.process() 388 | } 389 | case keyboard.KeyArrowLeft: 390 | if r.Options.Offset-r.Options.Limit >= 0 { 391 | r.Options.Offset -= r.Options.Limit 392 | clearScreen() 393 | cveResp = r.process() 394 | } 395 | } 396 | } 397 | }() 398 | 399 | waitGroup.Wait() 400 | } 401 | 402 | func parseHeaders(options *Options) { 403 | // construct headers 404 | headers := make([]string, 0) 405 | 406 | if options.Hackerone == "true" { 407 | defaultHeaders = []string{"ID", "CVSS", "Severity", "EPSS", "Rank", "Reports", "Age", "Product", "Template"} 408 | } 409 | 410 | options.IncludeColumns = getValidHeaders(options.IncludeColumns) 411 | options.ExcludeColumns = getValidHeaders(options.ExcludeColumns) 412 | 413 | options.IncludeColumns = append(defaultHeaders, options.IncludeColumns...) 414 | // case insensitive contains check 415 | contains := func(array []string, element string) bool { 416 | for _, e := range array { 417 | if strings.EqualFold(e, element) { 418 | return true 419 | } 420 | } 421 | return false 422 | } 423 | // add headers to display 424 | for _, header := range options.IncludeColumns { 425 | if !contains(options.ExcludeColumns, header) && !contains(headers, header) { 426 | headers = append(headers, header) 427 | } 428 | } 429 | options.TableHeaders = headers 430 | } 431 | 432 | func renderTable(headers []string, rows [][]interface{}) { 433 | // Create a table for displaying CVE data with the specified headers 434 | t := table.NewWriter() 435 | t.SetOutputMirror(os.Stdout) 436 | 437 | // Append the specified headers to the table 438 | headerRow := make([]interface{}, len(headers)) 439 | for i, header := range headers { 440 | headerRow[i] = header 441 | } 442 | t.AppendHeader(headerRow) 443 | // Loop through the retrieved CVE data and add rows to the table 444 | for _, row := range rows { 445 | t.AppendRow(row) 446 | } 447 | // t.SetColumnConfigs([]table.ColumnConfig{ 448 | // {Number: 5, WidthMax: 20}, 449 | // }) 450 | // Set table options and render it 451 | t.SetStyle(table.StyleRounded) 452 | t.Render() 453 | } 454 | 455 | func generateTableData(cves []types.CVEData, headers []string) ([]string, [][]interface{}) { 456 | dataRows := make([][]interface{}, len(cves)) 457 | for r, cve := range cves { 458 | dataRows[r] = getRow(headers, cve) 459 | } 460 | return headers, dataRows 461 | } 462 | 463 | func getRow(headers []string, cve types.CVEData) []interface{} { 464 | row := make([]interface{}, len(headers)) 465 | for i, header := range headers { 466 | switch strings.ToLower(header) { 467 | case "id": 468 | row[i] = getCellValueByLimit(cve.CveID) 469 | case "epss": 470 | row[i] = getCellValueByLimit(cve.Epss.Score) 471 | case "cvss": 472 | row[i] = "" 473 | if cve.CvssMetrics != nil { 474 | row[i] = getCellValueByLimit(getLatestVersionCVSSScore(*cve.CvssMetrics)) 475 | } 476 | case "severity": 477 | row[i] = getCellValueByLimit(strings.ToTitle(cve.Severity)) 478 | case "cwe": 479 | row[i] = "" 480 | if len(cve.Weaknesses) > 0 { 481 | row[i] = getCellValueByLimit(cve.Weaknesses[0].CWEID) 482 | } 483 | case "vendor": 484 | row[i] = "" 485 | if cve.Cpe != nil { 486 | row[i] = getCellValueByLimit(*cve.Cpe.Vendor) 487 | } 488 | case "product": 489 | row[i] = "" 490 | if cve.Cpe != nil { 491 | row[i] = getCellValueByLimit(*cve.Cpe.Product) 492 | } 493 | case "vstatus": 494 | row[i] = getCellValueByLimit(strings.ToUpper(cve.VulnStatus)) 495 | case "assignee": 496 | row[i] = "" 497 | if len(cve.Assignee) > 0 { 498 | row[i] = getCellValueByLimit(cve.Assignee) 499 | } 500 | case "age": 501 | row[i] = "" 502 | if cve.AgeInDays > 0 { 503 | row[i] = getCellValueByLimit(cve.AgeInDays) 504 | } 505 | case "kev": 506 | row[i] = getCellValueByLimit(strings.ToUpper(strconv.FormatBool(cve.IsKev))) 507 | case "template": 508 | if cve.IsTemplate { 509 | row[i] = "✅" 510 | } else { 511 | row[i] = "❌" 512 | } 513 | case "poc": 514 | row[i] = getCellValueByLimit(strings.ToUpper(strconv.FormatBool(cve.IsPoc))) 515 | case "rank": 516 | row[i] = "" 517 | if cve.Hackerone.Rank > 0 { 518 | row[i] = getCellValueByLimit(cve.Hackerone.Rank) 519 | } 520 | case "reports": 521 | row[i] = getCellValueByLimit(cve.Hackerone.Count) 522 | 523 | default: 524 | row[i] = "" 525 | } 526 | } 527 | return row 528 | } 529 | 530 | func getCellValueByLimit(cell interface{}) string { 531 | if cell == nil { 532 | return "" 533 | } 534 | cellValue := fmt.Sprintf("%v", cell) 535 | if len(cellValue) > DEFAULT_FEILD_CHAR_LIMIT { 536 | cellValue = cellValue[:DEFAULT_FEILD_CHAR_LIMIT] + "..." 537 | } 538 | return cellValue 539 | } 540 | 541 | func outputJson(cve []types.CVEData) { 542 | json, err := json.MarshalIndent(cve, "", " ") 543 | if err != nil { 544 | gologger.Error().Msgf("Error marshalling json: %s\n", err) 545 | return 546 | } 547 | gologger.Silent().Msgf("%s\n", string(json)) 548 | } 549 | 550 | func writeToFile(filename string, cves []types.CVEData) { 551 | file, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644) 552 | if err != nil { 553 | gologger.Fatal().Msgf("failed to open or create file: %v", err) 554 | } 555 | defer file.Close() 556 | json, err := json.MarshalIndent(cves, "", " ") 557 | if err != nil { 558 | gologger.Error().Msgf("Error marshalling json: %s\n", err) 559 | } 560 | // Write to the file 561 | _, err = file.WriteString(string(json)) 562 | if err != nil { 563 | gologger.Fatal().Msgf("failed to write to file: %v", err) 564 | } 565 | } 566 | 567 | func constructQueryParams(opts *Options) string { 568 | queryParams := urlutil.NewOrderedParams() 569 | if len(opts.Severity) > 0 { 570 | addQueryParams(queryParams, "severity", opts.Severity) 571 | } 572 | if len(opts.Assignees) > 0 { 573 | addQueryParams(queryParams, "assignee", opts.Assignees) 574 | } 575 | if len(opts.CvssScore) > 0 { 576 | var cvsKey string 577 | for _, cvssScore := range opts.CvssScore { 578 | cvsKey = "cvss_score" 579 | if cvssScore[0] == '>' { 580 | cvsKey = "cvss_score_gte" 581 | cvssScore = strings.TrimSpace(cvssScore[1:]) 582 | } else if cvssScore[0] == '<' { 583 | cvsKey = "cvss_score_lte" 584 | cvssScore = strings.TrimSpace(cvssScore[1:]) 585 | } 586 | queryParams.Add(cvsKey, cvssScore) 587 | } 588 | } 589 | 590 | if len(opts.Age) > 0 { 591 | ageKey := "age_in_days" 592 | if opts.Age[0] == '>' { 593 | ageKey = "age_in_days_gte" 594 | opts.Age = strings.TrimSpace(opts.Age[1:]) 595 | } else if opts.Age[0] == '<' { 596 | ageKey = "age_in_days_lte" 597 | opts.Age = strings.TrimSpace(opts.Age[1:]) 598 | } 599 | queryParams.Add(ageKey, opts.Age) 600 | } 601 | if len(opts.VulnStatus) > 0 { 602 | queryParams.Add("vuln_status", strings.ToLower(opts.VulnStatus)) 603 | } 604 | if len(opts.Reference) > 0 { 605 | addQueryParams(queryParams, "reference", opts.Reference) 606 | } 607 | if len(opts.EpssScore) > 0 { 608 | epssKey := "epss.epss_score" 609 | if opts.EpssScore[0] == '>' { 610 | epssKey = "epss.epss_score_gte" 611 | opts.EpssScore = strings.TrimSpace(opts.EpssScore[1:]) 612 | } else if opts.EpssScore[0] == '<' { 613 | epssKey = "epss.epss_score_lte" 614 | opts.EpssScore = strings.TrimSpace(opts.EpssScore[1:]) 615 | } 616 | queryParams.Add(epssKey, opts.EpssScore) 617 | } 618 | if len(opts.EpssPercentile) > 0 { 619 | var epKey string 620 | for _, ep := range opts.EpssPercentile { 621 | epKey = "epss.epss_percentile" 622 | if ep[0] == '>' { 623 | epKey = "epss.epss_percentile_gte" 624 | ep = strings.TrimSpace(ep[1:]) 625 | } else if ep[0] == '<' { 626 | epKey = "epss.epss_percentile_lte" 627 | ep = strings.TrimSpace(ep[1:]) 628 | } 629 | queryParams.Add(epKey, ep) 630 | } 631 | } 632 | if len(opts.CweIds) > 0 { 633 | addQueryParams(queryParams, "weaknesses.$.cwe_id", opts.CweIds) 634 | } 635 | if len(opts.Cpe) > 0 { 636 | queryParams.Add("cpe.cpe", opts.Cpe) 637 | } 638 | if len(opts.Product) > 0 { 639 | addQueryParams(queryParams, "cpe.product", opts.Product) 640 | } 641 | if len(opts.Eproduct) > 0 { 642 | addQueryParams(queryParams, "cpe.product_ne", opts.Eproduct) 643 | } 644 | if len(opts.Vendor) > 0 { 645 | addQueryParams(queryParams, "cpe.vendor", opts.Vendor) 646 | } 647 | if opts.Kev == "true" { 648 | queryParams.Add("is_exploited", "true") 649 | } else if opts.Kev == "false" { 650 | queryParams.Add("is_exploited", "false") 651 | } 652 | if opts.HasNucleiTemplate == "true" { 653 | queryParams.Add("is_template", "true") 654 | } else if opts.HasNucleiTemplate == "false" { 655 | queryParams.Add("is_template", "false") 656 | } 657 | if opts.HasPoc == "true" { 658 | queryParams.Add("is_poc", "true") 659 | } else if opts.HasPoc == "false" { 660 | queryParams.Add("is_poc", "false") 661 | } 662 | if opts.RemotlyExploitable == "true" { 663 | queryParams.Add("is_remote", "true") 664 | } 665 | subQuery := "" 666 | if opts.Hackerone == "true" { 667 | subQuery = "hackerone.rank_gte=1" 668 | subQuery += "&sort_asc=hackerone.rank" 669 | } else { 670 | subQuery = "sort_desc=cve_id" 671 | } 672 | if opts.Limit > 0 { 673 | if len(subQuery) > 0 { 674 | subQuery += "&" 675 | } 676 | subQuery += fmt.Sprintf("limit=%d", opts.Limit) 677 | } 678 | if opts.Offset >= 0 { 679 | if len(subQuery) > 0 { 680 | subQuery += "&" 681 | } 682 | subQuery += fmt.Sprintf("offset=%d", opts.Offset) 683 | } 684 | query := queryParams.Encode() 685 | if len(opts.CweIds) == 1 { 686 | if len(query) > 0 && len(subQuery) > 0 { 687 | query += "&" 688 | } 689 | return query + subQuery 690 | } 691 | if len(query) > 0 && len(subQuery) > 0 { 692 | query = "&" + query 693 | } 694 | return subQuery + query 695 | } 696 | 697 | func constructQueryByOptions(opts Options) string { 698 | query := opts.Search 699 | if len(opts.Vendor) > 0 { 700 | query = fmt.Sprintf("%s cpe.vendor:%s", query, strings.Join(opts.Vendor, ",")) 701 | } 702 | if len(opts.Product) > 0 { 703 | query = fmt.Sprintf("%s cpe.product:%s", query, strings.Join(opts.Product, ",")) 704 | } 705 | if len(opts.Eproduct) > 0 { 706 | query = fmt.Sprintf("%s cpe.product_ne:%s", query, strings.Join(opts.Eproduct, ",")) 707 | } 708 | if len(opts.Severity) > 0 { 709 | query = fmt.Sprintf("%s severity:%s", query, strings.Join(opts.Severity, ",")) 710 | } 711 | if len(opts.CvssScore) > 0 { 712 | var cvsKey string 713 | for _, cvssScore := range opts.CvssScore { 714 | cvsKey = "cvss_score" 715 | if cvssScore[0] == '>' { 716 | cvsKey = "cvss_score_gte" 717 | cvssScore = strings.TrimSpace(cvssScore[1:]) 718 | } else if cvssScore[0] == '<' { 719 | cvsKey = "cvss_score_lte" 720 | cvssScore = strings.TrimSpace(cvssScore[1:]) 721 | } 722 | query = fmt.Sprintf("%s %s:%s", query, cvsKey, cvssScore) 723 | } 724 | } 725 | if len(opts.EpssScore) > 0 { 726 | epssKey := "epss.epss_score" 727 | if opts.EpssScore[0] == '>' { 728 | epssKey = "epss.epss_score_gte" 729 | opts.EpssScore = strings.TrimSpace(opts.EpssScore[1:]) 730 | } else if opts.EpssScore[0] == '<' { 731 | epssKey = "epss.epss_score_lte" 732 | opts.EpssScore = strings.TrimSpace(opts.EpssScore[1:]) 733 | } 734 | query = fmt.Sprintf("%s %s:%s", query, epssKey, opts.EpssScore) 735 | } 736 | if len(opts.EpssPercentile) > 0 { 737 | var epKey string 738 | for _, ep := range opts.EpssPercentile { 739 | epKey = "epss.epss_percentile" 740 | if ep[0] == '>' { 741 | epKey = "epss.epss_percentile_gte" 742 | ep = strings.TrimSpace(ep[1:]) 743 | } else if ep[0] == '<' { 744 | epKey = "epss.epss_percentile_lte" 745 | ep = strings.TrimSpace(ep[1:]) 746 | } 747 | query = fmt.Sprintf("%s %s:%s", query, epKey, ep) 748 | } 749 | } 750 | if len(opts.Cpe) > 0 { 751 | query = fmt.Sprintf(`%s cpe.cpe:"%s"`, query, opts.Cpe) 752 | } 753 | if len(opts.CweIds) > 0 { 754 | query = fmt.Sprintf("%s %s:%s", query, "weaknesses.$.cwe_id", strings.Join(opts.CweIds, ",")) 755 | } 756 | if len(opts.Age) > 0 { 757 | ageKey := "age_in_days" 758 | if opts.Age[0] == '>' { 759 | ageKey = "age_in_days_gte" 760 | opts.Age = strings.TrimSpace(opts.Age[1:]) 761 | } else if opts.Age[0] == '<' { 762 | ageKey = "age_in_days_lte" 763 | opts.Age = strings.TrimSpace(opts.Age[1:]) 764 | } 765 | query = fmt.Sprintf("%s %s:%s", query, ageKey, opts.Age) 766 | } 767 | if len(opts.Assignees) > 0 { 768 | query = fmt.Sprintf("%s assignee:%s", query, strings.Join(opts.Assignees, ",")) 769 | } 770 | if len(opts.VulnStatus) > 0 { 771 | query = fmt.Sprintf("%s vuln_status:%s", query, strings.ToLower(opts.VulnStatus)) 772 | } 773 | if opts.Kev == "true" { 774 | query = fmt.Sprintf("%s is_exploited:true", query) 775 | } else if opts.Kev == "false" { 776 | query = fmt.Sprintf("%s is_exploited:false", query) 777 | } 778 | if opts.HasNucleiTemplate == "true" { 779 | query = fmt.Sprintf("%s is_template:true", query) 780 | } else if opts.HasNucleiTemplate == "false" { 781 | query = fmt.Sprintf("%s is_template:false", query) 782 | } 783 | if opts.HasPoc == "true" { 784 | query = fmt.Sprintf("%s is_poc:true", query) 785 | } else if opts.HasPoc == "false" { 786 | query = fmt.Sprintf("%s is_poc:false", query) 787 | } 788 | if opts.Hackerone == "true" { 789 | query = fmt.Sprintf("%s hackerone.rank_gte:1 sort_asc:hackerone.rank", query) 790 | } else { 791 | query = fmt.Sprintf("%s sort_desc:cve_id", query) 792 | } 793 | if opts.RemotlyExploitable == "true" { 794 | query = fmt.Sprintf("%s is_remote:true", query) 795 | } 796 | 797 | parts := strings.Split(query, " ") 798 | parts = sliceutil.PruneEmptyStrings(parts) 799 | parts = sliceutil.Dedupe(parts) 800 | query = strings.Join(parts, " ") 801 | return query 802 | } 803 | 804 | func addQueryParams(queryParams *urlutil.OrderedParams, key string, values []string) *urlutil.OrderedParams { 805 | if len(values) > 0 { 806 | for _, value := range values { 807 | queryParams.Add(key, value) 808 | } 809 | } 810 | return queryParams 811 | } 812 | 813 | func getValidHeaders(keys []string) []string { 814 | headers := []string{} 815 | for _, hk := range keys { 816 | if v, ok := headerMap[hk]; ok { 817 | headers = append(headers, v) 818 | } 819 | } 820 | return headers 821 | } 822 | -------------------------------------------------------------------------------- /pkg/runner/util.go: -------------------------------------------------------------------------------- 1 | package runner 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | "os" 7 | "os/exec" 8 | "runtime" 9 | "strings" 10 | 11 | "github.com/projectdiscovery/cvemap/pkg/types" 12 | fileutil "github.com/projectdiscovery/utils/file" 13 | ) 14 | 15 | func DoHealthCheck(opts Options) string { 16 | var test strings.Builder 17 | test.WriteString(fmt.Sprintf("Version: %s\n", Version)) 18 | test.WriteString(fmt.Sprintf("Operating System: %s\n", runtime.GOOS)) 19 | test.WriteString(fmt.Sprintf("Architecture: %s\n", runtime.GOARCH)) 20 | test.WriteString(fmt.Sprintf("Go Version: %s\n", runtime.Version())) 21 | test.WriteString(fmt.Sprintf("Compiler: %s\n", runtime.Compiler)) 22 | 23 | var testResult string 24 | c4, err := net.Dial("tcp4", "cve.projectdiscovery.io:443") 25 | if err == nil && c4 != nil { 26 | c4.Close() 27 | } 28 | testResult = "Ok" 29 | if err != nil { 30 | testResult = fmt.Sprintf("Ko (%s)", err) 31 | } 32 | test.WriteString(fmt.Sprintf("IPv4 connectivity to cve.projectdiscovery.io:443 => %s\n", testResult)) 33 | 34 | u4, err := net.Dial("udp4", "cve.projectdiscovery.io:53") 35 | if err == nil && u4 != nil { 36 | u4.Close() 37 | } 38 | testResult = "Ok" 39 | if err != nil { 40 | testResult = fmt.Sprintf("Ko (%s)", err) 41 | } 42 | test.WriteString(fmt.Sprintf("IPv4 UDP connectivity to cve.projectdiscovery.io:53 => %s\n", testResult)) 43 | return test.String() 44 | } 45 | 46 | func getLatestVersionCVSSScore(cvss types.CvssMetrics) float64 { 47 | var highestScore float64 48 | if cvss.Cvss2 != nil { 49 | highestScore = cvss.Cvss2.Score 50 | } 51 | if cvss.Cvss30 != nil { 52 | highestScore = cvss.Cvss30.Score 53 | } 54 | if cvss.Cvss31 != nil { 55 | highestScore = cvss.Cvss31.Score 56 | } 57 | return highestScore 58 | } 59 | 60 | func isDefaultRun(opts *Options) bool { 61 | options := len(opts.CveIds) == 0 && len(opts.CweIds) == 0 && len(opts.Vendor) == 0 && len(opts.Product) == 0 && len(opts.Severity) == 0 && len(opts.CvssScore) == 0 && len(opts.EpssPercentile) == 0 && len(opts.Assignees) == 0 && len(opts.Reference) == 0 && opts.EpssScore == "" && opts.Cpe == "" && opts.VulnStatus == "" && opts.Age == "" 62 | filters := opts.Kev == "" && opts.Hackerone == "" && opts.HasNucleiTemplate == "" && opts.HasPoc == "" && opts.RemotlyExploitable == "" && opts.Search == "" 63 | return options && filters && !fileutil.HasStdin() 64 | } 65 | 66 | // clearScreen clears the terminal screen 67 | func clearScreen() { 68 | var cmd *exec.Cmd 69 | if runtime.GOOS == "windows" { 70 | cmd = exec.Command("cls") 71 | } else { 72 | cmd = exec.Command("clear") 73 | } 74 | cmd.Stdout = os.Stdout 75 | _ = cmd.Run() 76 | } 77 | -------------------------------------------------------------------------------- /pkg/service/cvemap.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "fmt" 7 | "net/http" 8 | "net/url" 9 | "strings" 10 | 11 | "github.com/projectdiscovery/cvemap/pkg/types" 12 | "github.com/projectdiscovery/gologger" 13 | "github.com/projectdiscovery/retryablehttp-go" 14 | "github.com/projectdiscovery/utils/env" 15 | errorutil "github.com/projectdiscovery/utils/errors" 16 | ) 17 | 18 | const xPDCPHeaderKey = "X-PDCP-Key" 19 | 20 | var ( 21 | BaseUrl = env.GetEnvOrDefault("CVEMAP_API_URL", "https://cve.projectdiscovery.io/api/v1") 22 | ErrUnAuthorized = errorutil.New(`unauthorized: 401 (get your free api key from https://cloud.projectdiscovery.io)`) 23 | ) 24 | 25 | type Cvemap struct { 26 | opts *Options 27 | client *retryablehttp.Client 28 | } 29 | 30 | type Options struct { 31 | // ApiKey is the api key for the cvemap api 32 | ApiKey string 33 | // RetryableHttpOptions contains options for the http client (optional) 34 | RetryableHttpOptions *retryablehttp.Options 35 | // HttpClient is the http client to use (optional) 36 | HttpClient *http.Client 37 | // Debug is a flag that enables debugging output 38 | Debug bool 39 | } 40 | 41 | func NewCvemap(opts *Options) (*Cvemap, error) { 42 | if opts == nil { 43 | return nil, fmt.Errorf("Options cannot be nil") 44 | } 45 | if opts.ApiKey == "" { 46 | return nil, fmt.Errorf("api key cannot be empty") 47 | } 48 | clientOpts := retryablehttp.DefaultOptionsSingle 49 | if opts.RetryableHttpOptions != nil { 50 | clientOpts = *opts.RetryableHttpOptions 51 | } 52 | if opts.HttpClient != nil { 53 | clientOpts.HttpClient = opts.HttpClient 54 | } 55 | httpClient := retryablehttp.NewClient(clientOpts) 56 | 57 | return &Cvemap{ 58 | opts: opts, 59 | client: httpClient, 60 | }, nil 61 | } 62 | 63 | func (c *Cvemap) GetCvesByIds(cveIds []string) (*types.CVEBulkData, error) { 64 | url := fmt.Sprintf("%s/cves", BaseUrl) 65 | // send only 100 cve ids max 66 | if len(cveIds) > 100 { 67 | cveIds = cveIds[:100] 68 | } 69 | var cveIdList types.CVEIdList 70 | cveIdList.Cves = append(cveIdList.Cves, cveIds...) 71 | reqData, err := json.Marshal(cveIdList) 72 | if err != nil { 73 | return nil, err 74 | } 75 | // Send an HTTP POST request 76 | req, err := retryablehttp.NewRequest("POST", url, bytes.NewBuffer(reqData)) 77 | if err != nil { 78 | return nil, err 79 | } 80 | req.Header.Set("Content-Type", "application/json") 81 | req.Header.Set(xPDCPHeaderKey, c.opts.ApiKey) 82 | 83 | response, err := c.doRequest(req) 84 | if err != nil { 85 | return nil, err 86 | } 87 | defer response.Body.Close() 88 | // Check the response status code 89 | if response.StatusCode != http.StatusOK { 90 | return nil, errorutil.New("unexpected status code: %d", response.StatusCode) 91 | } 92 | var cvesInBulk types.CVEBulkData 93 | // Decode the JSON response into an array of CVEData structs 94 | err = json.NewDecoder(response.Body).Decode(&cvesInBulk) 95 | if err != nil { 96 | return nil, err 97 | } 98 | return &cvesInBulk, nil 99 | } 100 | 101 | func (c *Cvemap) GetCvesByFilters(encodedParams string) (*types.CVEBulkData, error) { 102 | url := fmt.Sprintf("%s/cves?%s", BaseUrl, encodedParams) 103 | // Send an HTTP GET request 104 | response, err := c.makeGetRequest(url) 105 | if err != nil { 106 | return nil, err 107 | } 108 | defer response.Body.Close() 109 | // Check the response status code 110 | if response.StatusCode != http.StatusOK { 111 | return nil, errorutil.New("unexpected status code: %d", response.StatusCode) 112 | } 113 | // Create a variable to store the response data 114 | var cvesInBulk types.CVEBulkData 115 | // Decode the JSON response into an array of CVEData structs 116 | err = json.NewDecoder(response.Body).Decode(&cvesInBulk) 117 | if err != nil { 118 | return nil, err 119 | } 120 | return &cvesInBulk, nil 121 | } 122 | 123 | func (c *Cvemap) GetCvesBySearchString(query string, limit, offset int) (*types.CVEBulkData, error) { 124 | u, err := url.Parse(fmt.Sprintf("%s/cves/search", BaseUrl)) 125 | if err != nil { 126 | return nil, err 127 | } 128 | // Construct query parameters 129 | q := u.Query() 130 | q.Set("q", query) 131 | q.Set("limit", fmt.Sprintf("%v", limit)) 132 | q.Set("offset", fmt.Sprintf("%v", offset)) 133 | u.RawQuery = q.Encode() 134 | response, err := c.makeGetRequest(u.String()) 135 | if err != nil { 136 | return nil, err 137 | } 138 | defer response.Body.Close() 139 | // Check the response status code 140 | if response.StatusCode != http.StatusOK { 141 | return nil, errorutil.New("unexpected status code: %d", response.StatusCode) 142 | } 143 | // Create a variable to store the response data 144 | var cvesInBulk types.CVEBulkData 145 | // Decode the JSON response into an array of CVEData structs 146 | err = json.NewDecoder(response.Body).Decode(&cvesInBulk) 147 | if err != nil { 148 | return nil, err 149 | } 150 | return &cvesInBulk, nil 151 | } 152 | 153 | // all the root level fields are supported 154 | func (c *Cvemap) GetCvesForSpecificFields(fields []string, encodedParams string, limit, offset int) (*types.CVEBulkData, error) { 155 | url := fmt.Sprintf("%s/cves?fields=%s&%s&limit=%v&offset=%v", BaseUrl, strings.Join(fields, ","), encodedParams, limit, offset) 156 | // Send an HTTP GET request 157 | response, err := c.makeGetRequest(url) 158 | if err != nil { 159 | return nil, err 160 | } 161 | defer response.Body.Close() 162 | // Check the response status code 163 | if response.StatusCode != http.StatusOK { 164 | return nil, errorutil.New("unexpected status code: %d", response.StatusCode) 165 | } 166 | // Create a variable to store the response data 167 | var cvesInBulk types.CVEBulkData 168 | // Decode the JSON response into an array of CVEData structs 169 | err = json.NewDecoder(response.Body).Decode(&cvesInBulk) 170 | if err != nil { 171 | return nil, err 172 | } 173 | return &cvesInBulk, nil 174 | } 175 | 176 | func (c *Cvemap) makeGetRequest(url string) (*http.Response, error) { 177 | req, err := retryablehttp.NewRequest("GET", url, nil) 178 | if err != nil { 179 | gologger.Fatal().Msgf("Error creating request: %s\n", err) 180 | } 181 | req.Header.Set(xPDCPHeaderKey, c.opts.ApiKey) 182 | return c.doRequest(req) 183 | } 184 | 185 | func (c *Cvemap) doRequest(req *retryablehttp.Request) (*http.Response, error) { 186 | if c.opts.Debug { 187 | // dump request 188 | dump, err := req.Dump() 189 | if err != nil { 190 | gologger.Fatal().Msgf("Error dumping request: %s\n", err) 191 | } 192 | gologger.Print().Msgf("%s\n", string(dump)) 193 | } 194 | resp, err := c.client.Do(req) 195 | 196 | if err == nil && resp.StatusCode != http.StatusOK { 197 | if resp.StatusCode == http.StatusUnauthorized { 198 | return nil, ErrUnAuthorized 199 | } 200 | if c.opts.Debug { 201 | var errResp types.ErrorMessage 202 | err = json.NewDecoder(resp.Body).Decode(&errResp) 203 | if err == nil { 204 | return nil, errorutil.New("error %d: %s\n", resp.StatusCode, errResp.Message) 205 | } 206 | } 207 | } 208 | return resp, err 209 | } 210 | -------------------------------------------------------------------------------- /pkg/testutils/util.go: -------------------------------------------------------------------------------- 1 | package testutils 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "os/exec" 7 | "strings" 8 | ) 9 | 10 | // RunCvemapßBinaryAndGetResults returns a list of the results 11 | func RunCvemapBinaryAndGetResults(cvemapBinary string, debug bool, args []string) ([]string, error) { 12 | cmd := exec.Command("bash", "-c") 13 | cmdLine := fmt.Sprintf(`./%s `, cvemapBinary) 14 | cmdLine += strings.Join(args, " ") 15 | if debug { 16 | os.Setenv("DEBUG", "1") 17 | cmd.Stderr = os.Stderr 18 | } 19 | cmd.Args = append(cmd.Args, cmdLine) 20 | data, err := cmd.Output() 21 | if err != nil { 22 | return nil, err 23 | } 24 | parts := []string{} 25 | items := strings.Split(string(data), "\n") 26 | for _, i := range items { 27 | if i != "" { 28 | parts = append(parts, i) 29 | } 30 | } 31 | return parts, nil 32 | } 33 | 34 | // TestCase is a single integration test case 35 | type TestCase interface { 36 | // Execute executes a test case and returns any errors if occurred 37 | Execute() error 38 | } 39 | -------------------------------------------------------------------------------- /pkg/types/types.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import "time" 4 | 5 | type CVEBulkData struct { 6 | ResultCount int `json:"result_count"` 7 | TotalResults int `json:"total_results"` 8 | Cves []CVEData `json:"cves"` 9 | } 10 | 11 | type CVEData struct { 12 | CveID string `json:"cve_id,omitempty"` 13 | CveDescription string `json:"cve_description,omitempty"` 14 | Severity string `json:"severity,omitempty"` 15 | CvssScore float64 `json:"cvss_score,omitempty"` 16 | CvssMetrics *CvssMetrics `json:"cvss_metrics,omitempty"` 17 | Weaknesses []struct { 18 | CWEID string `json:"cwe_id"` 19 | CWEName string `json:"cwe_name,omitempty"` 20 | } `json:"weaknesses,omitempty"` 21 | Epss struct { 22 | Score float64 `json:"epss_score"` 23 | Percentile float64 `json:"epss_percentile"` 24 | } `json:"epss,omitempty"` 25 | Cpe *OutputCpe `json:"cpe,omitempty"` 26 | Reference []string `json:"reference,omitempty"` 27 | Poc []struct { 28 | URL string `json:"url"` 29 | Source string `json:"source"` 30 | AddedAt string `json:"added_at"` 31 | } `json:"poc,omitempty"` 32 | VendorAdvisory *string `json:"vendor_advisory,omitempty"` 33 | Patch []string `json:"patch_url,omitempty"` 34 | IsTemplate bool `json:"is_template"` 35 | NucleiTemplates *NucleiTemplates `json:"nuclei_templates,omitempty"` 36 | IsKev bool `json:"is_exploited"` 37 | Kev *KevObject `json:"kev,omitempty"` 38 | Assignee string `json:"assignee,omitempty"` 39 | PublishedAt string `json:"published_at,omitempty"` 40 | UpdatedAt string `json:"updated_at,omitempty"` 41 | Hackerone struct { 42 | Rank int `json:"rank"` 43 | Count int `json:"count"` 44 | } `json:"hackerone,omitempty"` 45 | AgeInDays int `json:"age_in_days"` 46 | VulnStatus string `json:"vuln_status,omitempty"` 47 | IsPoc bool `json:"is_poc"` 48 | IsRemote bool `json:"is_remote"` 49 | IsOss bool `json:"is_oss"` 50 | VulnerableCPE []string `json:"vulnerable_cpe,omitempty"` 51 | Shodan *OutputShodanData `json:"shodan,omitempty"` 52 | OSS *OSS `json:"oss,omitempty"` 53 | } 54 | 55 | type CvssMetrics struct { 56 | Cvss2 *Cvss2 `json:"cvss2,omitempty"` 57 | Cvss30 *Cvss30 `json:"cvss30,omitempty"` 58 | Cvss31 *Cvss31 `json:"cvss31,omitempty"` 59 | } 60 | 61 | type Cvss2 struct { 62 | Score float64 `json:"score"` 63 | Vector string `json:"vector"` 64 | Severity string `json:"severity"` 65 | } 66 | 67 | type Cvss30 struct { 68 | Score float64 `json:"score"` 69 | Vector string `json:"vector"` 70 | Severity string `json:"severity"` 71 | } 72 | 73 | type Cvss31 struct { 74 | Score float64 `json:"score"` 75 | Vector string `json:"vector"` 76 | Severity string `json:"severity"` 77 | } 78 | 79 | type NucleiTemplates struct { 80 | TemplateIssue string `json:"template_issue,omitempty"` 81 | TemplateIssueType string `json:"template_issue_type,omitempty"` 82 | TemplatePath string `json:"template_path,omitempty"` 83 | TemplatePR string `json:"template_pr,omitempty"` 84 | TemplateURL string `json:"template_url,omitempty"` 85 | CreatedAt *time.Time `json:"created_at,omitempty"` 86 | UpdatedAt *time.Time `json:"updated_at,omitempty"` 87 | } 88 | 89 | type OSS struct { 90 | AllLanguages map[string]int `json:"all_languages,omitempty"` 91 | Description string `json:"description,omitempty"` 92 | Forks int `json:"forks,omitempty"` 93 | Language string `json:"language,omitempty"` 94 | Stars int `json:"stars,omitempty"` 95 | Subscribers int `json:"subscribers,omitempty"` 96 | Topics []string `json:"topics,omitempty"` 97 | PushedAt CustomTime `json:"pushed_at,omitempty"` 98 | CreatedAt CustomTime `json:"created_at,omitempty"` 99 | UpdatedAt CustomTime `json:"updated_at,omitempty"` 100 | URL string `json:"url,omitempty"` 101 | } 102 | 103 | type CustomTime struct { 104 | time.Time 105 | } 106 | 107 | func (ct *CustomTime) UnmarshalJSON(b []byte) error { 108 | s := string(b) 109 | if s == "null" { 110 | return nil 111 | } 112 | t, err := time.Parse(`"2006-01-02 15:04:05 -0700 MST"`, s) 113 | if err != nil { 114 | return err 115 | } 116 | ct.Time = t 117 | return nil 118 | } 119 | 120 | type OutputCpe struct { 121 | Cpe *string `json:"cpe,omitempty"` 122 | Vendor *string `json:"vendor,omitempty"` 123 | Product *string `json:"product,omitempty"` 124 | Platform *string `json:"framework,omitempty"` 125 | } 126 | 127 | type KevObject struct { 128 | AddedDate string `json:"added_date"` 129 | DueDate string `json:"due_date"` 130 | KnownRansomwareCampaignUse bool `json:"known_ransomware_campaign_use"` 131 | } 132 | 133 | type OutputShodanData struct { 134 | Count int `json:"count"` 135 | Query []string `json:"query"` 136 | } 137 | 138 | type ErrorMessage struct { 139 | Message string `json:"message"` 140 | } 141 | 142 | type CVEIdList struct { 143 | Cves []string `json:"cves"` 144 | } 145 | -------------------------------------------------------------------------------- /static/cvemap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/projectdiscovery/cvemap/0ec6ce6c5d9b2740566a7fa52a35483c744b2cb2/static/cvemap.png --------------------------------------------------------------------------------