├── .devcontainer └── devcontainer.json ├── .github ├── ISSUE_TEMPLATE │ ├── config.yml │ ├── feature_request.md │ └── issue-report.md ├── dependabot.yml ├── stale.yml └── workflows │ ├── build-test.yml │ ├── codeql-analysis.yml │ ├── dockerhub-push.yml │ ├── lint-test.yml │ └── release-binary.yml ├── .gitignore ├── .goreleaser.yml ├── Dockerfile ├── LICENSE.md ├── README.md ├── README_KU.md ├── README_TR.md ├── cmd └── openrisk │ └── main.go ├── examples ├── example.go └── example_nuclei_scan.txt ├── go.mod ├── go.sum └── pkg └── openrisk ├── issue_processor.go ├── jsonl_parser.go ├── markdown_parser.go ├── openrisk.go └── types.go /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the 2 | // README at: https://github.com/devcontainers/templates/tree/main/src/go 3 | { 4 | "name": "Go", 5 | "image": "mcr.microsoft.com/devcontainers/go:0-1.20-buster", 6 | 7 | // Features to add to the dev container. More info: https://containers.dev/features. 8 | // "features": {}, 9 | 10 | // Configure tool-specific properties. 11 | "customizations": { 12 | // Configure properties specific to VS Code. 13 | "vscode": { 14 | // Set *default* container specific settings.json values on container create. 15 | "settings": { 16 | "go.toolsManagement.checkForUpdates": "local", 17 | "go.useLanguageServer": true, 18 | "go.gopath": "/go" 19 | } 20 | } 21 | }, 22 | "features": { 23 | "ghcr.io/devcontainers/features/python:1": {}, 24 | } 25 | 26 | // Use 'forwardPorts' to make a list of ports inside the container available locally. 27 | // "forwardPorts": [], 28 | 29 | // Use 'postCreateCommand' to run commands after the container is created. 30 | // "postCreateCommand": "go version", 31 | 32 | // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. 33 | // "remoteUser": "root" 34 | } 35 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | 3 | contact_links: 4 | - name: Ask an question / advise on using openrisk 5 | url: https://github.com/projectdiscovery/openrisk/discussions/categories/q-a 6 | about: Ask a question or request support for using openrisk 7 | 8 | - name: Share idea / feature to discuss for openrisk 9 | url: https://github.com/projectdiscovery/openrisk/discussions/categories/ideas 10 | about: Share idea / feature to discuss for openrisk 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 | ### openrisk 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 GitHub Actions 10 | - package-ecosystem: "github-actions" 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 | 21 | # Maintain dependencies for go modules 22 | - package-ecosystem: "gomod" 23 | directory: "/" 24 | schedule: 25 | interval: "daily" 26 | target-branch: "main" 27 | commit-message: 28 | prefix: "chore" 29 | include: "scope" 30 | labels: 31 | - "Type: Maintenance" 32 | 33 | # Maintain dependencies for docker 34 | - package-ecosystem: "docker" 35 | directory: "/" 36 | schedule: 37 | interval: "weekly" 38 | target-branch: "main" 39 | commit-message: 40 | prefix: "chore" 41 | include: "scope" 42 | labels: 43 | - "Type: Maintenance" 44 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Number of days of inactivity before an issue becomes stale 2 | daysUntilStale: 14 3 | 4 | # Number of days of inactivity before a stale issue is closed 5 | daysUntilClose: 30 6 | 7 | # Issues with these labels will never be considered stale 8 | # exemptLabels: 9 | # - pinned 10 | # - security 11 | 12 | # Only issues or pull requests with all of these labels are check if stale. 13 | onlyLabels: 14 | - "Status: Abandoned" 15 | - "Type: Question" 16 | 17 | # Label to use when marking as stale 18 | staleLabel: stale 19 | 20 | # Comment to post when marking an issue as stale. Set to `false` to disable 21 | markComment: > 22 | This issue has been automatically marked as stale because it has not had 23 | activity in the past 2 weeks. It will be closed if no further activity occurs. Thank you 24 | for your contributions. 25 | # Comment to post when closing a stale issue. Set to `false` to disable 26 | closeComment: This issue is being closed after 30 days of inactivity. Thank you. -------------------------------------------------------------------------------- /.github/workflows/build-test.yml: -------------------------------------------------------------------------------- 1 | name: 🔨 Build Test 2 | on: 3 | pull_request: 4 | workflow_dispatch: 5 | 6 | jobs: 7 | build: 8 | name: Test Builds 9 | runs-on: ${{ matrix.os }} 10 | strategy: 11 | matrix: 12 | os: [ubuntu-latest, windows-latest, macOS-latest] 13 | steps: 14 | - name: Set up Go 15 | uses: actions/setup-go@v4 16 | with: 17 | go-version: 1.20.x 18 | 19 | - name: Check out code 20 | uses: actions/checkout@v3 21 | 22 | - name: Build 23 | run: go build . 24 | working-directory: cmd/openrisk 25 | 26 | - name: Test 27 | run: go test ./... 28 | working-directory: cmd/openrisk 29 | 30 | - name: Building example 31 | # env: 32 | # OPENAI_API_KEY: ${{secrets.OPENAI_API_KEY}} 33 | run: go build . 34 | working-directory: examples/ 35 | 36 | 37 | -------------------------------------------------------------------------------- /.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/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 13 | steps: 14 | - name: Git Checkout 15 | uses: actions/checkout@v3 16 | 17 | - name: Get Github tag 18 | id: meta 19 | run: | 20 | echo "::set-output name=tag::$(curl --silent "https://api.github.com/repos/projectdiscovery/openrisk/releases/latest" | jq -r .tag_name)" 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/openrisk:latest,projectdiscovery/openrisk:${{ steps.meta.outputs.tag }} -------------------------------------------------------------------------------- /.github/workflows/lint-test.yml: -------------------------------------------------------------------------------- 1 | name: 🙏🏻 Lint Test 2 | on: 3 | pull_request: 4 | workflow_dispatch: 5 | 6 | jobs: 7 | lint: 8 | name: Lint Test 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Checkout code 12 | uses: actions/checkout@v3 13 | - name: "Set up Go" 14 | uses: actions/setup-go@v4 15 | with: 16 | go-version: 1.20.x 17 | - name: Run golangci-lint 18 | uses: golangci/golangci-lint-action@v3.4.0 19 | with: 20 | version: latest 21 | args: --timeout 5m 22 | working-directory: . -------------------------------------------------------------------------------- /.github/workflows/release-binary.yml: -------------------------------------------------------------------------------- 1 | name: 🎉 Release Binary 2 | on: 3 | push: 4 | tags: 5 | - 'v*' 6 | workflow_dispatch: 7 | 8 | jobs: 9 | release: 10 | runs-on: ubuntu-latest 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.20.x 21 | 22 | - name: "Create release on GitHub" 23 | uses: goreleaser/goreleaser-action@v4 24 | with: 25 | args: "release --rm-dist" 26 | version: latest 27 | workdir: . 28 | env: 29 | GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" -------------------------------------------------------------------------------- /.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 | openrisk 11 | !openrisk/ 12 | 13 | # Test binary, built with `go test -c` 14 | *.test 15 | 16 | # Output of the go coverage tool, specifically when used with LiteIDE 17 | *.out 18 | 19 | # Dependency directories (remove the comment below to include it) 20 | # vendor/ 21 | 22 | # Go workspace file 23 | go.work 24 | dist/* 25 | 26 | # IDE settings 27 | /.idea -------------------------------------------------------------------------------- /.goreleaser.yml: -------------------------------------------------------------------------------- 1 | before: 2 | hooks: 3 | - go mod tidy 4 | 5 | builds: 6 | - binary: '{{ .ProjectName }}' 7 | main: . 8 | 9 | goos: 10 | - windows 11 | - linux 12 | - darwin 13 | goarch: 14 | - amd64 15 | - 386 16 | - arm 17 | - arm64 18 | 19 | ignore: 20 | - goos: darwin 21 | goarch: '386' 22 | - goos: windows 23 | goarch: 'arm' 24 | - goos: windows 25 | goarch: 'arm64' 26 | 27 | archives: 28 | - format: zip 29 | replacements: 30 | darwin: macOS 31 | 32 | checksum: 33 | algorithm: sha256 34 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.18.2-alpine3.14 AS build-env 2 | RUN apk add --no-cache build-base 3 | RUN go install -v github.com/projectdiscovery/openrisk@latest 4 | 5 | FROM alpine:3.18.0 6 | RUN apk add --no-cache bind-tools ca-certificates 7 | COPY --from=build-env /go/bin/openrisk /usr/local/bin/openrisk 8 | ENTRYPOINT ["openrisk"] -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 ProjectDiscovery, Inc. 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | openrisk 3 |
4 |

