From 5b79fc6cd389fcbf9eb317f070d93f8627426b4c Mon Sep 17 00:00:00 2001 From: "bram-star-app[bot]" <203639708+bram-star-app[bot]@users.noreply.github.com> Date: Tue, 2 Sep 2025 10:03:56 +0000 Subject: [PATCH 1/4] chore: initialize PR with an empty commit skip-checks:true From f2bd1a8f91791c411e002ded51562a0b760ad54d Mon Sep 17 00:00:00 2001 From: "bram-star-app[bot]" <203639708+bram-star-app[bot]@users.noreply.github.com> Date: Tue, 2 Sep 2025 10:14:48 +0000 Subject: [PATCH 2/4] ci: temporarily disable workflows while addressing security issues skip-checks:true --- .github/workflows/build_and_push_stable.yml | 18 ++++----- .github/workflows/build_and_push_unstable.yml | 18 ++++----- .github/workflows/check-client.yml | 33 ++++++---------- .github/workflows/check.yml | 38 +++++++------------ 4 files changed, 40 insertions(+), 67 deletions(-) diff --git a/.github/workflows/build_and_push_stable.yml b/.github/workflows/build_and_push_stable.yml index fb4885e8..9c482155 100644 --- a/.github/workflows/build_and_push_stable.yml +++ b/.github/workflows/build_and_push_stable.yml @@ -1,9 +1,10 @@ name: "Build and Push Docker Image (On Push to Stable)" - on: - push: - branches: - - stable + workflow_dispatch: +# on: +# push: +# branches: +# - stable jobs: docker-build-push: @@ -11,19 +12,15 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v4 - - name: Login to DockerHub run: | docker login --username=${{ vars.DOCKERHUB_DULL_USER }} --password=${{ secrets.DOCKERHUB_DULL_TOKEN }} - - name: Generate timestamp id: timestamp run: echo "TIMESTAMP=$(date +%Y%m%d%H%M%S)" >> $GITHUB_ENV - - name: Generate short SHA id: sha run: echo "SHORT_SHA=$(echo ${{ github.sha }} | cut -c1-6)" >> $GITHUB_ENV - - name: Build and tag Docker images run: | for TAG_PREFIX in stable unstable; do @@ -31,11 +28,10 @@ jobs: docker tag bramkor/pureflow:${TAG_PREFIX} bramkor/pureflow:${TAG_PREFIX}-${{ env.SHORT_SHA }} docker tag bramkor/pureflow:${TAG_PREFIX} bramkor/pureflow:${TAG_PREFIX}-${{ env.SHORT_SHA }}-${{ env.TIMESTAMP }} done - - name: Push Docker images - run: | + run: |- for TAG_PREFIX in stable unstable; do docker push bramkor/pureflow:${TAG_PREFIX} docker push bramkor/pureflow:${TAG_PREFIX}-${{ env.SHORT_SHA }} docker push bramkor/pureflow:${TAG_PREFIX}-${{ env.SHORT_SHA }}-${{ env.TIMESTAMP }} - done \ No newline at end of file + done diff --git a/.github/workflows/build_and_push_unstable.yml b/.github/workflows/build_and_push_unstable.yml index d6e69500..1af4801b 100644 --- a/.github/workflows/build_and_push_unstable.yml +++ b/.github/workflows/build_and_push_unstable.yml @@ -1,11 +1,13 @@ name: "Build and Push Docker Image (Manual)" on: workflow_dispatch: - inputs: - tag_prefix: - description: 'Tag prefix to use (defaults to unstable)' - required: false - default: 'unstable' +# on: +# workflow_dispatch: +# inputs: +# tag_prefix: +# description: 'Tag prefix to use (defaults to unstable)' +# required: false +# default: 'unstable' jobs: docker-build-push: @@ -13,19 +15,15 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v4 - - name: Login to DockerHub run: | docker login --username=${{ vars.DOCKERHUB_DULL_USER }} --password=${{ secrets.DOCKERHUB_DULL_TOKEN }} - - name: Generate timestamp id: timestamp run: echo "TIMESTAMP=$(date +%Y%m%d%H%M%S)" >> $GITHUB_ENV - - name: Generate short SHA id: sha run: echo "SHORT_SHA=$(echo ${{ github.sha }} | cut -c1-6)" >> $GITHUB_ENV - - name: Set tag prefix id: set_tag_prefix run: | @@ -36,13 +34,11 @@ jobs: TAG_PREFIX="${{ github.event.inputs.tag_prefix }}" fi echo "TAG_PREFIX=${TAG_PREFIX}" >> $GITHUB_ENV - - name: Build Docker image run: | docker build -t dull/pureflow:${{ env.TAG_PREFIX }} . docker tag dull/pureflow:${{ env.TAG_PREFIX }} brdullc/pureflow:${{ env.TAG_PREFIX }}-${{ env.SHORT_SHA }} docker tag dull/pureflow:${{ env.TAG_PREFIX }} brdullc/pureflow:${{ env.TAG_PREFIX }}-${{ env.SHORT_SHA }}-${{ env.TIMESTAMP }} - - name: Push Docker images run: | docker push dull/pureflow:${{ env.TAG_PREFIX }} diff --git a/.github/workflows/check-client.yml b/.github/workflows/check-client.yml index ada35f1d..2f0237b7 100644 --- a/.github/workflows/check-client.yml +++ b/.github/workflows/check-client.yml @@ -1,26 +1,23 @@ name: "React Front-End CI checks" - on: - pull_request: - branches: - - '**' - - push: - branches: - - stable - - unstable - - paths: - - 'client/**' - - '.github/workflows/*client.yml' + workflow_dispatch: +# on: +# pull_request: +# branches: +# - '**' +# push: +# branches: +# - stable +# - unstable +# paths: +# - 'client/**' +# - '.github/workflows/*client.yml' env: HUSKY: 0 - concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true - jobs: check: runs-on: ubuntu-latest @@ -30,23 +27,17 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 - - name: Setup Node.js ${{ matrix.node-version }} uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} - - name: Disable prepare script (husky) run: npm pkg delete scripts.prepare - - name: Install dependencies run: npm ci --prefix=client --no-audit - - name: Check format run: npm run format --prefix=client - - name: Lint run: npm run lint --prefix=client - - name: Build run: npm run build --prefix=client diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 409c9b86..94023959 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -1,28 +1,25 @@ name: "Nest Back-End CI checks" - on: - pull_request: - branches: - - '**' - - push: - branches: - - stable - - unstable - - paths: - - '*' - - 'src/**' - - 'test/**' - - '.github/workflows/check.yml' + workflow_dispatch: +# on: +# pull_request: +# branches: +# - '**' +# push: +# branches: +# - stable +# - unstable +# paths: +# - '*' +# - 'src/**' +# - 'test/**' +# - '.github/workflows/check.yml' env: HUSKY: 0 - concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true - jobs: check: runs-on: ubuntu-latest @@ -32,26 +29,19 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 - - name: Setup Node.js ${{ matrix.node-version }} uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} - - name: Disable prepare script (husky) run: npm pkg delete scripts.prepare - - name: Install dependencies run: npm ci --no-audit - - name: Check format run: npm run format - - name: Lint run: npm run lint - - name: Build run: npm run build - - name: Test run: npm run test From a8be2d184de5531499c9a7d16abbf21e46eb7097 Mon Sep 17 00:00:00 2001 From: "bram-star-app[bot]" <203639708+bram-star-app[bot]@users.noreply.github.com> Date: Tue, 2 Sep 2025 10:24:39 +0000 Subject: [PATCH 3/4] test: add auto-generated e2e security tests skip-checks:true --- .../delete-api-email-delete-emails.test.ts | 34 +++++++++++++ ...ig-products-crystals-some-file-jpg.test.ts | 34 +++++++++++++ .../tests/get-api-auth-dom-csrf-flow.test.ts | 35 ++++++++++++++ .../tests/get-api-auth-oidc-client.test.ts | 34 +++++++++++++ .../get-api-auth-simple-csrf-flow.test.ts | 34 +++++++++++++ .brightsec/tests/get-api-config.test.ts | 34 +++++++++++++ .../tests/get-api-email-get-emails.test.ts | 35 ++++++++++++++ .../get-api-email-send-support-email.test.ts | 35 ++++++++++++++ .brightsec/tests/get-api-file-aws.test.ts | 35 ++++++++++++++ .brightsec/tests/get-api-file-azure.test.ts | 35 ++++++++++++++ .../tests/get-api-file-digital-ocean.test.ts | 35 ++++++++++++++ .brightsec/tests/get-api-file-google.test.ts | 35 ++++++++++++++ ...fig-products-crystals-amethyst-jpg.test.ts | 35 ++++++++++++++ .brightsec/tests/get-api-file.test.ts | 35 ++++++++++++++ .brightsec/tests/get-api-goto.test.ts | 34 +++++++++++++ .../tests/get-api-nested-json-depth-1.test.ts | 35 ++++++++++++++ .../get-api-partners-partner-login.test.ts | 35 ++++++++++++++ .../tests/get-api-partners-query.test.ts | 35 ++++++++++++++ .../get-api-partners-search-partners.test.ts | 35 ++++++++++++++ .../tests/get-api-products-latest.test.ts | 35 ++++++++++++++ .../tests/get-api-products-views.test.ts | 35 ++++++++++++++ .brightsec/tests/get-api-secrets.test.ts | 34 +++++++++++++ .../tests/get-api-spawn-command.test.ts | 34 +++++++++++++ .../tests/get-api-testimonials-count.test.ts | 35 ++++++++++++++ .brightsec/tests/get-api-testimonials.test.ts | 34 +++++++++++++ .../get-api-users-fullinfo-email.test.ts | 34 +++++++++++++ .brightsec/tests/get-api-users-id-1.test.ts | 34 +++++++++++++ .brightsec/tests/get-api-users-ldap.test.ts | 34 +++++++++++++ .../tests/get-api-users-one-email.test.ts | 34 +++++++++++++ .../tests/get-api-users-search-john.test.ts | 34 +++++++++++++ .../tests/get-graphql-latest-products.test.ts | 35 ++++++++++++++ .../tests/get-graphql-select-count.test.ts | 34 +++++++++++++ .brightsec/tests/options-api-users.test.ts | 35 ++++++++++++++ .brightsec/tests/options-api.test.ts | 35 ++++++++++++++ .../tests/post-api-auth-admin-login.test.ts | 40 ++++++++++++++++ .../post-api-auth-jwt-hmac-login.test.ts | 40 ++++++++++++++++ .../tests/post-api-auth-jwt-jku-login.test.ts | 43 +++++++++++++++++ .../tests/post-api-auth-jwt-jwk-login.test.ts | 40 ++++++++++++++++ .../post-api-auth-jwt-kid-sql-login.test.ts | 43 +++++++++++++++++ .../post-api-auth-jwt-weak-key-login.test.ts | 40 ++++++++++++++++ .../tests/post-api-auth-jwt-x5c-login.test.ts | 40 ++++++++++++++++ .../tests/post-api-auth-jwt-x5u-login.test.ts | 43 +++++++++++++++++ .brightsec/tests/post-api-auth-login.test.ts | 40 ++++++++++++++++ .brightsec/tests/post-api-chat-query.test.ts | 39 +++++++++++++++ .brightsec/tests/post-api-metadata.test.ts | 36 ++++++++++++++ .brightsec/tests/post-api-render.test.ts | 36 ++++++++++++++ .../tests/post-api-subscriptions.test.ts | 34 +++++++++++++ .brightsec/tests/post-api-users-basic.test.ts | 46 ++++++++++++++++++ .brightsec/tests/post-api-users-oidc.test.ts | 48 +++++++++++++++++++ .../post-graphql-all-testimonials.test.ts | 38 +++++++++++++++ .../post-graphql-get-command-result.test.ts | 39 +++++++++++++++ .../post-graphql-latest-products.test.ts | 38 +++++++++++++++ .../post-graphql-testimonials-count.test.ts | 39 +++++++++++++++ .../tests/post-graphql-view-product.test.ts | 41 ++++++++++++++++ ...ile-raw-path-some-path-to-file-png.test.ts | 36 ++++++++++++++ 55 files changed, 2014 insertions(+) create mode 100644 .brightsec/tests/delete-api-email-delete-emails.test.ts create mode 100644 .brightsec/tests/delete-api-file-path-config-products-crystals-some-file-jpg.test.ts create mode 100644 .brightsec/tests/get-api-auth-dom-csrf-flow.test.ts create mode 100644 .brightsec/tests/get-api-auth-oidc-client.test.ts create mode 100644 .brightsec/tests/get-api-auth-simple-csrf-flow.test.ts create mode 100644 .brightsec/tests/get-api-config.test.ts create mode 100644 .brightsec/tests/get-api-email-get-emails.test.ts create mode 100644 .brightsec/tests/get-api-email-send-support-email.test.ts create mode 100644 .brightsec/tests/get-api-file-aws.test.ts create mode 100644 .brightsec/tests/get-api-file-azure.test.ts create mode 100644 .brightsec/tests/get-api-file-digital-ocean.test.ts create mode 100644 .brightsec/tests/get-api-file-google.test.ts create mode 100644 .brightsec/tests/get-api-file-raw-path-config-products-crystals-amethyst-jpg.test.ts create mode 100644 .brightsec/tests/get-api-file.test.ts create mode 100644 .brightsec/tests/get-api-goto.test.ts create mode 100644 .brightsec/tests/get-api-nested-json-depth-1.test.ts create mode 100644 .brightsec/tests/get-api-partners-partner-login.test.ts create mode 100644 .brightsec/tests/get-api-partners-query.test.ts create mode 100644 .brightsec/tests/get-api-partners-search-partners.test.ts create mode 100644 .brightsec/tests/get-api-products-latest.test.ts create mode 100644 .brightsec/tests/get-api-products-views.test.ts create mode 100644 .brightsec/tests/get-api-secrets.test.ts create mode 100644 .brightsec/tests/get-api-spawn-command.test.ts create mode 100644 .brightsec/tests/get-api-testimonials-count.test.ts create mode 100644 .brightsec/tests/get-api-testimonials.test.ts create mode 100644 .brightsec/tests/get-api-users-fullinfo-email.test.ts create mode 100644 .brightsec/tests/get-api-users-id-1.test.ts create mode 100644 .brightsec/tests/get-api-users-ldap.test.ts create mode 100644 .brightsec/tests/get-api-users-one-email.test.ts create mode 100644 .brightsec/tests/get-api-users-search-john.test.ts create mode 100644 .brightsec/tests/get-graphql-latest-products.test.ts create mode 100644 .brightsec/tests/get-graphql-select-count.test.ts create mode 100644 .brightsec/tests/options-api-users.test.ts create mode 100644 .brightsec/tests/options-api.test.ts create mode 100644 .brightsec/tests/post-api-auth-admin-login.test.ts create mode 100644 .brightsec/tests/post-api-auth-jwt-hmac-login.test.ts create mode 100644 .brightsec/tests/post-api-auth-jwt-jku-login.test.ts create mode 100644 .brightsec/tests/post-api-auth-jwt-jwk-login.test.ts create mode 100644 .brightsec/tests/post-api-auth-jwt-kid-sql-login.test.ts create mode 100644 .brightsec/tests/post-api-auth-jwt-weak-key-login.test.ts create mode 100644 .brightsec/tests/post-api-auth-jwt-x5c-login.test.ts create mode 100644 .brightsec/tests/post-api-auth-jwt-x5u-login.test.ts create mode 100644 .brightsec/tests/post-api-auth-login.test.ts create mode 100644 .brightsec/tests/post-api-chat-query.test.ts create mode 100644 .brightsec/tests/post-api-metadata.test.ts create mode 100644 .brightsec/tests/post-api-render.test.ts create mode 100644 .brightsec/tests/post-api-subscriptions.test.ts create mode 100644 .brightsec/tests/post-api-users-basic.test.ts create mode 100644 .brightsec/tests/post-api-users-oidc.test.ts create mode 100644 .brightsec/tests/post-graphql-all-testimonials.test.ts create mode 100644 .brightsec/tests/post-graphql-get-command-result.test.ts create mode 100644 .brightsec/tests/post-graphql-latest-products.test.ts create mode 100644 .brightsec/tests/post-graphql-testimonials-count.test.ts create mode 100644 .brightsec/tests/post-graphql-view-product.test.ts create mode 100644 .brightsec/tests/put-api-file-raw-path-some-path-to-file-png.test.ts diff --git a/.brightsec/tests/delete-api-email-delete-emails.test.ts b/.brightsec/tests/delete-api-email-delete-emails.test.ts new file mode 100644 index 00000000..4e01f6b1 --- /dev/null +++ b/.brightsec/tests/delete-api-email-delete-emails.test.ts @@ -0,0 +1,34 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('DELETE /api/email/deleteEmails', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'http_method_fuzzing', 'email_injection', 'improper_asset_management', 'open_database'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { databases: ['PostgreSQL'] } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.DELETE, + url: `${baseUrl}/api/email/deleteEmails` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/delete-api-file-path-config-products-crystals-some-file-jpg.test.ts b/.brightsec/tests/delete-api-file-path-config-products-crystals-some-file-jpg.test.ts new file mode 100644 index 00000000..92c7ddef --- /dev/null +++ b/.brightsec/tests/delete-api-file-path-config-products-crystals-some-file-jpg.test.ts @@ -0,0 +1,34 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('DELETE /api/file?path=config/products/crystals/some_file.jpg', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['lfi', 'bopla', 'ssrf', 'sqli', 'csrf'], + attackParamLocations: [AttackParamLocation.QUERY], + starMetadata: { databases: ['PostgreSQL'] } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.DELETE, + url: `${baseUrl}/api/file?path=config/products/crystals/some_file.jpg` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-api-auth-dom-csrf-flow.test.ts b/.brightsec/tests/get-api-auth-dom-csrf-flow.test.ts new file mode 100644 index 00000000..8aad62c0 --- /dev/null +++ b/.brightsec/tests/get-api-auth-dom-csrf-flow.test.ts @@ -0,0 +1,35 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('GET /api/auth/dom-csrf-flow', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'full_path_disclosure', 'secret_tokens'], + attackParamLocations: [AttackParamLocation.HEADER], + starMetadata: { databases: ['PostgreSQL'] } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/api/auth/dom-csrf-flow`, + headers: { fingerprint: 'example-fingerprint' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-api-auth-oidc-client.test.ts b/.brightsec/tests/get-api-auth-oidc-client.test.ts new file mode 100644 index 00000000..2b74b2bf --- /dev/null +++ b/.brightsec/tests/get-api-auth-oidc-client.test.ts @@ -0,0 +1,34 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('GET /api/auth/oidc-client', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'secret_tokens', 'insecure_tls_configuration', 'unvalidated_redirect'], + attackParamLocations: [AttackParamLocation.HEADER, AttackParamLocation.PATH], + starMetadata: { databases: ['PostgreSQL'] } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/api/auth/oidc-client` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-api-auth-simple-csrf-flow.test.ts b/.brightsec/tests/get-api-auth-simple-csrf-flow.test.ts new file mode 100644 index 00000000..91e12d23 --- /dev/null +++ b/.brightsec/tests/get-api-auth-simple-csrf-flow.test.ts @@ -0,0 +1,34 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('GET /api/auth/simple-csrf-flow', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'xss', 'full_path_disclosure'], + attackParamLocations: [AttackParamLocation.PATH, AttackParamLocation.QUERY], + starMetadata: { databases: ['PostgreSQL'] } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/api/auth/simple-csrf-flow` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-api-config.test.ts b/.brightsec/tests/get-api-config.test.ts new file mode 100644 index 00000000..6af807db --- /dev/null +++ b/.brightsec/tests/get-api-config.test.ts @@ -0,0 +1,34 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('GET /api/config', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['improper_asset_management', 'secret_tokens', 'csrf', 'xss', 'full_path_disclosure'], + attackParamLocations: [AttackParamLocation.PATH, AttackParamLocation.QUERY, AttackParamLocation.HEADER], + starMetadata: { databases: ['PostgreSQL'] } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/api/config` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-api-email-get-emails.test.ts b/.brightsec/tests/get-api-email-get-emails.test.ts new file mode 100644 index 00000000..922c736f --- /dev/null +++ b/.brightsec/tests/get-api-email-get-emails.test.ts @@ -0,0 +1,35 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('GET /api/email/getEmails', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['proto_pollution', 'business_constraint_bypass', 'improper_asset_management'], + attackParamLocations: [AttackParamLocation.QUERY], + starMetadata: { databases: ['PostgreSQL'] } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/api/email/getEmails?withSource=true`, + headers: { 'Content-Type': 'application/json' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-api-email-send-support-email.test.ts b/.brightsec/tests/get-api-email-send-support-email.test.ts new file mode 100644 index 00000000..cd09d91f --- /dev/null +++ b/.brightsec/tests/get-api-email-send-support-email.test.ts @@ -0,0 +1,35 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('GET /api/email/sendSupportEmail', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['proto_pollution', 'email_injection', 'xss'], + attackParamLocations: [AttackParamLocation.QUERY], + starMetadata: { databases: ['PostgreSQL'] } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/api/email/sendSupportEmail?name=Bob%20Dylan&to=username%40email.com&subject=Help%20Request&content=I%20would%20like%20to%20request%20help%20regarding..`, + headers: { 'Content-Type': 'application/json' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-api-file-aws.test.ts b/.brightsec/tests/get-api-file-aws.test.ts new file mode 100644 index 00000000..c145674b --- /dev/null +++ b/.brightsec/tests/get-api-file-aws.test.ts @@ -0,0 +1,35 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('GET /api/file/aws', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['amazon_s3_takeover', 'open_cloud_storage', 'ssrf', 'lfi', 'unvalidated_redirect'], + attackParamLocations: [AttackParamLocation.QUERY, AttackParamLocation.HEADER], + starMetadata: { databases: ['PostgreSQL'] } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/api/file/aws?path=config/products/crystals/amethyst.jpg&type=image/jpg`, + headers: { accept: 'image/jpg' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-api-file-azure.test.ts b/.brightsec/tests/get-api-file-azure.test.ts new file mode 100644 index 00000000..28e3a184 --- /dev/null +++ b/.brightsec/tests/get-api-file-azure.test.ts @@ -0,0 +1,35 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('GET /api/file/azure', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['ssrf', 'lfi', 'open_cloud_storage', 'unvalidated_redirect'], + attackParamLocations: [AttackParamLocation.QUERY], + starMetadata: { databases: ['PostgreSQL'] } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/api/file/azure?path=config/products/crystals/amethyst.jpg&type=image/jpg`, + headers: { accept: 'image/jpg' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-api-file-digital-ocean.test.ts b/.brightsec/tests/get-api-file-digital-ocean.test.ts new file mode 100644 index 00000000..4a8042fe --- /dev/null +++ b/.brightsec/tests/get-api-file-digital-ocean.test.ts @@ -0,0 +1,35 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('GET /api/file/digital_ocean', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['ssrf', 'lfi', 'open_cloud_storage', 'file_upload'], + attackParamLocations: [AttackParamLocation.QUERY], + starMetadata: { databases: ['PostgreSQL'] } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/api/file/digital_ocean?path=config/products/crystals/amethyst.jpg&type=image/jpg`, + headers: { accept: 'image/jpg' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-api-file-google.test.ts b/.brightsec/tests/get-api-file-google.test.ts new file mode 100644 index 00000000..94311105 --- /dev/null +++ b/.brightsec/tests/get-api-file-google.test.ts @@ -0,0 +1,35 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('GET /api/file/google?path=config/products/crystals/amethyst.jpg&type=image/jpg', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['ssrf', 'lfi', 'open_cloud_storage', 'file_upload'], + attackParamLocations: [AttackParamLocation.QUERY], + starMetadata: { databases: ['PostgreSQL'] } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/api/file/google?path=config/products/crystals/amethyst.jpg&type=image/jpg`, + headers: { accept: 'image/jpg' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-api-file-raw-path-config-products-crystals-amethyst-jpg.test.ts b/.brightsec/tests/get-api-file-raw-path-config-products-crystals-amethyst-jpg.test.ts new file mode 100644 index 00000000..f6e1bc2a --- /dev/null +++ b/.brightsec/tests/get-api-file-raw-path-config-products-crystals-amethyst-jpg.test.ts @@ -0,0 +1,35 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('GET /api/file/raw?path=config/products/crystals/amethyst.jpg', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['lfi', 'ssrf', 'full_path_disclosure', 'open_cloud_storage', 'unvalidated_redirect'], + attackParamLocations: [AttackParamLocation.QUERY], + starMetadata: { databases: ['PostgreSQL'] } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/api/file/raw?path=config/products/crystals/amethyst.jpg`, + headers: { accept: 'image/jpg' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-api-file.test.ts b/.brightsec/tests/get-api-file.test.ts new file mode 100644 index 00000000..b22e812c --- /dev/null +++ b/.brightsec/tests/get-api-file.test.ts @@ -0,0 +1,35 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('GET /api/file', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['lfi', 'ssrf', 'file_upload', 'open_cloud_storage', 'full_path_disclosure'], + attackParamLocations: [AttackParamLocation.QUERY], + starMetadata: { databases: ['PostgreSQL'] } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/api/file?path=config/products/crystals/amethyst.jpg&type=image/jpg`, + headers: { accept: 'image/jpg' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-api-goto.test.ts b/.brightsec/tests/get-api-goto.test.ts new file mode 100644 index 00000000..32a30e02 --- /dev/null +++ b/.brightsec/tests/get-api-goto.test.ts @@ -0,0 +1,34 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('GET /api/goto', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['unvalidated_redirect', 'ssrf'], + attackParamLocations: [AttackParamLocation.QUERY], + starMetadata: { databases: ['PostgreSQL'] } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/api/goto?url=https://google.com` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-api-nested-json-depth-1.test.ts b/.brightsec/tests/get-api-nested-json-depth-1.test.ts new file mode 100644 index 00000000..a465f2b7 --- /dev/null +++ b/.brightsec/tests/get-api-nested-json-depth-1.test.ts @@ -0,0 +1,35 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('GET /api/nestedJson?depth=1', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['business_constraint_bypass', 'xss', 'sqli', 'osi', 'csrf'], + attackParamLocations: [AttackParamLocation.QUERY], + starMetadata: { databases: ['PostgreSQL'] } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/api/nestedJson?depth=1`, + headers: { 'Content-Type': 'application/json' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-api-partners-partner-login.test.ts b/.brightsec/tests/get-api-partners-partner-login.test.ts new file mode 100644 index 00000000..ff7366a1 --- /dev/null +++ b/.brightsec/tests/get-api-partners-partner-login.test.ts @@ -0,0 +1,35 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('GET /api/partners/partnerLogin', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['xpathi', 'xss', 'full_path_disclosure'], + attackParamLocations: [AttackParamLocation.QUERY], + starMetadata: { databases: ['PostgreSQL'] } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/api/partners/partnerLogin?username=walter100&password=Heisenberg123`, + headers: { 'Content-Type': 'text/xml' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-api-partners-query.test.ts b/.brightsec/tests/get-api-partners-query.test.ts new file mode 100644 index 00000000..a59bd0ef --- /dev/null +++ b/.brightsec/tests/get-api-partners-query.test.ts @@ -0,0 +1,35 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('GET /api/partners/query', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['xpathi', 'xxe', 'full_path_disclosure'], + attackParamLocations: [AttackParamLocation.QUERY], + starMetadata: { databases: ['PostgreSQL'] } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/api/partners/query?xpath=%2Fpartners%2Fpartner%2Fname`, + headers: { 'Content-Type': 'text/xml' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-api-partners-search-partners.test.ts b/.brightsec/tests/get-api-partners-search-partners.test.ts new file mode 100644 index 00000000..701e4f81 --- /dev/null +++ b/.brightsec/tests/get-api-partners-search-partners.test.ts @@ -0,0 +1,35 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('GET /api/partners/searchPartners', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['xpathi', 'xss', 'csrf', 'full_path_disclosure'], + attackParamLocations: [AttackParamLocation.QUERY, AttackParamLocation.HEADER], + starMetadata: { databases: ['PostgreSQL'] } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/api/partners/searchPartners?keyword=Walter`, + headers: { 'Content-Type': 'text/xml' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-api-products-latest.test.ts b/.brightsec/tests/get-api-products-latest.test.ts new file mode 100644 index 00000000..63c2ae4c --- /dev/null +++ b/.brightsec/tests/get-api-products-latest.test.ts @@ -0,0 +1,35 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('GET /api/products/latest', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['business_constraint_bypass', 'sqli', 'date_manipulation'], + attackParamLocations: [AttackParamLocation.QUERY], + starMetadata: { databases: ['PostgreSQL'] }, + skipStaticParams: false + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/api/products/latest?limit=3` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-api-products-views.test.ts b/.brightsec/tests/get-api-products-views.test.ts new file mode 100644 index 00000000..c84e9e69 --- /dev/null +++ b/.brightsec/tests/get-api-products-views.test.ts @@ -0,0 +1,35 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('GET /api/products/views', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['sqli', 'business_constraint_bypass', 'full_path_disclosure'], + attackParamLocations: [AttackParamLocation.HEADER], + starMetadata: { databases: ['PostgreSQL'] } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/api/products/views`, + headers: { 'x-product-name': 'Amethyst' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-api-secrets.test.ts b/.brightsec/tests/get-api-secrets.test.ts new file mode 100644 index 00000000..86191258 --- /dev/null +++ b/.brightsec/tests/get-api-secrets.test.ts @@ -0,0 +1,34 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('get-api-secrets', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['secret_tokens', 'csrf', 'improper_asset_management'], + attackParamLocations: [AttackParamLocation.HEADER], + starMetadata: { databases: ['PostgreSQL'] } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/api/secrets` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-api-spawn-command.test.ts b/.brightsec/tests/get-api-spawn-command.test.ts new file mode 100644 index 00000000..0c3f569b --- /dev/null +++ b/.brightsec/tests/get-api-spawn-command.test.ts @@ -0,0 +1,34 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('GET /api/spawn?command=:command', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['osi', 'csrf', 'full_path_disclosure'], + attackParamLocations: [AttackParamLocation.QUERY], + starMetadata: { databases: ['PostgreSQL'] } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/api/spawn?command=ls%20-la` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-api-testimonials-count.test.ts b/.brightsec/tests/get-api-testimonials-count.test.ts new file mode 100644 index 00000000..8b20c8c2 --- /dev/null +++ b/.brightsec/tests/get-api-testimonials-count.test.ts @@ -0,0 +1,35 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('GET /api/testimonials/count', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['sqli', 'full_path_disclosure', 'business_constraint_bypass'], + attackParamLocations: [AttackParamLocation.QUERY], + starMetadata: { databases: ['PostgreSQL'] } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/api/testimonials/count?query=select%20count(*)%20as%20count%20from%20testimonial`, + headers: { 'Content-Type': 'text/html' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-api-testimonials.test.ts b/.brightsec/tests/get-api-testimonials.test.ts new file mode 100644 index 00000000..60af2266 --- /dev/null +++ b/.brightsec/tests/get-api-testimonials.test.ts @@ -0,0 +1,34 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('GET /api/testimonials', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['sqli', 'csrf', 'xss', 'business_constraint_bypass'], + attackParamLocations: [AttackParamLocation.QUERY, AttackParamLocation.PATH], + starMetadata: { databases: ['PostgreSQL'] } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/api/testimonials` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-api-users-fullinfo-email.test.ts b/.brightsec/tests/get-api-users-fullinfo-email.test.ts new file mode 100644 index 00000000..b6cc37a7 --- /dev/null +++ b/.brightsec/tests/get-api-users-fullinfo-email.test.ts @@ -0,0 +1,34 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('GET /api/users/fullinfo/:email', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['id_enumeration', 'csrf', 'xss', 'ldap_injection', 'open_database'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { databases: ['PostgreSQL'] } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/api/users/fullinfo/john.doe@example.com` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-api-users-id-1.test.ts b/.brightsec/tests/get-api-users-id-1.test.ts new file mode 100644 index 00000000..8f452faa --- /dev/null +++ b/.brightsec/tests/get-api-users-id-1.test.ts @@ -0,0 +1,34 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('GET /api/users/id/1', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['id_enumeration', 'bopla', 'sqli', 'xss', 'csrf'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { databases: ['PostgreSQL'] } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/api/users/id/1` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-api-users-ldap.test.ts b/.brightsec/tests/get-api-users-ldap.test.ts new file mode 100644 index 00000000..2d461136 --- /dev/null +++ b/.brightsec/tests/get-api-users-ldap.test.ts @@ -0,0 +1,34 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('GET /api/users/ldap', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['ldapi', 'id_enumeration', 'full_path_disclosure', 'csrf'], + attackParamLocations: [AttackParamLocation.QUERY], + starMetadata: { databases: ['PostgreSQL'] } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/api/users/ldap?query=%28%26%28objectClass%3Dperson%29%28objectClass%3Duser%29%28email%3Djohn.doe%40example.com%29%29` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-api-users-one-email.test.ts b/.brightsec/tests/get-api-users-one-email.test.ts new file mode 100644 index 00000000..d8245687 --- /dev/null +++ b/.brightsec/tests/get-api-users-one-email.test.ts @@ -0,0 +1,34 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('GET /api/users/one/:email', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['id_enumeration', 'csrf', 'xss', 'ldap_injection', 'sqli', 'xxe'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { databases: ['PostgreSQL'] } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/api/users/one/john.doe@example.com` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-api-users-search-john.test.ts b/.brightsec/tests/get-api-users-search-john.test.ts new file mode 100644 index 00000000..f0a48815 --- /dev/null +++ b/.brightsec/tests/get-api-users-search-john.test.ts @@ -0,0 +1,34 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('GET /api/users/search/john', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['xss', 'sqli', 'id_enumeration', 'business_constraint_bypass'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { databases: ['PostgreSQL'] } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/api/users/search/john` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-graphql-latest-products.test.ts b/.brightsec/tests/get-graphql-latest-products.test.ts new file mode 100644 index 00000000..0f9b9ec2 --- /dev/null +++ b/.brightsec/tests/get-graphql-latest-products.test.ts @@ -0,0 +1,35 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('GET /graphql-latest-products', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['graphql_introspection', 'bopla', 'jwt', 'sqli', 'xss'], + attackParamLocations: [AttackParamLocation.QUERY, AttackParamLocation.HEADER], + starMetadata: { databases: ['PostgreSQL'] } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/graphql?query=%7B%0A%20%20latestProducts%20%7B%0A%20%20%20%20id%0A%20%20%20%20name%0A%20%20%20%20price%0A%20%20%7D%0A%7D`, + headers: { Authorization: 'Bearer ' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-graphql-select-count.test.ts b/.brightsec/tests/get-graphql-select-count.test.ts new file mode 100644 index 00000000..cb878fe7 --- /dev/null +++ b/.brightsec/tests/get-graphql-select-count.test.ts @@ -0,0 +1,34 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('GET /graphql-select-count', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['graphql_introspection', 'sqli', 'csrf', 'xss'], + attackParamLocations: [AttackParamLocation.QUERY], + starMetadata: { databases: ['PostgreSQL'] } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/graphql?query=SELECT%20COUNT(*)%20FROM%20testimonials` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/options-api-users.test.ts b/.brightsec/tests/options-api-users.test.ts new file mode 100644 index 00000000..0f9ad417 --- /dev/null +++ b/.brightsec/tests/options-api-users.test.ts @@ -0,0 +1,35 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('OPTIONS /api/users', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['http_method_fuzzing', 'csrf', 'insecure_tls_configuration'], + attackParamLocations: [AttackParamLocation.HEADER], + starMetadata: { databases: ['PostgreSQL'] } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.OPTIONS, + url: `${baseUrl}/api/users`, + headers: { 'Access-Control-Request-Headers': 'OPTIONS, GET, POST, DELETE' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/options-api.test.ts b/.brightsec/tests/options-api.test.ts new file mode 100644 index 00000000..4bf700da --- /dev/null +++ b/.brightsec/tests/options-api.test.ts @@ -0,0 +1,35 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('OPTIONS /api', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['http_method_fuzzing', 'secret_tokens', 'open_database'], + attackParamLocations: [AttackParamLocation.HEADER], + starMetadata: { databases: ['PostgreSQL'] } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.OPTIONS, + url: `${baseUrl}/api`, + headers: { allow: 'OPTIONS, GET, HEAD, POST' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/post-api-auth-admin-login.test.ts b/.brightsec/tests/post-api-auth-admin-login.test.ts new file mode 100644 index 00000000..d3718e92 --- /dev/null +++ b/.brightsec/tests/post-api-auth-admin-login.test.ts @@ -0,0 +1,40 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('POST /api/auth/admin/login', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'jwt', 'sqli', 'osi', 'unvalidated_redirect'], + attackParamLocations: [AttackParamLocation.BODY], + starMetadata: { databases: ['PostgreSQL'] } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.POST, + url: `${baseUrl}/api/auth/admin/login`, + body: { + user: 'john', + password: 'Pa55w0rd', + op: 'basic' + }, + headers: { 'Content-Type': 'application/json' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/post-api-auth-jwt-hmac-login.test.ts b/.brightsec/tests/post-api-auth-jwt-hmac-login.test.ts new file mode 100644 index 00000000..4746d0cb --- /dev/null +++ b/.brightsec/tests/post-api-auth-jwt-hmac-login.test.ts @@ -0,0 +1,40 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('POST /api/auth/jwt/hmac/login', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['jwt', 'csrf', 'sqli', 'xss', 'secret_tokens'], + attackParamLocations: [AttackParamLocation.BODY], + starMetadata: { databases: ['PostgreSQL'] } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.POST, + url: `${baseUrl}/api/auth/jwt/hmac/login`, + body: { + user: 'john', + password: 'Pa55w0rd', + op: 'basic' + }, + headers: { 'Content-Type': 'application/json' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/post-api-auth-jwt-jku-login.test.ts b/.brightsec/tests/post-api-auth-jwt-jku-login.test.ts new file mode 100644 index 00000000..46d39e18 --- /dev/null +++ b/.brightsec/tests/post-api-auth-jwt-jku-login.test.ts @@ -0,0 +1,43 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('POST /api/auth/jwt/jku/login', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['jwt', 'csrf', 'sqli', 'osi', 'xss'], + attackParamLocations: [AttackParamLocation.BODY, AttackParamLocation.HEADER], + starMetadata: { databases: ['PostgreSQL'] } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.POST, + url: `${baseUrl}/api/auth/jwt/jku/login`, + body: { + user: 'john', + password: 'Pa55w0rd', + op: 'basic' + }, + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiam9obkBleGFtcGxlLmNvbSIsImV4cCI6MTYwOTI3MzYwMH0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c' + } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/post-api-auth-jwt-jwk-login.test.ts b/.brightsec/tests/post-api-auth-jwt-jwk-login.test.ts new file mode 100644 index 00000000..58660e7c --- /dev/null +++ b/.brightsec/tests/post-api-auth-jwt-jwk-login.test.ts @@ -0,0 +1,40 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('POST /api/auth/jwt/jwk/login', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['jwt', 'csrf', 'sqli', 'osi', 'secret_tokens'], + attackParamLocations: [AttackParamLocation.BODY], + starMetadata: { databases: ['PostgreSQL'] } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.POST, + url: `${baseUrl}/api/auth/jwt/jwk/login`, + body: { + user: 'john', + password: 'Pa55w0rd', + op: 'basic' + }, + headers: { 'Content-Type': 'application/json' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/post-api-auth-jwt-kid-sql-login.test.ts b/.brightsec/tests/post-api-auth-jwt-kid-sql-login.test.ts new file mode 100644 index 00000000..14de468a --- /dev/null +++ b/.brightsec/tests/post-api-auth-jwt-kid-sql-login.test.ts @@ -0,0 +1,43 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('POST /api/auth/jwt/kid-sql/login', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['sqli', 'jwt', 'csrf', 'xss', 'osi'], + attackParamLocations: [AttackParamLocation.BODY, AttackParamLocation.HEADER], + starMetadata: { databases: ['PostgreSQL'] } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.POST, + url: `${baseUrl}/api/auth/jwt/kid-sql/login`, + body: { + user: 'john', + password: 'Pa55w0rd', + op: 'basic' + }, + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiam9obiIsImV4cCI6MTYwOTI4MjQwMH0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c' + } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/post-api-auth-jwt-weak-key-login.test.ts b/.brightsec/tests/post-api-auth-jwt-weak-key-login.test.ts new file mode 100644 index 00000000..a4dea4f4 --- /dev/null +++ b/.brightsec/tests/post-api-auth-jwt-weak-key-login.test.ts @@ -0,0 +1,40 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('POST /api/auth/jwt/weak-key/login', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['jwt', 'csrf', 'sqli', 'secret_tokens'], + attackParamLocations: [AttackParamLocation.BODY], + starMetadata: { databases: ['PostgreSQL'] } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.POST, + url: `${baseUrl}/api/auth/jwt/weak-key/login`, + body: { + user: 'john', + password: 'Pa55w0rd', + op: 'basic' + }, + headers: { 'Content-Type': 'application/json' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/post-api-auth-jwt-x5c-login.test.ts b/.brightsec/tests/post-api-auth-jwt-x5c-login.test.ts new file mode 100644 index 00000000..bb83e275 --- /dev/null +++ b/.brightsec/tests/post-api-auth-jwt-x5c-login.test.ts @@ -0,0 +1,40 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('POST /api/auth/jwt/x5c/login', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['jwt', 'csrf', 'sqli', 'osi', 'unvalidated_redirect'], + attackParamLocations: [AttackParamLocation.BODY], + starMetadata: { databases: ['PostgreSQL'] } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.POST, + url: `${baseUrl}/api/auth/jwt/x5c/login`, + body: { + user: 'john', + password: 'Pa55w0rd', + op: 'basic' + }, + headers: { 'Content-Type': 'application/json' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/post-api-auth-jwt-x5u-login.test.ts b/.brightsec/tests/post-api-auth-jwt-x5u-login.test.ts new file mode 100644 index 00000000..2f79e78b --- /dev/null +++ b/.brightsec/tests/post-api-auth-jwt-x5u-login.test.ts @@ -0,0 +1,43 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('POST /api/auth/jwt/x5u/login', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['jwt', 'csrf', 'sqli', 'xss', 'open_database'], + attackParamLocations: [AttackParamLocation.BODY, AttackParamLocation.HEADER], + starMetadata: { databases: ['PostgreSQL'] } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.POST, + url: `${baseUrl}/api/auth/jwt/x5u/login`, + body: { + user: 'john', + password: 'Pa55w0rd', + op: 'basic' + }, + headers: { + 'Content-Type': 'application/json', + Authorization: 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiam9obiIsImV4cCI6MTYwOTI3MzYwMH0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c' + } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/post-api-auth-login.test.ts b/.brightsec/tests/post-api-auth-login.test.ts new file mode 100644 index 00000000..be8ea6b9 --- /dev/null +++ b/.brightsec/tests/post-api-auth-login.test.ts @@ -0,0 +1,40 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('POST /api/auth/login', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'jwt', 'sqli', 'xss', 'osi', 'secret_tokens'], + attackParamLocations: [AttackParamLocation.BODY], + starMetadata: { databases: ['PostgreSQL'] } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.POST, + url: `${baseUrl}/api/auth/login`, + body: { + user: 'john', + password: 'Pa55w0rd', + op: 'basic' + }, + headers: { 'Content-Type': 'application/json' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/post-api-chat-query.test.ts b/.brightsec/tests/post-api-chat-query.test.ts new file mode 100644 index 00000000..f60314fc --- /dev/null +++ b/.brightsec/tests/post-api-chat-query.test.ts @@ -0,0 +1,39 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('POST /api/chat/query', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'prompt_injection', 'secret_tokens', 'server_side_js_injection', 'ssrf'], + attackParamLocations: [AttackParamLocation.BODY, AttackParamLocation.HEADER], + starMetadata: { databases: ['PostgreSQL'] } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.POST, + url: `${baseUrl}/api/chat/query`, + body: [{ role: 'user', content: 'Hello, how are you?' }], + headers: { + 'Content-Type': 'application/json', + Authorization: 'Bearer YOUR_API_TOKEN' + } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/post-api-metadata.test.ts b/.brightsec/tests/post-api-metadata.test.ts new file mode 100644 index 00000000..d9b5d784 --- /dev/null +++ b/.brightsec/tests/post-api-metadata.test.ts @@ -0,0 +1,36 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('POST /api/metadata', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['xxe', 'xss', 'open_database', 'osi'], + attackParamLocations: [AttackParamLocation.BODY, AttackParamLocation.HEADER], + starMetadata: { databases: ['PostgreSQL'] } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.POST, + url: `${baseUrl}/api/metadata`, + body: `\u003csvg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" viewBox=\"0 0 915 585\"\u003e\u003cg stroke-width=\"3.45\" fill=\"none\"\u003e\u003cpath stroke=\"#000\" d=\"M11.8 11.8h411v411l-411 .01v-411z\"/\u003e\u003cpath stroke=\"#448\" d=\"M489 11.7h415v411H489v-411z\"/\u003e\u003c/g\u003e\u003c/svg\u003e`, + headers: { 'Content-Type': 'text/xml' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/post-api-render.test.ts b/.brightsec/tests/post-api-render.test.ts new file mode 100644 index 00000000..4a4e0166 --- /dev/null +++ b/.brightsec/tests/post-api-render.test.ts @@ -0,0 +1,36 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('POST /api/render', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['ssti', 'xss', 'osi'], + attackParamLocations: [AttackParamLocation.BODY], + starMetadata: { databases: ['PostgreSQL'] } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.POST, + url: `${baseUrl}/api/render`, + body: "Write your text here", + headers: { 'Content-Type': 'text/plain' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/post-api-subscriptions.test.ts b/.brightsec/tests/post-api-subscriptions.test.ts new file mode 100644 index 00000000..05dd301c --- /dev/null +++ b/.brightsec/tests/post-api-subscriptions.test.ts @@ -0,0 +1,34 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('POST /api/subscriptions', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'email_injection', 'xss', 'stored_xss', 'unvalidated_redirect'], + attackParamLocations: [AttackParamLocation.QUERY], + starMetadata: { databases: ['PostgreSQL'] } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.POST, + url: `${baseUrl}/api/subscriptions?email=john.doe@example.com` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/post-api-users-basic.test.ts b/.brightsec/tests/post-api-users-basic.test.ts new file mode 100644 index 00000000..22d40c3c --- /dev/null +++ b/.brightsec/tests/post-api-users-basic.test.ts @@ -0,0 +1,46 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('POST /api/users/basic', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['bopla', 'csrf', 'email_injection', 'sqli', 'xss'], + attackParamLocations: [AttackParamLocation.BODY], + starMetadata: { databases: ['PostgreSQL'] } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.POST, + url: `${baseUrl}/api/users/basic`, + body: { + email: 'john.doe@example.com', + firstName: 'John', + lastName: 'Doe', + company: 'Dull Security', + id: 1, + cardNumber: '4263982640269299', + phoneNumber: '12065550100', + password: 'Pa55w0rd', + op: 'basic' + }, + headers: { 'Content-Type': 'application/json' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/post-api-users-oidc.test.ts b/.brightsec/tests/post-api-users-oidc.test.ts new file mode 100644 index 00000000..431264a3 --- /dev/null +++ b/.brightsec/tests/post-api-users-oidc.test.ts @@ -0,0 +1,48 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('POST /api/users/oidc', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['bopla', 'csrf', 'ldapi', 'osi', 'sqli', 'xss'], + attackParamLocations: [AttackParamLocation.BODY], + starMetadata: { + databases: ['PostgreSQL'] + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.POST, + url: `${baseUrl}/api/users/oidc`, + body: { + email: 'john.doe@example.com', + firstName: 'John', + lastName: 'Doe', + company: 'Dull Security', + id: 1, + cardNumber: '4263982640269299', + phoneNumber: '12065550100', + password: 'Pa55w0rd', + op: 'oidc' + }, + headers: { 'Content-Type': 'application/json' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/post-graphql-all-testimonials.test.ts b/.brightsec/tests/post-graphql-all-testimonials.test.ts new file mode 100644 index 00000000..c4414906 --- /dev/null +++ b/.brightsec/tests/post-graphql-all-testimonials.test.ts @@ -0,0 +1,38 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('POST /graphql allTestimonials', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['graphql_introspection', 'bopla', 'sqli', 'xss', 'csrf'], + attackParamLocations: [AttackParamLocation.BODY], + starMetadata: { databases: ['PostgreSQL'] } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.POST, + url: `${baseUrl}/graphql`, + body: { + query: "query { allTestimonials { name title message } }" + }, + headers: { 'Content-Type': 'application/json' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/post-graphql-get-command-result.test.ts b/.brightsec/tests/post-graphql-get-command-result.test.ts new file mode 100644 index 00000000..cbae3ed7 --- /dev/null +++ b/.brightsec/tests/post-graphql-get-command-result.test.ts @@ -0,0 +1,39 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('POST /graphql getCommandResult', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['osi', 'graphql_introspection', 'xss', 'full_path_disclosure'], + attackParamLocations: [AttackParamLocation.BODY], + starMetadata: { databases: ['PostgreSQL'] } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.POST, + url: `${baseUrl}/graphql`, + body: { + query: "query getCommandResult($command: String!) { getCommandResult(command: $command) }", + variables: { command: "ls -la" } + }, + headers: { 'Content-Type': 'application/json' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/post-graphql-latest-products.test.ts b/.brightsec/tests/post-graphql-latest-products.test.ts new file mode 100644 index 00000000..c457100e --- /dev/null +++ b/.brightsec/tests/post-graphql-latest-products.test.ts @@ -0,0 +1,38 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('POST /graphql latestProducts', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['sqli', 'csrf', 'graphql_introspection', 'xss'], + attackParamLocations: [AttackParamLocation.BODY], + starMetadata: { databases: ['PostgreSQL'] } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.POST, + url: `${baseUrl}/graphql`, + body: { + query: `query latestProducts { latestProducts { name category photoUrl description viewsCount } }` + }, + headers: { 'Content-Type': 'application/json' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/post-graphql-testimonials-count.test.ts b/.brightsec/tests/post-graphql-testimonials-count.test.ts new file mode 100644 index 00000000..9db85958 --- /dev/null +++ b/.brightsec/tests/post-graphql-testimonials-count.test.ts @@ -0,0 +1,39 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('POST /graphql testimonialsCount', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['graphql_introspection', 'sqli', 'xss', 'csrf'], + attackParamLocations: [AttackParamLocation.BODY], + starMetadata: { databases: ['PostgreSQL'] } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.POST, + url: `${baseUrl}/graphql`, + body: { + query: "query testimonialsCount($query: String!) { testimonialsCount(query: $query) }", + variables: { query: "SELECT COUNT(*) FROM testimonials" } + }, + headers: { 'Content-Type': 'application/json' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/post-graphql-view-product.test.ts b/.brightsec/tests/post-graphql-view-product.test.ts new file mode 100644 index 00000000..5f344156 --- /dev/null +++ b/.brightsec/tests/post-graphql-view-product.test.ts @@ -0,0 +1,41 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('POST /graphql viewProduct', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['sqli', 'csrf', 'graphql_introspection', 'bopla', 'xss'], + attackParamLocations: [AttackParamLocation.BODY, AttackParamLocation.HEADER], + starMetadata: { databases: ['PostgreSQL'] } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.POST, + url: `${baseUrl}/graphql`, + body: { + query: "mutation { viewProduct(productName: \"Amethyst\") }" + }, + headers: { + 'Content-Type': 'application/json', + 'x-product-name': 'Amethyst' + } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/put-api-file-raw-path-some-path-to-file-png.test.ts b/.brightsec/tests/put-api-file-raw-path-some-path-to-file-png.test.ts new file mode 100644 index 00000000..8354bd50 --- /dev/null +++ b/.brightsec/tests/put-api-file-raw-path-some-path-to-file-png.test.ts @@ -0,0 +1,36 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('PUT /api/file/raw?path=some/path/to/file.png', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['file_upload', 'lfi', 'ssrf', 'osi', 'full_path_disclosure'], + attackParamLocations: [AttackParamLocation.QUERY, AttackParamLocation.BODY], + starMetadata: { databases: ['PostgreSQL'] } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.PUT, + url: `${baseUrl}/api/file/raw?path=some/path/to/file.png`, + body: 'Sample raw file content', + headers: { 'Content-Type': 'text/plain' } + }); +}); \ No newline at end of file From 7ef133d27fe2fe9866384e21f7af49f300ec7b8d Mon Sep 17 00:00:00 2001 From: "bram-star-app[bot]" <203639708+bram-star-app[bot]@users.noreply.github.com> Date: Tue, 2 Sep 2025 10:24:53 +0000 Subject: [PATCH 4/4] ci: add CI workflow to run e2e security tests --- .github/workflows/bright.yml | 61 +++++++++++++++++++ .../configure-bright-credentials/action.yaml | 53 ++++++++++++++++ 2 files changed, 114 insertions(+) create mode 100644 .github/workflows/bright.yml create mode 100644 .github/workflows/composite/configure-bright-credentials/action.yaml diff --git a/.github/workflows/bright.yml b/.github/workflows/bright.yml new file mode 100644 index 00000000..481a62a0 --- /dev/null +++ b/.github/workflows/bright.yml @@ -0,0 +1,61 @@ +name: Bright + +on: + pull_request: + branches: + - '**' + +permissions: + checks: write + contents: read + id-token: write + +jobs: + test: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js 18.x + uses: actions/setup-node@v4 + with: + node-version: 18.x + + - name: Install application dependencies + run: npm ci --no-audit + + - name: Start application + run: docker compose --file=compose.local.yml up --wait + + - name: Verify application readiness + run: | + until nc -zv 127.0.0.1 3000; do + echo "Waiting for application to be ready..." + sleep 5 + done + + - name: Setup Node.js 22.x + uses: actions/setup-node@v4 + with: + node-version: 22.x + + - name: Install SecTesterJS dependencies + run: npm i --save=false --prefix .brightsec @sectester/core @sectester/repeater @sectester/scan @sectester/runner @sectester/reporter + + - name: Authenticate with Bright + uses: ./.github/workflows/composite/configure-bright-credentials + with: + BRIGHT_HOSTNAME: https://development.playground.brightsec.com + BRIGHT_PROJECT_ID: mk3WHe9kadEadK4FBGQsEu + BRIGHT_TOKEN: ${{ secrets.BRIGHT_TOKEN }} + + - name: Run security tests + env: + BRIGHT_HOSTNAME: https://development.playground.brightsec.com + BRIGHT_PROJECT_ID: mk3WHe9kadEadK4FBGQsEu + BRIGHT_AUTH_ID: ${{ vars.BRIGHT_AUTH_ID }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + BRIGHT_TOKEN: ${{ env.BRIGHT_TOKEN }} + BRIGHT_TARGET_URL: http://127.0.0.1:3000 + run: node --experimental-transform-types --experimental-strip-types --experimental-detect-module --disable-warning=MODULE_TYPELESS_PACKAGE_JSON --disable-warning=ExperimentalWarning --test-force-exit --test-concurrency=4 --test .brightsec/tests/*.test.ts \ No newline at end of file diff --git a/.github/workflows/composite/configure-bright-credentials/action.yaml b/.github/workflows/composite/configure-bright-credentials/action.yaml new file mode 100644 index 00000000..84983846 --- /dev/null +++ b/.github/workflows/composite/configure-bright-credentials/action.yaml @@ -0,0 +1,53 @@ +name: 'Configure BrightSec credentials' + +inputs: + BRIGHT_HOSTNAME: + description: 'Hostname for the BrightSec environment' + required: true + BRIGHT_PROJECT_ID: + description: 'Project ID for BrightSec' + required: true + BRIGHT_TOKEN: + description: 'Pre-configured token' + required: false + +runs: + using: 'composite' + steps: + - id: configure_env_from_input + name: 'Set existing token in env' + shell: bash + if: ${{ inputs.BRIGHT_TOKEN != '' }} + env: + BRIGHT_TOKEN: ${{ inputs.BRIGHT_TOKEN }} + run: | + echo "BRIGHT_TOKEN=${BRIGHT_TOKEN}" >> $GITHUB_ENV + + - id: configure_bright_credentials_through_oidc + name: 'Exchange OIDC credentials for Bright token' + shell: bash + if: ${{ inputs.BRIGHT_TOKEN == '' }} + env: + BRIGHT_HOSTNAME: ${{ inputs.BRIGHT_HOSTNAME }} + BRIGHT_PROJECT_ID: ${{ inputs.BRIGHT_PROJECT_ID }} + run: | + # Retrieve OIDC token from GitHub + OIDC_TOKEN=$(curl -sS -H "Authorization: Bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \ + "${ACTIONS_ID_TOKEN_REQUEST_URL}" | jq -r '.value') + + # Post the token to BrightSec + RESPONSE=$(curl -s -X POST "https://${BRIGHT_HOSTNAME}/api/v1/projects/${BRIGHT_PROJECT_ID}/api-keys/oidc" \ + -H "Content-Type: application/json" \ + -d "{\"token\": \"${OIDC_TOKEN}\"}") + + if ! echo "$RESPONSE" | jq -e . > /dev/null 2>&1; then + echo "Error: $RESPONSE" 1>&2 + exit 1 + fi + + # Extract the pureKey + PURE_KEY=$(echo "$RESPONSE" | jq -r '.pureKey') + + # Mask and store in environment + echo "::add-mask::$PURE_KEY" + echo "BRIGHT_TOKEN=$PURE_KEY" >> $GITHUB_ENV