5 | 6 | 7 | openrisk is an experimental tool which reads [nuclei](http://github.com/projectdiscovery/nuclei) output (text, markdown, and JSON) and generates a risk score for the host using OpenAI's GPT-3 model. It is intended, for now, to work against a single target at a time. 8 | 9 | > **NOTE**: This is an experimental program released by the ProjectDiscovery Research Team. As such, it may not meet the same code quality standards as our other projects, and may not be as well-tested. We welcome suggestions, bug fixes, and ideas on integrating these experiments into our other tools! 10 | 11 | ### Install openrisk 12 | openrisk requires **go1.20** to install successfully. Run the following command to install the latest version - 13 | 14 | ```sh 15 | go install -v github.com/projectdiscovery/openrisk@latest 16 | ``` 17 | 18 | ### Usage 19 | 20 | ```sh 21 | openrisk -h 22 | ``` 23 | 24 | ```console 25 | _ __ 26 | ____ ____ ___ ____ _____(_)____/ /__ 27 | / __ \/ __ \/ _ \/ __ \/ ___/ / ___/ //_/ 28 | / /_/ / /_/ / __/ / / / / / (__ ) ,< 29 | \____/ .___/\___/_/ /_/_/ /_/____/_/|_| Powered by OpenAI (GPT-3) 30 | /_/ v0.0.1 (experimental) 31 | projectdiscovery.io 32 | 33 | openrisk is an experimental tool generates a risk score from nuclei output for the host using OpenAI's GPT-3 model. 34 | 35 | Usage: 36 | openrisk [flags] 37 | 38 | Flags: 39 | INPUT: 40 | -f, -files string[] Nuclei scan result file or directory path. Supported file extensions: .txt, .md, .jsonl 41 | ``` 42 | 43 | > **NOTE**: `OPENAI_API_KEY` is required to run this program and can be obtained by signing up at `https://openai.com/api/` 44 | 45 | ### Generating Risk Score 46 | 47 | ```sh 48 | export OPENAI_API_KEY= 49 | 50 | openrisk -f nuclei_scan_result.txt 51 | ``` 52 | 53 | ### Example Run: 54 | 55 | ```console 56 | openrisk -f nuclei_results.txt 57 | 58 | _ __ 59 | ____ ____ ___ ____ _____(_)____/ /__ 60 | / __ \/ __ \/ _ \/ __ \/ ___/ / ___/ //_/ 61 | / /_/ / /_/ / __/ / / / / / (__ ) ,< 62 | \____/ .___/\___/_/ /_/_/ /_/____/_/|_| Powered by OpenAI (GPT-3) 63 | /_/ v0.0.1 (experimental) 64 | 65 | projectdiscovery.io 66 | 67 | [RISK SCORE] The 10-scale risk score for the Nuclei scan results is 10. There are multiple high-severity vulnerabilities related to Pantheon, AWS, and Netlify takeovers. 68 | ``` 69 | 70 | ### Using `openrisk` as a library 71 | 72 | To utilize `openrisk` as a library, simply create an instance of the `Options` structure and input your OpenAI API key. With these options, you can then create `OpenRisk` and `IssueProcessor` by including a sample nuclei scan result file. To generate a score for the sample file, call the `openRisk.GetScore` function. For a clear example, refer to the code provided in the [examples](examples/) folder. -------------------------------------------------------------------------------- /README_KU.md: -------------------------------------------------------------------------------- 1 | # openrisk 2 | 3 | openrisk amûrek ceribandî ye ku derketina nuclei (text û markdown) dixwîne û bi karanîna modela GPT-3 ya OpenAI-ê ji bo host xala rîskê çêdike. Armanc ew e, ji bo niha, ku di demekê de li dijî yek hostê bixebite. 4 | 5 | > **NOTE**: Ev bernameyek ceribandinê ye ku ji hêla Tîma Lêkolînê ya ProjectDiscovery ve hatî berdan. Bi vî rengî, dibe ku ew standardên kalîteya kodê wekî projeyên me yên din pêk neyne û dibe ku ew qas baş neyê ceribandin. Em pêşwaziya pêşniyaran, rastkirina xeletiyan, û ramanên li ser yekkirina van ceribandinan di nav amûrên me yên din de dikin! 6 | 7 | # openrisk saz bikin 8 | openrisk pêdivî ye ku **go1.20** bi serfirazî were saz kirin. Fermana jêrîn bicîh bikin ku guhertoya herî dawî saz bikin - 9 | 10 | ```sh 11 | go install -v github.com/projectdiscovery/openrisk 12 | ``` 13 | 14 | ### Bikaranîn 15 | 16 | ```sh 17 | openrisk -h 18 | ``` 19 | 20 | ```console 21 | _ __ 22 | ____ ____ ___ ____ _____(_)____/ /__ 23 | / __ \/ __ \/ _ \/ __ \/ ___/ / ___/ //_/ 24 | / /_/ / /_/ / __/ / / / / / (__ ) ,< 25 | \____/ .___/\___/_/ /_/_/ /_/____/_/|_| Powered by OpenAI (GPT-3) 26 | /_/ v0.0.1 (experimental) 27 | projectdiscovery.io 28 | 29 | Usage: 30 | openrisk [flags] 31 | 32 | Flags: 33 | INPUT: 34 | -f, -files string[] Nuclei scan result file or directory path. Supported file extensions: .txt, .md, .jsonl 35 | ``` 36 | 37 | ### Hilberîna xala riskê 38 | 39 | ```sh 40 | export OPENAI_API_KEY= 41 | openrisk -f nuclei_scan_result.txt 42 | ``` 43 | 44 | Nimûne derketin: 45 | 46 | ```console 47 | openrisk -f nuclei_results.txt 48 | 49 | _ __ 50 | ____ ____ ___ ____ _____(_)____/ /__ 51 | / __ \/ __ \/ _ \/ __ \/ ___/ / ___/ //_/ 52 | / /_/ / /_/ / __/ / / / / / (__ ) ,< 53 | \____/ .___/\___/_/ /_/_/ /_/____/_/|_| Powered by OpenAI (GPT-3) 54 | /_/ v0.0.1 (experimental) 55 | 56 | projectdiscovery.io 57 | 58 | [RISK SCORE] The 10-scale risk score for the Nuclei scan results is 10. There are multiple high-severity vulnerabilities related to Pantheon, AWS, and Netlify takeovers. 59 | ``` 60 | 61 | ### `openrisk`-ê wek library bikar anîn 62 | Ji bo bikaranîna `openrisk` wek libraryê, nimûne yekê ji `Options` ava bikin û keya API'yê ya OpenAI'yê tevlî bikin. Bi tevlîkirina pelê encama skanê ya nimûneyê ya nuclei hûn dikarin `OpenRisk` û `IssueProcessor` biafirînin. Ji bo çêkirina xala rîskê ji bo pelê nimûneyê, bang fonksiyona `openRisk.GetScore` bikin. Ji bo nimûne yekê ya diyar, referansa koda ku di peldanka [examples](examples/) de hatiye dayîn bikin. 63 | -------------------------------------------------------------------------------- /README_TR.md: -------------------------------------------------------------------------------- 1 | # openrisk 2 | 3 | openrisk, nuclei çıktısını (text ve markdown) okuyan ve OpenAI'nin GPT-3 modelini kullanarak host için bir risk puanı oluşturan deneysel bir araçtır. Şimdilik, tek seferde tek bir host -a karşı çalışması amaçlanıyor. 4 | 5 | > **NOT**: Bu, ProjectDiscovery Araştırma Ekibi tarafından yayınlanan deneysel bir programdır. Bu nedenle, diğer projelerimizle aynı kod kalite standartlarını karşılamayabilir ve iyi test edilmemiş olabilir. Önerilere, hata düzeltmelerine ve bu deneyleri diğer araçlarımıza entegre etmeye yönelik fikirlere açığız! 6 | 7 | # openrisk'i yükleyin 8 | openrisk'in başarıyla yüklenmesi için **g20** gereklidir. En son sürümü yüklemek için aşağıdaki komutu çalıştırın - 9 | 10 | ```sh 11 | go install -v github.com/projectdiscovery/openrisk 12 | ``` 13 | 14 | ### Kullanım 15 | 16 | ```sh 17 | openrisk -h 18 | ``` 19 | 20 | ```console 21 | _ __ 22 | ____ ____ ___ ____ _____(_)____/ /__ 23 | / __ \/ __ \/ _ \/ __ \/ ___/ / ___/ //_/ 24 | / /_/ / /_/ / __/ / / / / / (__ ) ,< 25 | \____/ .___/\___/_/ /_/_/ /_/____/_/|_| Powered by OpenAI (GPT-3) 26 | /_/ v0.0.1 (experimental) 27 | projectdiscovery.io 28 | 29 | Usage: 30 | openrisk [flags] 31 | 32 | Flags: 33 | INPUT: 34 | -f, -files string[] Nuclei scan result file or directory path. Supported file extensions: .txt, .md, .jsonl 35 | ``` 36 | 37 | ### Risk puanı oluşturma 38 | 39 | ```sh 40 | export OPENAI_API_KEY= 41 | openrisk -f nuclei_scan_result.txt 42 | ``` 43 | 44 | Örnek çıktı: 45 | 46 | ```console 47 | openrisk -f nuclei_results.txt 48 | 49 | _ __ 50 | ____ ____ ___ ____ _____(_)____/ /__ 51 | / __ \/ __ \/ _ \/ __ \/ ___/ / ___/ //_/ 52 | / /_/ / /_/ / __/ / / / / / (__ ) ,< 53 | \____/ .___/\___/_/ /_/_/ /_/____/_/|_| Powered by OpenAI (GPT-3) 54 | /_/ v0.0.1 (experimental) 55 | 56 | projectdiscovery.io 57 | 58 | [RISK SCORE] The 10-scale risk score for the Nuclei scan results is 10. There are multiple high-severity vulnerabilities related to Pantheon, AWS, and Netlify takeovers. 59 | ``` 60 | 61 | ### `openrisk`'i bir kütüphane olarak kullanma 62 | 63 | `openrisk`'i bir kütüphane olarak kullanmak için, `Options` örneği oluşturun ve OpenAI API anahtarınızı girin. Bu seçeneklerle, örnek bir nuclei tarama sonuç dosyasını dahil ederek `OpenRisk` ve `IssueProcessor`'u oluşturabilirsiniz. Örnek dosya için bir puan oluşturmak için, `openRisk.GetScore` fonksiyonunu çağırın. Açık bir örnek için, [örnekler](examples/) klasöründeki sağlanan koda bakın. 64 | -------------------------------------------------------------------------------- /cmd/openrisk/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "os" 7 | 8 | "github.com/projectdiscovery/goflags" 9 | "github.com/projectdiscovery/gologger" 10 | "github.com/projectdiscovery/openrisk/pkg/openrisk" 11 | ) 12 | 13 | var version = "0.0.1" 14 | 15 | var banner = fmt.Sprintf(` 16 | _ __ 17 | ____ ____ ___ ____ _____(_)____/ /__ 18 | / __ \/ __ \/ _ \/ __ \/ ___/ / ___/ //_/ 19 | / /_/ / /_/ / __/ / / / / / (__ ) ,< 20 | \____/ .___/\___/_/ /_/_/ /_/____/_/|_| Powered by OpenAI (GPT-3) 21 | /_/ v%s (experimental) 22 | `, version) 23 | 24 | func printBanner() { 25 | gologger.Print().Msgf("%s\n", banner) 26 | gologger.Print().Msgf("\t\tprojectdiscovery.io\n\n") 27 | } 28 | 29 | type CliOptions struct { 30 | Files goflags.StringSlice 31 | } 32 | 33 | var cliOptions = CliOptions{} 34 | 35 | func main() { 36 | printBanner() 37 | flagSet := goflags.NewFlagSet() 38 | flagSet.SetDescription(`openrisk is an experimental tool generates a risk score from nuclei output for the host using OpenAI's GPT-3 model.`) 39 | flagSet.CreateGroup("input", "Input", 40 | flagSet.StringSliceVarP(&cliOptions.Files, "files", "f", nil, "Nuclei scan result file or directory path. Supported file extensions: .txt, .md, .jsonl", goflags.CommaSeparatedStringSliceOptions), 41 | ) 42 | 43 | if err := flagSet.Parse(); err != nil { 44 | gologger.Error().Msg("could not parse flags") 45 | return 46 | } 47 | 48 | if len(cliOptions.Files) == 0 { 49 | gologger.Fatal().Msgf("no input provided") 50 | } 51 | 52 | apiKey, err := getApiKey() 53 | if err != nil { 54 | gologger.Fatal().Msgf("%s\n", err) 55 | } 56 | options := &openrisk.Options{ApiKey: apiKey} 57 | openRisk, _ := openrisk.New(options) 58 | 59 | for _, file := range cliOptions.Files { 60 | issues, err := openRisk.ParseIssuesWithFile(file) 61 | if err != nil { 62 | gologger.Error().Msgf("Could not parse issues: %v", err) 63 | } 64 | 65 | nucleiScan, _ := openRisk.GetScoreWithIssues(issues) 66 | gologger.Info().Label("RISK SCORE[" + file + "]").Msg(nucleiScan.Score) 67 | } 68 | } 69 | 70 | func getApiKey() (string, error) { 71 | apiKey := os.Getenv("OPENAI_API_KEY") 72 | if apiKey == "" { 73 | return "", errors.New("Environment variable for OPENAI_API_KEY is not set.") 74 | } 75 | return apiKey, nil 76 | } 77 | -------------------------------------------------------------------------------- /examples/example.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "os" 7 | 8 | "github.com/projectdiscovery/openrisk/pkg/openrisk" 9 | ) 10 | 11 | func main() { 12 | apiKey := os.Getenv("OPENAI_API_KEY") 13 | options := &openrisk.Options{ApiKey: apiKey} 14 | openRisk, err := openrisk.New(options) 15 | if err != nil { 16 | log.Fatal(err) 17 | } 18 | 19 | file := "example_nuclei_scan.txt" 20 | issues, err := openRisk.ParseIssuesWithFile(file) 21 | if err != nil { 22 | log.Fatal(err) 23 | } 24 | 25 | nucleiScan, err := openRisk.GetScoreWithIssues(issues) 26 | if err != nil { 27 | log.Fatal(err) 28 | } 29 | fmt.Println(nucleiScan.Score) 30 | } 31 | -------------------------------------------------------------------------------- /examples/example_nuclei_scan.txt: -------------------------------------------------------------------------------- 1 | __ _ 2 | ____ __ _______/ /__ (_) 3 | / __ \/ / / / ___/ / _ \/ / 4 | / / / / /_/ / /__/ / __/ / 5 | /_/ /_/\__,_/\___/_/\___/_/ v2.8.2 6 | 7 | projectdiscovery.io 8 | 9 | 10 | [WRN] Use with caution. You are responsible for your actions. 11 | [WRN] Developers assume no liability and are not responsible for any misuse or damage. 12 | [INF] Using Nuclei Engine 2.8.2 (latest) 13 | [INF] Using Nuclei Templates 9.3.1 (latest) 14 | [INF] Templates added in last update: 2 15 | [INF] Templates loaded for scan: 14 16 | [INF] Targets loaded for scan: 6 17 | [INF] Using Interactsh Server: oast.me 18 | [open-redirect] [http] [medium] http://127.0.0.1:8082/redirect?redirect_url=https%3A%2F%2Fevil.com 19 | [reflected-xss] [http] [medium] http://127.0.0.1:8082/email?text=important_user%27%22%3E%3C32511 20 | [reflected-xss] [http] [medium] http://127.0.0.1:8082/info?another=value&name=test%27%22%3E%3C32511&random=data 21 | [reflection-ssti] [http] [medium] http://127.0.0.1:8082/email?text=important_user%7B%7B7478%2A3958%7D%7D 22 | [reflected-xss] [http] [medium] http://127.0.0.1:8082/info?name=redirected_from_url%27%22%3E%3C32511 23 | [reflected-xss] [http] [medium] http://127.0.0.1:8082/request?url=https%3A%2F%2Fexample.com%27%22%3E%3C32511 24 | [blind-ssrf] [http] [medium] http://127.0.0.1:8082/request?url=https%3A%2F%2Fce9f23fkobjp303t0ti0j5xwyddrip93y.oast.me -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/projectdiscovery/openrisk 2 | 3 | go 1.20 4 | 5 | require ( 6 | github.com/projectdiscovery/goflags v0.1.8 7 | github.com/projectdiscovery/gologger v1.1.10 8 | github.com/sashabaranov/go-gpt3 v1.3.3 9 | ) 10 | 11 | require ( 12 | github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect 13 | github.com/aymerick/douceur v0.2.0 // indirect 14 | github.com/cnf/structhash v0.0.0-20201127153200-e1b16c1ebc08 // indirect 15 | github.com/dsnet/compress v0.0.1 // indirect 16 | github.com/golang/snappy v0.0.1 // indirect 17 | github.com/google/go-cmp v0.5.9 // indirect 18 | github.com/gorilla/css v1.0.0 // indirect 19 | github.com/json-iterator/go v1.1.12 // indirect 20 | github.com/logrusorgru/aurora v2.0.3+incompatible // indirect 21 | github.com/mholt/archiver v3.1.1+incompatible // indirect 22 | github.com/microcosm-cc/bluemonday v1.0.21 // indirect 23 | github.com/miekg/dns v1.1.50 // indirect 24 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 25 | github.com/modern-go/reflect2 v1.0.2 // indirect 26 | github.com/nwaples/rardecode v1.1.0 // indirect 27 | github.com/pierrec/lz4 v2.6.0+incompatible // indirect 28 | github.com/pkg/errors v0.9.1 // indirect 29 | github.com/projectdiscovery/utils v0.0.4-0.20221214110533-9f95ee986a54 // indirect 30 | github.com/rogpeppe/go-internal v1.9.0 // indirect 31 | github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca // indirect 32 | github.com/ulikunitz/xz v0.5.11 // indirect 33 | github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect 34 | golang.org/x/exp v0.0.0-20221019170559-20944726eadf // indirect 35 | golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect 36 | golang.org/x/net v0.7.0 // indirect 37 | golang.org/x/sys v0.5.0 // indirect 38 | golang.org/x/tools v0.1.12 // indirect 39 | gopkg.in/djherbis/times.v1 v1.3.0 // indirect 40 | gopkg.in/yaml.v3 v3.0.1 // indirect 41 | ) 42 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d h1:Byv0BzEl3/e6D5CLfI0j/7hiIEtvGVFPCZ7Ei2oq8iQ= 2 | github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= 3 | github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= 4 | github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= 5 | github.com/cnf/structhash v0.0.0-20201127153200-e1b16c1ebc08 h1:ox2F0PSMlrAAiAdknSRMDrAr8mfxPCfSZolH+/qQnyQ= 6 | github.com/cnf/structhash v0.0.0-20201127153200-e1b16c1ebc08/go.mod h1:pCxVEbcm3AMg7ejXyorUXi6HQCzOIBf7zEDVPtw0/U4= 7 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 8 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 9 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 10 | github.com/dsnet/compress v0.0.1 h1:PlZu0n3Tuv04TzpfPbrnI0HW/YwodEXDS+oPKahKF0Q= 11 | github.com/dsnet/compress v0.0.1/go.mod h1:Aw8dCMJ7RioblQeTqt88akK31OvO8Dhf5JflhBbQEHo= 12 | github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY= 13 | github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= 14 | github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= 15 | github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 16 | github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= 17 | github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 18 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 19 | github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= 20 | github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= 21 | github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= 22 | github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 23 | github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= 24 | github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= 25 | github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= 26 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 27 | github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= 28 | github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= 29 | github.com/mholt/archiver v3.1.1+incompatible h1:1dCVxuqs0dJseYEhi5pl7MYPH9zDa1wBi7mF09cbNkU= 30 | github.com/mholt/archiver v3.1.1+incompatible/go.mod h1:Dh2dOXnSdiLxRiPoVfIr/fI1TwETms9B8CTWfeh7ROU= 31 | github.com/microcosm-cc/bluemonday v1.0.21 h1:dNH3e4PSyE4vNX+KlRGHT5KrSvjeUkoNPwEORjffHJg= 32 | github.com/microcosm-cc/bluemonday v1.0.21/go.mod h1:ytNkv4RrDrLJ2pqlsSI46O6IVXmZOBBD4SaJyDwwTkM= 33 | github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA= 34 | github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= 35 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 36 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= 37 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 38 | github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= 39 | github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= 40 | github.com/nwaples/rardecode v1.1.0 h1:vSxaY8vQhOcVr4mm5e8XllHWTiM4JF507A0Katqw7MQ= 41 | github.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0= 42 | github.com/pierrec/lz4 v2.6.0+incompatible h1:Ix9yFKn1nSPBLFl/yZknTp8TU5G4Ps0JDmguYK6iH1A= 43 | github.com/pierrec/lz4 v2.6.0+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= 44 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 45 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 46 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 47 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 48 | github.com/projectdiscovery/goflags v0.1.8 h1:Urhm2Isq2BdRt8h4h062lHKYXO65RHRjGTDSkUwex/g= 49 | github.com/projectdiscovery/goflags v0.1.8/go.mod h1:Yxi9tclgwGczzDU65ntrwaIql5cXeTvW5j2WxFuF+Jk= 50 | github.com/projectdiscovery/gologger v1.1.10 h1:XNRdtzLTdxiFGuK9gutoL752mykzXDoii4P2yDovqck= 51 | github.com/projectdiscovery/gologger v1.1.10/go.mod h1:VqANHK7qcEq3i6/vV5HNWwdyv2aFPSrlaVDU4Ogrc6U= 52 | github.com/projectdiscovery/utils v0.0.4-0.20221214110533-9f95ee986a54 h1:/fZvw6gT1fzdmMLMBBw75OrJ0Z6g7dulQrxM9FRp1qU= 53 | github.com/projectdiscovery/utils v0.0.4-0.20221214110533-9f95ee986a54/go.mod h1:PCwA5YuCYWPgHaGiZmr53/SA9iGQmAnw7DSHuhr8VPQ= 54 | github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= 55 | github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= 56 | github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca h1:NugYot0LIVPxTvN8n+Kvkn6TrbMyxQiuvKdEwFdR9vI= 57 | github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca/go.mod h1:uugorj2VCxiV1x+LzaIdVa9b4S4qGAcH6cbhh4qVxOU= 58 | github.com/sashabaranov/go-gpt3 v1.3.3 h1:S8Zd4YybnBaNMK+w+XGGWgsjQY1R+6QE2n9SLzVna9k= 59 | github.com/sashabaranov/go-gpt3 v1.3.3/go.mod h1:BIZdbwdzxZbCrcKGMGH6u2eyGe1xFuX9Anmh3tCP8lQ= 60 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 61 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 62 | github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= 63 | github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= 64 | github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8= 65 | github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= 66 | github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo= 67 | github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= 68 | github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= 69 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 70 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 71 | golang.org/x/exp v0.0.0-20221019170559-20944726eadf h1:nFVjjKDgNY37+ZSYCJmtYf7tOlfQswHqplG2eosjOMg= 72 | golang.org/x/exp v0.0.0-20221019170559-20944726eadf/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= 73 | golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 74 | golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= 75 | golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= 76 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 77 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 78 | golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= 79 | golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 80 | golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= 81 | golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= 82 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 83 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 84 | golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw= 85 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 86 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 87 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 88 | golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 89 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 90 | golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 91 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 92 | golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= 93 | golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 94 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 95 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 96 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 97 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 98 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 99 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 100 | golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= 101 | golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= 102 | golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= 103 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 104 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 105 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 106 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 107 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= 108 | gopkg.in/djherbis/times.v1 v1.3.0 h1:uxMS4iMtH6Pwsxog094W0FYldiNnfY/xba00vq6C2+o= 109 | gopkg.in/djherbis/times.v1 v1.3.0/go.mod h1:AQlg6unIsrsCEdQYhTzERy542dz6SFdQFZFv6mUY0P8= 110 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 111 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 112 | -------------------------------------------------------------------------------- /pkg/openrisk/issue_processor.go: -------------------------------------------------------------------------------- 1 | package openrisk 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "path/filepath" 7 | "strings" 8 | 9 | "github.com/projectdiscovery/gologger" 10 | ) 11 | 12 | func (o *OpenRisk) ParseIssuesWithFile(path string) (string, error) { 13 | var issues strings.Builder 14 | 15 | err := filepath.Walk(path, func(path string, info os.FileInfo, err error) error { 16 | if err != nil { 17 | gologger.Error().Msgf("Invalid filename or directory: %v", err) 18 | return err 19 | } 20 | if !info.IsDir() { 21 | issue, err := processFile(path) 22 | if err != nil { 23 | return err 24 | } 25 | issues.WriteString(issue) 26 | } 27 | return nil 28 | }) 29 | return issues.String(), err 30 | } 31 | 32 | func processFile(path string) (string, error) { 33 | nucleiScanResult, err := os.ReadFile(path) 34 | if err != nil { 35 | return "", fmt.Errorf("Could not read the nuclei scan result: %v", err) 36 | } 37 | 38 | ext := filepath.Ext(path) 39 | switch ext { 40 | case ".jsonl": 41 | return ParseJsonL(nucleiScanResult) 42 | case ".md": 43 | return ParseMarkdown(nucleiScanResult) 44 | case ".txt": 45 | return string(nucleiScanResult), nil 46 | default: 47 | return "", fmt.Errorf("Unknown file type: %v", path) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /pkg/openrisk/jsonl_parser.go: -------------------------------------------------------------------------------- 1 | package openrisk 2 | 3 | import ( 4 | "bufio" 5 | "encoding/json" 6 | "errors" 7 | "fmt" 8 | "strings" 9 | ) 10 | 11 | func ParseJsonL(nucleiScanResult []byte) (string, error) { 12 | // Initialize the empty results string. This will be in the format "template_name,severity\n" to match the resulting 13 | // string from the Markdown parsing in parseMD() 14 | results := "" 15 | 16 | var errs []error 17 | 18 | // Loop through the lines of the file and parse each row as a JSON object as Nuclei exports the json 19 | // file as a JSON-line file 20 | scanner := bufio.NewScanner(strings.NewReader(string(nucleiScanResult))) 21 | for scanner.Scan() { 22 | line := scanner.Text() 23 | // Set the default and minimally required fields for the NucleiResult struct that are utilized in the result 24 | // parsing below 25 | result := NucleiResult{ 26 | Info: NucleiInfo{ 27 | Name: "", 28 | Severity: "", 29 | }, 30 | } 31 | //var result NucleiResult 32 | err := json.Unmarshal([]byte(line), &result) 33 | if err != nil { 34 | errs = append(errs, err) 35 | continue 36 | } 37 | results += fmt.Sprintf("%s,%s\n", result.Info.Name, result.Info.Severity) 38 | } 39 | 40 | return results, errors.Join(errs...) 41 | } 42 | -------------------------------------------------------------------------------- /pkg/openrisk/markdown_parser.go: -------------------------------------------------------------------------------- 1 | package openrisk 2 | 3 | import ( 4 | "bufio" 5 | "regexp" 6 | "strings" 7 | ) 8 | 9 | func ParseMarkdown(nucleiScanResult []byte) (string, error) { 10 | rName := regexp.MustCompile(`^\| Name \|\s*(.*)\s*\|$`) 11 | rSev := regexp.MustCompile(`^\| Severity \|\s*(.*)\s*\|$`) 12 | results := make(map[string]string) 13 | results["details"] = "" 14 | results["severity"] = "unknown" 15 | 16 | scanner := bufio.NewScanner(strings.NewReader(string(nucleiScanResult))) 17 | for scanner.Scan() { 18 | line := scanner.Text() 19 | mName := rName.FindStringSubmatch(line) 20 | if len(mName) > 0 { 21 | results["details"] = strings.TrimSpace(mName[1]) 22 | continue 23 | } 24 | 25 | mSev := rSev.FindStringSubmatch(line) 26 | if len(mSev) > 0 { 27 | results["severity"] = strings.TrimSpace(mSev[1]) 28 | continue 29 | } 30 | 31 | if mSev != nil && mName != nil { 32 | break 33 | } 34 | } 35 | 36 | return results["details"] + "," + results["severity"] + "\n", nil 37 | } 38 | -------------------------------------------------------------------------------- /pkg/openrisk/openrisk.go: -------------------------------------------------------------------------------- 1 | package openrisk 2 | 3 | import ( 4 | "bufio" 5 | "context" 6 | "errors" 7 | "regexp" 8 | "strings" 9 | 10 | gogpt "github.com/sashabaranov/go-gpt3" 11 | ) 12 | 13 | const Question = "Calculate the 10-scale risk score for the following Nuclei scan results. The format of the CSV is 'finding,severity'. Write an executive summary of vulnerabilities with 30 words max." 14 | 15 | func New(options *Options) (*OpenRisk, error) { 16 | if options.ApiKey == "" { 17 | return nil, errors.New("api key not defined") 18 | } 19 | gptClient := gogpt.NewClient(options.ApiKey) 20 | openRisk := &OpenRisk{ 21 | Options: options, 22 | client: gptClient, 23 | } 24 | return openRisk, nil 25 | 26 | } 27 | 28 | func (o *OpenRisk) GetScoreWithIssues(scanIssues string) (NucleiScan, error) { 29 | issues := reduceTokens(scanIssues) 30 | if len(issues) == 0 { 31 | return NucleiScan{Issues: scanIssues, Score: "Risk Score: 0 \nExecutive Summary: No vulnerabilities found."}, nil 32 | } 33 | 34 | prompt := buildPrompt(issues) 35 | req := buildRequest(prompt) 36 | resp, err := o.makeRequest(req) 37 | if err != nil { 38 | return NucleiScan{}, err 39 | } 40 | if len(resp.Choices) == 0 { 41 | return NucleiScan{}, errors.New("no choices returned") 42 | } 43 | return NucleiScan{Issues: scanIssues, Score: strings.TrimSpace(resp.Choices[0].Text)}, nil 44 | } 45 | 46 | func (o *OpenRisk) makeRequest(req gogpt.CompletionRequest) (gogpt.CompletionResponse, error) { 47 | return o.client.CreateCompletion(context.Background(), req) 48 | } 49 | 50 | func buildRequest(prompt string) gogpt.CompletionRequest { 51 | req := gogpt.CompletionRequest{ 52 | Model: "text-davinci-003", 53 | Temperature: 0.01, // FIXME: https://github.com/sashabaranov/go-gpt3/issues/9 54 | TopP: 1, 55 | FrequencyPenalty: 0.01, 56 | PresencePenalty: 0.01, 57 | BestOf: 1, 58 | MaxTokens: 256, 59 | Prompt: prompt, 60 | } 61 | return req 62 | } 63 | 64 | func buildPrompt(nucleiScanResult string) string { 65 | var sb strings.Builder 66 | sb.WriteString(Question) 67 | sb.WriteString("\n") 68 | sb.WriteString(nucleiScanResult) 69 | return sb.String() 70 | } 71 | 72 | func reduceTokens(issues string) string { 73 | var sb strings.Builder 74 | dateRegex := regexp.MustCompile(`^\[\d{4}\-\d{2}\-\d{2} \d{2}:\d{2}:\d{2}\] `) 75 | urlRegex := regexp.MustCompile(`(https?:\/\/)?(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#()?&//=]*)`) 76 | csvRegex := regexp.MustCompile(`\] \[?`) 77 | skipTxtRegex := regexp.MustCompile(`^(\[INF]|\[WRN]|\[ERR]|\[DBG]|\[FTL]|\s|\/|\\|\d)`) 78 | txtLine := regexp.MustCompile("^.*,.*,") 79 | scanner := bufio.NewScanner(strings.NewReader(issues)) 80 | for scanner.Scan() { 81 | line := scanner.Text() 82 | 83 | // Skip lines that start with space, \, or [ but not [YYYY-MM-DD HH:MM:SS] (txt) 84 | if skipTxtRegex.MatchString(line) { 85 | continue 86 | } 87 | 88 | // Remove the date and URL 89 | line = dateRegex.ReplaceAllString(line, "") 90 | line = urlRegex.ReplaceAllString(line, "") 91 | 92 | // Make it CSV 93 | line = csvRegex.ReplaceAllString(line, ",") 94 | line = strings.Trim(line, "[],") 95 | 96 | // Remove the protocol (txt) 97 | if txtLine.MatchString(line) { 98 | parts := strings.Split(line, ",") 99 | line = parts[0] + "," + parts[2] 100 | 101 | } 102 | 103 | // Skip info/unknown lines as they don't impact the score (md) 104 | if strings.HasSuffix(line, "info") || strings.HasSuffix(line, "unknown") { 105 | continue 106 | } 107 | 108 | // Skip lines that don't have 2 commas as it's not a valid vulnerability 109 | if strings.Count(line, ",") < 1 { 110 | continue 111 | } 112 | sb.WriteString(line + "\n") 113 | } 114 | return sb.String() 115 | } 116 | -------------------------------------------------------------------------------- /pkg/openrisk/types.go: -------------------------------------------------------------------------------- 1 | package openrisk 2 | 3 | import gogpt "github.com/sashabaranov/go-gpt3" 4 | 5 | type OpenRisk struct { 6 | Options *Options 7 | client *gogpt.Client 8 | } 9 | 10 | type Options struct { 11 | ApiKey string 12 | } 13 | 14 | type NucleiScan struct { 15 | Issues string 16 | Score string 17 | } 18 | 19 | // The JSON types do not define the entire structure of the JSON object that is exported by Nuclei, but rather only 20 | // the fields that are used in the issue list generation. This reduces the amount of data that is parsed from the JSON 21 | // file as well as reducing the risk of a change in the Nuclei JSON export format breaking the issue list generation. 22 | 23 | type NucleiInfo struct { 24 | Name string `json:"name,omitempty"` 25 | Severity string `json:"severity,omitempty"` 26 | } 27 | 28 | type NucleiResult struct { 29 | Info NucleiInfo 30 | } 31 | --------------------------------------------------------------------------------