diff --git a/.brightsec/tests/delete-api-addresses-1.test.ts b/.brightsec/tests/delete-api-addresses-1.test.ts new file mode 100644 index 00000000000..6df3f4d7e03 --- /dev/null +++ b/.brightsec/tests/delete-api-addresses-1.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('DELETE /api/addresses/1', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'id_enumeration', 'bopla', 'sqli', 'xss'], + attackParamLocations: [AttackParamLocation.PATH, AttackParamLocation.HEADER], + starMetadata: { + code_source: 'tssbox/juice-shop:master', + databases: ['SQLite'], + user_roles: { + roles: ['customer', 'deluxe', 'accounting', 'admin'] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.DELETE, + url: `${baseUrl}/api/addresses/1`, + headers: { 'X-Recruiting': 'true' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/delete-api-basketitems-1.test.ts b/.brightsec/tests/delete-api-basketitems-1.test.ts new file mode 100644 index 00000000000..8459c045589 --- /dev/null +++ b/.brightsec/tests/delete-api-basketitems-1.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('DELETE /api/BasketItems/1', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'bopla', 'id_enumeration', 'sqli', 'xss'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { + code_source: 'tssbox/juice-shop:master', + databases: ['SQLite'], + user_roles: { + roles: ['customer', 'deluxe', 'accounting', 'admin'] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.DELETE, + url: `${baseUrl}/api/BasketItems/1`, + headers: { 'Content-Type': 'application/json' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/delete-api-cards-1.test.ts b/.brightsec/tests/delete-api-cards-1.test.ts new file mode 100644 index 00000000000..6340260d3a3 --- /dev/null +++ b/.brightsec/tests/delete-api-cards-1.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('DELETE /api/cards/1', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'bopla', 'id_enumeration', 'xss', 'sqli'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { + code_source: 'tssbox/juice-shop:master', + databases: ['SQLite'], + user_roles: { + roles: ['customer', 'deluxe', 'accounting', 'admin'] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.DELETE, + url: `${baseUrl}/api/cards/1` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/delete-api-feedbacks-1.test.ts b/.brightsec/tests/delete-api-feedbacks-1.test.ts new file mode 100644 index 00000000000..3d6da7848a8 --- /dev/null +++ b/.brightsec/tests/delete-api-feedbacks-1.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('DELETE /api/feedbacks/1', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'id_enumeration', 'bopla', 'sqli', 'xss'], + attackParamLocations: [AttackParamLocation.PATH, AttackParamLocation.HEADER], + starMetadata: { + code_source: 'tssbox/juice-shop:master', + databases: ['SQLite'], + user_roles: { + roles: ['customer', 'deluxe', 'accounting', 'admin'] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.DELETE, + url: `${baseUrl}/api/Feedbacks/1`, + headers: { 'X-Recruiting': '' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-api-addresses-1.test.ts b/.brightsec/tests/get-api-addresses-1.test.ts new file mode 100644 index 00000000000..4a0be5c191e --- /dev/null +++ b/.brightsec/tests/get-api-addresses-1.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('GET /api/addresses/1', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['id_enumeration', 'bopla', 'sqli', 'csrf', 'xss'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { + code_source: "tssbox/juice-shop:master", + databases: ["SQLite"], + user_roles: { + roles: ["customer", "deluxe", "accounting", "admin"] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/api/Addresses/1` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-api-addresss.test.ts b/.brightsec/tests/get-api-addresss.test.ts new file mode 100644 index 00000000000..68107d85f94 --- /dev/null +++ b/.brightsec/tests/get-api-addresss.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('GET /api/addresss', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['bopla', 'csrf', 'xss', 'sqli', 'id_enumeration'], + attackParamLocations: [AttackParamLocation.HEADER], + starMetadata: { + code_source: 'tssbox/juice-shop:master', + databases: ['SQLite'], + user_roles: { + roles: ['customer', 'deluxe', 'accounting', 'admin'] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/api/Addresss`, + headers: { 'X-Recruiting': '' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-api-basket-items-1.test.ts b/.brightsec/tests/get-api-basket-items-1.test.ts new file mode 100644 index 00000000000..c46aa5eee60 --- /dev/null +++ b/.brightsec/tests/get-api-basket-items-1.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('GET /api/basket-items/1', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['bopla', 'id_enumeration', 'sqli', 'xss'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { + code_source: 'tssbox/juice-shop:master', + databases: ['SQLite'], + user_roles: { + roles: ['customer', 'deluxe', 'accounting', 'admin'] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/api/BasketItems/1`, + headers: { 'Content-Type': 'application/json' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-api-basket-items.test.ts b/.brightsec/tests/get-api-basket-items.test.ts new file mode 100644 index 00000000000..5189d7cd5a5 --- /dev/null +++ b/.brightsec/tests/get-api-basket-items.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('GET /api/basket-items', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['bopla', 'business_constraint_bypass', 'sqli', 'xss'], + attackParamLocations: [AttackParamLocation.HEADER], + starMetadata: { + code_source: 'tssbox/juice-shop:master', + databases: ['SQLite'], + user_roles: { + roles: ['customer', 'deluxe', 'accounting', 'admin'] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/api/BasketItems`, + headers: { + 'X-Recruiting': 'We are hiring! Visit https://owasp.org/www-project-juice-shop/' + } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-api-cards-1.test.ts b/.brightsec/tests/get-api-cards-1.test.ts new file mode 100644 index 00000000000..a33f51e2b70 --- /dev/null +++ b/.brightsec/tests/get-api-cards-1.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('GET /api/cards/1', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['bopla', 'id_enumeration', 'sqli', 'xss', 'csrf'], + attackParamLocations: [AttackParamLocation.PATH, AttackParamLocation.HEADER], + starMetadata: { + code_source: 'tssbox/juice-shop:master', + databases: ['SQLite'], + user_roles: { + roles: ['customer', 'deluxe', 'accounting', 'admin'] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/api/Cards/1`, + headers: { 'X-Recruiting': '' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-api-cards.test.ts b/.brightsec/tests/get-api-cards.test.ts new file mode 100644 index 00000000000..a3db33080ea --- /dev/null +++ b/.brightsec/tests/get-api-cards.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('GET /api/cards', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'bopla', 'id_enumeration', 'xss', 'sqli'], + attackParamLocations: [AttackParamLocation.HEADER], + starMetadata: { + code_source: 'tssbox/juice-shop:master', + databases: ['SQLite'], + user_roles: { + roles: ['customer', 'deluxe', 'accounting', 'admin'] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/api/cards`, + headers: { 'X-Recruiting': '' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-api-challenges.test.ts b/.brightsec/tests/get-api-challenges.test.ts new file mode 100644 index 00000000000..0e49d974acc --- /dev/null +++ b/.brightsec/tests/get-api-challenges.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('GET /api/challenges', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['xss', 'bopla', 'business_constraint_bypass', 'id_enumeration'], + attackParamLocations: [AttackParamLocation.QUERY], + starMetadata: { + code_source: "tssbox/juice-shop:master", + databases: ["SQLite"], + user_roles: { + roles: ["customer", "deluxe", "accounting", "admin"] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/api/Challenges?param=value` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-api-complaints.test.ts b/.brightsec/tests/get-api-complaints.test.ts new file mode 100644 index 00000000000..b4490d8e5f6 --- /dev/null +++ b/.brightsec/tests/get-api-complaints.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('GET /api/complaints', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'id_enumeration', 'xss', 'sqli', 'bopla'], + attackParamLocations: [AttackParamLocation.HEADER], + starMetadata: { + code_source: 'tssbox/juice-shop:master', + databases: ['SQLite'], + user_roles: { + roles: ['customer', 'deluxe', 'accounting', 'admin'] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/api/Complaints`, + headers: { 'X-Recruiting': '' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-api-docs.test.ts b/.brightsec/tests/get-api-docs.test.ts new file mode 100644 index 00000000000..3923c1949e2 --- /dev/null +++ b/.brightsec/tests/get-api-docs.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('GET /api-docs', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['xss', 'csrf', 'improper_asset_management', 'full_path_disclosure'], + attackParamLocations: [AttackParamLocation.HEADER], + starMetadata: { + code_source: "tssbox/juice-shop:master", + databases: ["SQLite"], + user_roles: { + roles: ["customer", "deluxe", "accounting", "admin"] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/api-docs`, + headers: { 'X-Recruiting': '' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-api-feedbacks-1.test.ts b/.brightsec/tests/get-api-feedbacks-1.test.ts new file mode 100644 index 00000000000..28179dac88d --- /dev/null +++ b/.brightsec/tests/get-api-feedbacks-1.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('GET /api/feedbacks/1', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['id_enumeration', 'bopla', 'xss', 'sqli', 'csrf'], + attackParamLocations: [AttackParamLocation.PATH, AttackParamLocation.HEADER], + starMetadata: { + code_source: 'tssbox/juice-shop:master', + databases: ['SQLite'], + user_roles: { + roles: ['customer', 'deluxe', 'accounting', 'admin'] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/api/Feedbacks/1`, + headers: { 'X-Recruiting': '' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-api-feedbacks.test.ts b/.brightsec/tests/get-api-feedbacks.test.ts new file mode 100644 index 00000000000..de58e85e73e --- /dev/null +++ b/.brightsec/tests/get-api-feedbacks.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('GET /api/feedbacks', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['xss', 'id_enumeration', 'business_constraint_bypass', 'sqli'], + attackParamLocations: [AttackParamLocation.QUERY], + starMetadata: { + code_source: 'tssbox/juice-shop:master', + databases: ['SQLite'], + user_roles: { + roles: ['customer', 'deluxe', 'accounting', 'admin'] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/api/Feedbacks?param=value` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-api-hints-1.test.ts b/.brightsec/tests/get-api-hints-1.test.ts new file mode 100644 index 00000000000..7e9098c342c --- /dev/null +++ b/.brightsec/tests/get-api-hints-1.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('GET /api/hints/1', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['bopla', 'id_enumeration', 'xss', 'sqli'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { + code_source: 'tssbox/juice-shop:master', + databases: ['SQLite'], + user_roles: { + roles: ['customer', 'deluxe', 'accounting', 'admin'] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/api/Hints/1` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-api-hints.test.ts b/.brightsec/tests/get-api-hints.test.ts new file mode 100644 index 00000000000..463a326b523 --- /dev/null +++ b/.brightsec/tests/get-api-hints.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('GET /api/hints', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['bopla', 'xss', 'improper_asset_management', 'sqli'], + attackParamLocations: [AttackParamLocation.PATH, AttackParamLocation.QUERY], + starMetadata: { + code_source: 'tssbox/juice-shop:master', + databases: ['SQLite'], + user_roles: { + roles: ['customer', 'deluxe', 'accounting', 'admin'] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/api/Hints` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-api-privacy-requests.test.ts b/.brightsec/tests/get-api-privacy-requests.test.ts new file mode 100644 index 00000000000..a6ad6350a57 --- /dev/null +++ b/.brightsec/tests/get-api-privacy-requests.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('GET /api/privacy-requests', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'bopla', 'id_enumeration', 'improper_asset_management', 'xss'], + attackParamLocations: [AttackParamLocation.HEADER], + starMetadata: { + code_source: "tssbox/juice-shop:master", + databases: ["SQLite"], + user_roles: { + roles: ["customer", "deluxe", "accounting", "admin"] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/api/PrivacyRequests`, + headers: { 'X-Recruiting': 'true' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-api-products-1.test.ts b/.brightsec/tests/get-api-products-1.test.ts new file mode 100644 index 00000000000..cc08c6e316f --- /dev/null +++ b/.brightsec/tests/get-api-products-1.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('GET /api/products/1', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['xss', 'sqli', 'id_enumeration', 'business_constraint_bypass'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { + code_source: 'tssbox/juice-shop:master', + databases: ['SQLite'], + user_roles: { + roles: ['customer', 'deluxe', 'accounting', 'admin'] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/api/Products/1` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-api-products.test.ts b/.brightsec/tests/get-api-products.test.ts new file mode 100644 index 00000000000..6c0558683a8 --- /dev/null +++ b/.brightsec/tests/get-api-products.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('GET /api/products', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['sqli', 'xss', 'business_constraint_bypass', 'full_path_disclosure'], + attackParamLocations: [AttackParamLocation.PATH, AttackParamLocation.QUERY], + starMetadata: { + code_source: 'tssbox/juice-shop:master', + databases: ['SQLite'], + user_roles: { + roles: ['customer', 'deluxe', 'accounting', 'admin'] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/api/Products` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-api-quantitys-1.test.ts b/.brightsec/tests/get-api-quantitys-1.test.ts new file mode 100644 index 00000000000..a6ebed9e7a5 --- /dev/null +++ b/.brightsec/tests/get-api-quantitys-1.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('GET /api/quantitys/1', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['bopla', 'id_enumeration', 'csrf', 'xss'], + attackParamLocations: [AttackParamLocation.PATH, AttackParamLocation.HEADER], + starMetadata: { + code_source: 'tssbox/juice-shop:master', + databases: ['SQLite'], + user_roles: { + roles: ['customer', 'deluxe', 'accounting', 'admin'] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/api/Quantitys/1`, + headers: { 'X-Recruiting': '' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-api-quantitys.test.ts b/.brightsec/tests/get-api-quantitys.test.ts new file mode 100644 index 00000000000..7f9272198e7 --- /dev/null +++ b/.brightsec/tests/get-api-quantitys.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('GET /api/quantitys', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['bopla', 'business_constraint_bypass', 'id_enumeration', 'sqli', 'xss'], + attackParamLocations: [AttackParamLocation.PATH, AttackParamLocation.QUERY], + starMetadata: { + code_source: 'tssbox/juice-shop:master', + databases: ['SQLite'], + user_roles: { + roles: ['customer', 'deluxe', 'accounting', 'admin'] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/api/Quantitys` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-api-recycles-1.test.ts b/.brightsec/tests/get-api-recycles-1.test.ts new file mode 100644 index 00000000000..9c422fd27f3 --- /dev/null +++ b/.brightsec/tests/get-api-recycles-1.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('GET /api/recycles/1', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['sqli', 'id_enumeration', 'full_path_disclosure', 'xss'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { + code_source: "tssbox/juice-shop:master", + databases: ["SQLite"], + user_roles: { + roles: ["customer", "deluxe", "accounting", "admin"] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/api/Recycles/1` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-api-security-questions.test.ts b/.brightsec/tests/get-api-security-questions.test.ts new file mode 100644 index 00000000000..ff927b38638 --- /dev/null +++ b/.brightsec/tests/get-api-security-questions.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('GET /api/security-questions', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'id_enumeration', 'xss', 'sqli', 'nosql'], + attackParamLocations: [AttackParamLocation.QUERY], + starMetadata: { + code_source: 'tssbox/juice-shop:master', + databases: ['SQLite'], + user_roles: { + roles: ['customer', 'deluxe', 'accounting', 'admin'] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/api/SecurityQuestions?email=user@example.com` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-assets-i18n.test.ts b/.brightsec/tests/get-assets-i18n.test.ts new file mode 100644 index 00000000000..1857aae42fd --- /dev/null +++ b/.brightsec/tests/get-assets-i18n.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('GET /assets/i18n', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['full_path_disclosure', 'xss', 'lfi', 'ssrf'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { + code_source: 'tssbox/juice-shop:master', + databases: ['SQLite'], + user_roles: { + roles: ['customer', 'deluxe', 'accounting', 'admin'] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/assets/i18n` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-assets-public-images-padding.test.ts b/.brightsec/tests/get-assets-public-images-padding.test.ts new file mode 100644 index 00000000000..4a1234c3e41 --- /dev/null +++ b/.brightsec/tests/get-assets-public-images-padding.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('GET /assets/public/images/padding', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['xss', 'csrf', 'improper_asset_management'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { + code_source: 'tssbox/juice-shop:master', + databases: ['SQLite'], + user_roles: { + roles: ['customer', 'deluxe', 'accounting', 'admin'] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/assets/public/images/padding` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-assets-public-images-products.test.ts b/.brightsec/tests/get-assets-public-images-products.test.ts new file mode 100644 index 00000000000..d8ee86e1fc2 --- /dev/null +++ b/.brightsec/tests/get-assets-public-images-products.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('GET /assets/public/images/products', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'xss', 'improper_asset_management', 'lfi'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { + code_source: 'tssbox/juice-shop:master', + databases: ['SQLite'], + user_roles: { + roles: ['customer', 'deluxe', 'accounting', 'admin'] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/assets/public/images/products` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-assets-public-images-uploads.test.ts b/.brightsec/tests/get-assets-public-images-uploads.test.ts new file mode 100644 index 00000000000..c662cdc496b --- /dev/null +++ b/.brightsec/tests/get-assets-public-images-uploads.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('GET /assets/public/images/uploads', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['xss', 'lfi', 'file_upload', 'full_path_disclosure', 'improper_asset_management'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { + code_source: 'tssbox/juice-shop:master', + databases: ['SQLite'], + user_roles: { + roles: ['customer', 'deluxe', 'accounting', 'admin'] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/assets/public/images/uploads` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-dataerasure.test.ts b/.brightsec/tests/get-dataerasure.test.ts new file mode 100644 index 00000000000..e62a49ba2b0 --- /dev/null +++ b/.brightsec/tests/get-dataerasure.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('GET /dataerasure', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'xss', 'lfi', 'bopla'], + attackParamLocations: [AttackParamLocation.HEADER], + starMetadata: { + code_source: "tssbox/juice-shop:master", + databases: ["SQLite"], + user_roles: { + roles: ["customer", "deluxe", "accounting", "admin"] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/dataerasure`, + headers: { 'X-Recruiting': 'We are hiring! Visit our careers page for more information.' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-encryptionkeys-samplefile-txt.test.ts b/.brightsec/tests/get-encryptionkeys-samplefile-txt.test.ts new file mode 100644 index 00000000000..a6330610974 --- /dev/null +++ b/.brightsec/tests/get-encryptionkeys-samplefile-txt.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('GET /encryptionkeys/samplefile.txt', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['lfi', 'full_path_disclosure', 'improper_asset_management'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { + code_source: 'tssbox/juice-shop:master', + databases: ['SQLite'], + user_roles: { + roles: ['customer', 'deluxe', 'accounting', 'admin'] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/encryptionkeys/samplefile.txt` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-encryptionkeys-samplefile.test.ts b/.brightsec/tests/get-encryptionkeys-samplefile.test.ts new file mode 100644 index 00000000000..8ae5b24e018 --- /dev/null +++ b/.brightsec/tests/get-encryptionkeys-samplefile.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('GET /encryptionkeys/samplefile', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['directoryListingChallenge', 'accessLogDisclosureChallenge', 'xss', 'csrf', 'lfi'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { + code_source: "tssbox/juice-shop:master", + databases: ["SQLite"], + user_roles: { + roles: ["customer", "deluxe", "accounting", "admin"] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/encryptionkeys/samplefile` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-ftp-acquisitions-md.test.ts b/.brightsec/tests/get-ftp-acquisitions-md.test.ts new file mode 100644 index 00000000000..34485438c76 --- /dev/null +++ b/.brightsec/tests/get-ftp-acquisitions-md.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('GET /ftp/acquisitions.md', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['lfi', 'full_path_disclosure', 'directory_listing', 'xss'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { + code_source: "tssbox/juice-shop:master", + databases: ["SQLite"], + user_roles: { + roles: ["customer", "deluxe", "accounting", "admin"] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/ftp/acquisitions.md` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-ftp-quarantine-juicy-malware-linux-amd-64-url.test.ts b/.brightsec/tests/get-ftp-quarantine-juicy-malware-linux-amd-64-url.test.ts new file mode 100644 index 00000000000..20e451b19fa --- /dev/null +++ b/.brightsec/tests/get-ftp-quarantine-juicy-malware-linux-amd-64-url.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('GET /ftp/quarantine/juicy_malware_linux_amd_64.url', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['test/api/ftpFolderSpec.ts', 'test/cypress/e2e/publicFtp.spec.ts'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { + code_source: "tssbox/juice-shop:master", + databases: ["SQLite"], + user_roles: { + roles: ["customer", "deluxe", "accounting", "admin"] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/ftp/quarantine/juicy_malware_linux_amd_64.url` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-ftp-sample-md.test.ts b/.brightsec/tests/get-ftp-sample-md.test.ts new file mode 100644 index 00000000000..3288b9d73be --- /dev/null +++ b/.brightsec/tests/get-ftp-sample-md.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('GET /ftp/sample.md', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['lfi', 'xss', 'secret_tokens', 'full_path_disclosure', 'css_injection'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { + code_source: "tssbox/juice-shop:master", + databases: ["SQLite"], + user_roles: { + roles: ["customer", "deluxe", "accounting", "admin"] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/ftp/sample.md` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-ftp-test-pdf.test.ts b/.brightsec/tests/get-ftp-test-pdf.test.ts new file mode 100644 index 00000000000..494589f81f4 --- /dev/null +++ b/.brightsec/tests/get-ftp-test-pdf.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('GET /ftp/test.pdf', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['lfi', 'file_upload', 'full_path_disclosure', 'xss'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { + code_source: 'tssbox/juice-shop:master', + databases: ['SQLite'], + user_roles: { + roles: ['customer', 'deluxe', 'accounting', 'admin'] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/ftp/test.pdf` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-metrics.test.ts b/.brightsec/tests/get-metrics.test.ts new file mode 100644 index 00000000000..78a97a14a70 --- /dev/null +++ b/.brightsec/tests/get-metrics.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('GET /metrics', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['improper_asset_management', 'csrf', 'xss', 'server_side_js_injection', 'secret_tokens'], + attackParamLocations: [AttackParamLocation.HEADER], + starMetadata: { + code_source: 'tssbox/juice-shop:master', + databases: ['SQLite'], + user_roles: { + roles: ['customer', 'deluxe', 'accounting', 'admin'] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/metrics`, + headers: { 'Content-Type': 'text/plain; version=0.0.4; charset=utf-8' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-profile.test.ts b/.brightsec/tests/get-profile.test.ts new file mode 100644 index 00000000000..8e2376cc7c2 --- /dev/null +++ b/.brightsec/tests/get-profile.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('GET /profile', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'xss', 'bopla', 'full_path_disclosure', 'improper_asset_management'], + attackParamLocations: [AttackParamLocation.HEADER], + starMetadata: { + code_source: 'tssbox/juice-shop:master', + databases: ['SQLite'], + user_roles: { + roles: ['customer', 'deluxe', 'accounting', 'admin'] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/profile`, + headers: { + 'Content-Security-Policy': "img-src 'self' ; script-src 'self' 'unsafe-eval' https://code.getmdl.io http://ajax.googleapis.com" + } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-promotion.test.ts b/.brightsec/tests/get-promotion.test.ts new file mode 100644 index 00000000000..ff3905c5eff --- /dev/null +++ b/.brightsec/tests/get-promotion.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('GET /promotion', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['xss', 'csrf', 'improper_asset_management', 'unvalidated_redirect', 'sqli'], + attackParamLocations: [AttackParamLocation.PATH, AttackParamLocation.QUERY], + starMetadata: { + code_source: "tssbox/juice-shop:master", + databases: ["SQLite"], + user_roles: { + roles: ["customer", "deluxe", "accounting", "admin"] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/promotion` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-redirect.test.ts b/.brightsec/tests/get-redirect.test.ts new file mode 100644 index 00000000000..96da62a6e66 --- /dev/null +++ b/.brightsec/tests/get-redirect.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('GET /redirect', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['unvalidated_redirect', 'xss', 'csrf'], + attackParamLocations: [AttackParamLocation.QUERY], + starMetadata: { + code_source: 'tssbox/juice-shop:master', + databases: ['SQLite'], + user_roles: { + roles: ['customer', 'deluxe', 'accounting', 'admin'] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/redirect?to=https://example.com` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-rest-admin-application-configuration.test.ts b/.brightsec/tests/get-rest-admin-application-configuration.test.ts new file mode 100644 index 00000000000..2870a746d71 --- /dev/null +++ b/.brightsec/tests/get-rest-admin-application-configuration.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('GET /rest/admin/application-configuration', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['improper_asset_management', 'full_path_disclosure', 'secret_tokens'], + attackParamLocations: [AttackParamLocation.HEADER], + starMetadata: { + code_source: 'tssbox/juice-shop:master', + databases: ['SQLite'], + user_roles: { + roles: ['customer', 'deluxe', 'accounting', 'admin'] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/rest/admin/application-configuration`, + headers: { 'X-Recruiting': '' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-rest-admin-application-version.test.ts b/.brightsec/tests/get-rest-admin-application-version.test.ts new file mode 100644 index 00000000000..769eb9b7e0f --- /dev/null +++ b/.brightsec/tests/get-rest-admin-application-version.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('GET /rest/admin/application-version', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'improper_asset_management', 'xss', 'full_path_disclosure'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { + code_source: "tssbox/juice-shop:master", + databases: ["SQLite"], + user_roles: { + roles: ["customer", "deluxe", "accounting", "admin"] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/rest/admin/application-version` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-rest-basket-1.test.ts b/.brightsec/tests/get-rest-basket-1.test.ts new file mode 100644 index 00000000000..9efefab0c82 --- /dev/null +++ b/.brightsec/tests/get-rest-basket-1.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('GET /rest/basket/1', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['bopla', 'id_enumeration', 'sqli', 'xss'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { + code_source: "tssbox/juice-shop:master", + databases: ["SQLite"], + user_roles: { + roles: ["customer", "deluxe", "accounting", "admin"] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/rest/basket/1`, + headers: { 'X-Recruiting': 'We are hiring! Check our careers page.' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-rest-captcha.test.ts b/.brightsec/tests/get-rest-captcha.test.ts new file mode 100644 index 00000000000..1e7a5d67d09 --- /dev/null +++ b/.brightsec/tests/get-rest-captcha.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('GET /rest/captcha', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['xss', 'csrf', 'business_constraint_bypass'], + attackParamLocations: [AttackParamLocation.QUERY], + starMetadata: { + code_source: "tssbox/juice-shop:master", + databases: ["SQLite"], + user_roles: { + roles: ["customer", "deluxe", "accounting", "admin"] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/rest/captcha?dummyParam=value` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-rest-chatbot-status.test.ts b/.brightsec/tests/get-rest-chatbot-status.test.ts new file mode 100644 index 00000000000..23eb25d5014 --- /dev/null +++ b/.brightsec/tests/get-rest-chatbot-status.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('GET /rest/chatbot/status', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'jwt', 'xss', 'server_side_js_injection', 'osi'], + attackParamLocations: [AttackParamLocation.HEADER], + starMetadata: { + code_source: 'tssbox/juice-shop:master', + databases: ['SQLite'], + user_roles: { + roles: ['customer', 'deluxe', 'accounting', 'admin'] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/rest/chatbot/status`, + headers: { 'X-Recruiting': 'We are hiring! Visit our careers page for more information.' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-rest-continue-code-apply-code.test.ts b/.brightsec/tests/get-rest-continue-code-apply-code.test.ts new file mode 100644 index 00000000000..1c449421685 --- /dev/null +++ b/.brightsec/tests/get-rest-continue-code-apply-code.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('GET /rest/continue-code/apply/:code', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['id_enumeration', 'xss', 'csrf', 'sqli', 'proto_pollution'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { + code_source: "tssbox/juice-shop:master", + databases: ["SQLite"], + user_roles: { + roles: ["customer", "deluxe", "accounting", "admin"] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/rest/continue-code/apply/abc123` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-rest-continue-code-findit-apply-id.test.ts b/.brightsec/tests/get-rest-continue-code-findit-apply-id.test.ts new file mode 100644 index 00000000000..2659c090922 --- /dev/null +++ b/.brightsec/tests/get-rest-continue-code-findit-apply-id.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('GET /rest/continue-code-findIt/apply/:id', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['bopla', 'id_enumeration', 'secret_tokens', 'xss'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { + code_source: "tssbox/juice-shop:master", + databases: ["SQLite"], + user_roles: { + roles: ["customer", "deluxe", "accounting", "admin"] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/rest/continue-code-findIt/apply/abc123` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-rest-continue-code-findit.test.ts b/.brightsec/tests/get-rest-continue-code-findit.test.ts new file mode 100644 index 00000000000..1321c60d3ed --- /dev/null +++ b/.brightsec/tests/get-rest-continue-code-findit.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('GET /rest/continue-code-findIt', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['business_constraint_bypass', 'sqli', 'xss', 'secret_tokens'], + attackParamLocations: [AttackParamLocation.PATH, AttackParamLocation.QUERY], + starMetadata: { + code_source: 'tssbox/juice-shop:master', + databases: ['SQLite'], + user_roles: { + roles: ['customer', 'deluxe', 'accounting', 'admin'] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/rest/continue-code-findIt` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-rest-continue-code-fixit-apply-id.test.ts b/.brightsec/tests/get-rest-continue-code-fixit-apply-id.test.ts new file mode 100644 index 00000000000..24b67550c76 --- /dev/null +++ b/.brightsec/tests/get-rest-continue-code-fixit-apply-id.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('GET /rest/continue-code-fixIt/apply/:id', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'id_enumeration', 'xss', 'secret_tokens'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { + code_source: 'tssbox/juice-shop:master', + databases: ['SQLite'], + user_roles: { + roles: ['customer', 'deluxe', 'accounting', 'admin'] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/rest/continue-code-fixIt/apply/abc123` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-rest-continue-code-fixit.test.ts b/.brightsec/tests/get-rest-continue-code-fixit.test.ts new file mode 100644 index 00000000000..8c162144596 --- /dev/null +++ b/.brightsec/tests/get-rest-continue-code-fixit.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('GET /rest/continue-code-fixIt', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['business_constraint_bypass', 'sqli', 'xss', 'csrf'], + attackParamLocations: [AttackParamLocation.PATH, AttackParamLocation.QUERY], + starMetadata: { + code_source: 'tssbox/juice-shop:master', + databases: ['SQLite'], + user_roles: { + roles: ['customer', 'deluxe', 'accounting', 'admin'] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/rest/continue-code-fixIt` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-rest-continue-code.test.ts b/.brightsec/tests/get-rest-continue-code.test.ts new file mode 100644 index 00000000000..5b6ff00028b --- /dev/null +++ b/.brightsec/tests/get-rest-continue-code.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('GET /rest/continue-code', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['business_constraint_bypass', 'xss', 'secret_tokens'], + attackParamLocations: [AttackParamLocation.PATH, AttackParamLocation.QUERY], + starMetadata: { + code_source: "tssbox/juice-shop:master", + databases: ["SQLite"], + user_roles: { + roles: ["customer", "deluxe", "accounting", "admin"] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/rest/continue-code` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-rest-country-mapping.test.ts b/.brightsec/tests/get-rest-country-mapping.test.ts new file mode 100644 index 00000000000..97b494d325f --- /dev/null +++ b/.brightsec/tests/get-rest-country-mapping.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('GET /rest/country-mapping', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['improper_asset_management', 'full_path_disclosure', 'secret_tokens'], + attackParamLocations: [AttackParamLocation.HEADER], + starMetadata: { + code_source: "tssbox/juice-shop:master", + databases: ["SQLite"], + user_roles: { + roles: ["customer", "deluxe", "accounting", "admin"] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/rest/country-mapping`, + headers: { 'X-Recruiting': '' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-rest-deluxe-membership.test.ts b/.brightsec/tests/get-rest-deluxe-membership.test.ts new file mode 100644 index 00000000000..9ef0d385abd --- /dev/null +++ b/.brightsec/tests/get-rest-deluxe-membership.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('GET /rest/deluxe-membership', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'business_constraint_bypass', 'xss', 'sqli', 'secret_tokens'], + attackParamLocations: [AttackParamLocation.HEADER], + starMetadata: { + code_source: 'tssbox/juice-shop:master', + databases: ['SQLite'], + user_roles: { + roles: ['customer', 'deluxe', 'accounting', 'admin'] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/rest/deluxe-membership`, + headers: { 'X-Recruiting': '' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-rest-image-captcha.test.ts b/.brightsec/tests/get-rest-image-captcha.test.ts new file mode 100644 index 00000000000..bf7823c7482 --- /dev/null +++ b/.brightsec/tests/get-rest-image-captcha.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('GET /rest/image-captcha', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'xss', 'business_constraint_bypass', 'osi'], + attackParamLocations: [AttackParamLocation.HEADER], + starMetadata: { + code_source: "tssbox/juice-shop:master", + databases: ["SQLite"], + user_roles: { + roles: ["customer", "deluxe", "accounting", "admin"] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/rest/image-captcha`, + headers: { 'Content-Type': 'application/json' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-rest-languages.test.ts b/.brightsec/tests/get-rest-languages.test.ts new file mode 100644 index 00000000000..bff0428a66b --- /dev/null +++ b/.brightsec/tests/get-rest-languages.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('GET /rest/languages', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['full_path_disclosure', 'xss', 'lfi', 'improper_asset_management'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { + code_source: "tssbox/juice-shop:master", + databases: ["SQLite"], + user_roles: { + roles: ["customer", "deluxe", "accounting", "admin"] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/rest/languages` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-rest-memories.test.ts b/.brightsec/tests/get-rest-memories.test.ts new file mode 100644 index 00000000000..bf02acfb9e6 --- /dev/null +++ b/.brightsec/tests/get-rest-memories.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('GET /rest/memories', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['bopla', 'sqli', 'xss', 'improper_asset_management'], + attackParamLocations: [AttackParamLocation.PATH, AttackParamLocation.QUERY], + starMetadata: { + code_source: 'tssbox/juice-shop:master', + databases: ['SQLite'], + user_roles: { + roles: ['customer', 'deluxe', 'accounting', 'admin'] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/rest/memories` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-rest-order-history-orders.test.ts b/.brightsec/tests/get-rest-order-history-orders.test.ts new file mode 100644 index 00000000000..42058614601 --- /dev/null +++ b/.brightsec/tests/get-rest-order-history-orders.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('GET /rest/order-history/orders', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['bopla', 'id_enumeration', 'nosql', 'xss'], + attackParamLocations: [AttackParamLocation.PATH, AttackParamLocation.QUERY], + starMetadata: { + code_source: "tssbox/juice-shop:master", + databases: ["SQLite"], + user_roles: { + roles: ["customer", "deluxe", "accounting", "admin"] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/rest/order-history/orders` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-rest-order-history.test.ts b/.brightsec/tests/get-rest-order-history.test.ts new file mode 100644 index 00000000000..b28d5f6af87 --- /dev/null +++ b/.brightsec/tests/get-rest-order-history.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('GET /rest/order-history', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['bopla', 'id_enumeration', 'nosql', 'xss'], + attackParamLocations: [AttackParamLocation.HEADER], + starMetadata: { + code_source: 'tssbox/juice-shop:master', + databases: ['SQLite'], + user_roles: { + roles: ['customer', 'deluxe', 'accounting', 'admin'] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/rest/order-history`, + headers: { 'Authorization': 'Bearer ' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-rest-products-1-reviews.test.ts b/.brightsec/tests/get-rest-products-1-reviews.test.ts new file mode 100644 index 00000000000..75b56ccca2b --- /dev/null +++ b/.brightsec/tests/get-rest-products-1-reviews.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('GET /rest/products/1/reviews', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['nosql', 'business_constraint_bypass', 'xss', 'csrf'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { + code_source: "tssbox/juice-shop:master", + databases: ["SQLite"], + user_roles: { + roles: ["customer", "deluxe", "accounting", "admin"] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/rest/products/1/reviews` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-rest-products-search-q-apple.test.ts b/.brightsec/tests/get-rest-products-search-q-apple.test.ts new file mode 100644 index 00000000000..84795f3b25c --- /dev/null +++ b/.brightsec/tests/get-rest-products-search-q-apple.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('GET /rest/products/search?q=apple', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['sqli', 'full_path_disclosure', 'xss', 'business_constraint_bypass'], + attackParamLocations: [AttackParamLocation.QUERY], + starMetadata: { + code_source: "tssbox/juice-shop:master", + databases: ["SQLite"], + user_roles: { + roles: ["customer", "deluxe", "accounting", "admin"] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/rest/products/search?q=apple`, + headers: { 'X-Recruiting': 'We are hiring! Visit our careers page for more information.' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-rest-products-search.test.ts b/.brightsec/tests/get-rest-products-search.test.ts new file mode 100644 index 00000000000..8874ac7b422 --- /dev/null +++ b/.brightsec/tests/get-rest-products-search.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('GET /rest/products/search?q=apple', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['sqli', 'xss', 'full_path_disclosure'], + attackParamLocations: [AttackParamLocation.QUERY], + starMetadata: { + code_source: "tssbox/juice-shop:master", + databases: ["SQLite"], + user_roles: { + roles: ["customer", "deluxe", "accounting", "admin"] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/rest/products/search?q=apple` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-rest-repeat-notification.test.ts b/.brightsec/tests/get-rest-repeat-notification.test.ts new file mode 100644 index 00000000000..db8eea49457 --- /dev/null +++ b/.brightsec/tests/get-rest-repeat-notification.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('GET /rest/repeat-notification', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['xss', 'unvalidated_redirect', 'business_constraint_bypass'], + attackParamLocations: [AttackParamLocation.QUERY], + starMetadata: { + code_source: 'tssbox/juice-shop:master', + databases: ['SQLite'], + user_roles: { + roles: ['customer', 'deluxe', 'accounting', 'admin'] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/rest/repeat-notification?challenge=some%20challenge` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-rest-save-login-ip.test.ts b/.brightsec/tests/get-rest-save-login-ip.test.ts new file mode 100644 index 00000000000..7f14b51f947 --- /dev/null +++ b/.brightsec/tests/get-rest-save-login-ip.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('GET /rest/saveLoginIp', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['xss', 'csrf', 'bopla', 'http_method_fuzzing'], + attackParamLocations: [AttackParamLocation.HEADER], + starMetadata: { + code_source: "tssbox/juice-shop:master", + databases: ["SQLite"], + user_roles: { + roles: ["customer", "deluxe", "accounting", "admin"] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/rest/saveLoginIp`, + headers: { 'X-Recruiting': '' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-rest-track-order-id.test.ts b/.brightsec/tests/get-rest-track-order-id.test.ts new file mode 100644 index 00000000000..3a42d7dc17f --- /dev/null +++ b/.brightsec/tests/get-rest-track-order-id.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('GET /rest/track-order/:id', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['xss', 'nosql', 'id_enumeration'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { + code_source: "tssbox/juice-shop:master", + databases: ["SQLite"], + user_roles: { + roles: ["customer", "deluxe", "accounting", "admin"] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/rest/track-order/12345` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-rest-user-change-password.test.ts b/.brightsec/tests/get-rest-user-change-password.test.ts new file mode 100644 index 00000000000..0d9872ff591 --- /dev/null +++ b/.brightsec/tests/get-rest-user-change-password.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('GET /rest/user/change-password', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'xss', 'jwt', 'bopla', 'sqli'], + attackParamLocations: [AttackParamLocation.QUERY], + starMetadata: { + code_source: "tssbox/juice-shop:master", + databases: ["SQLite"], + user_roles: { + roles: ["customer", "deluxe", "accounting", "admin"] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/rest/user/change-password?current=oldPassword123&new=newPassword123&repeat=newPassword123`, + headers: { Authorization: 'Bearer ' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-rest-user-security-question.test.ts b/.brightsec/tests/get-rest-user-security-question.test.ts new file mode 100644 index 00000000000..bf8fe838818 --- /dev/null +++ b/.brightsec/tests/get-rest-user-security-question.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('GET /rest/user/security-question?email=:email', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['nosql', 'id_enumeration', 'xss'], + attackParamLocations: [AttackParamLocation.QUERY], + starMetadata: { + code_source: "tssbox/juice-shop:master", + databases: ["SQLite"], + user_roles: { + roles: ["customer", "deluxe", "accounting", "admin"] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/rest/user/security-question?email=user@example.com` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-rest-user-whoami.test.ts b/.brightsec/tests/get-rest-user-whoami.test.ts new file mode 100644 index 00000000000..0d887cc884c --- /dev/null +++ b/.brightsec/tests/get-rest-user-whoami.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('GET /rest/user/whoami', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['sqli', 'xss', 'jwt'], + attackParamLocations: [AttackParamLocation.QUERY, AttackParamLocation.HEADER], + starMetadata: { + code_source: "tssbox/juice-shop:master", + databases: ["SQLite"], + user_roles: { + roles: ["customer", "deluxe", "accounting", "admin"] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/rest/user/whoami?callback=callbackFunction`, + headers: { 'X-Recruiting': 'We are hiring!' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-rest-wallet-balance.test.ts b/.brightsec/tests/get-rest-wallet-balance.test.ts new file mode 100644 index 00000000000..edf871034a5 --- /dev/null +++ b/.brightsec/tests/get-rest-wallet-balance.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('GET /rest/wallet/balance', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['bopla', 'nosql', 'csrf', 'xss'], + attackParamLocations: [AttackParamLocation.QUERY], + starMetadata: { + code_source: "tssbox/juice-shop:master", + databases: ["SQLite"], + user_roles: { + roles: ["customer", "deluxe", "accounting", "admin"] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/rest/wallet/balance?dummyParam=value` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-rest-web3-nft-mint-listen.test.ts b/.brightsec/tests/get-rest-web3-nft-mint-listen.test.ts new file mode 100644 index 00000000000..4710a0cc195 --- /dev/null +++ b/.brightsec/tests/get-rest-web3-nft-mint-listen.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('GET /rest/web3/nftMintListen', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['ssrf', 'secret_tokens', 'csrf', 'improper_asset_management'], + attackParamLocations: [AttackParamLocation.QUERY], + starMetadata: { + code_source: "tssbox/juice-shop:master", + databases: ["SQLite"], + user_roles: { + roles: ["customer", "deluxe", "accounting", "admin"] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/rest/web3/nftMintListen` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-rest-web3-nft-unlocked.test.ts b/.brightsec/tests/get-rest-web3-nft-unlocked.test.ts new file mode 100644 index 00000000000..66333712f47 --- /dev/null +++ b/.brightsec/tests/get-rest-web3-nft-unlocked.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('GET /rest/web3/nftUnlocked', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'full_path_disclosure', 'secret_tokens', 'xss'], + attackParamLocations: [AttackParamLocation.PATH, AttackParamLocation.QUERY], + starMetadata: { + code_source: "tssbox/juice-shop:master", + databases: ["SQLite"], + user_roles: { + roles: ["customer", "deluxe", "accounting", "admin"] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/rest/web3/nftUnlocked` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-security-txt.test.ts b/.brightsec/tests/get-security-txt.test.ts new file mode 100644 index 00000000000..b86be4b165b --- /dev/null +++ b/.brightsec/tests/get-security-txt.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('GET /security.txt', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'full_path_disclosure', 'improper_asset_management', 'xss'], + attackParamLocations: [AttackParamLocation.HEADER], + starMetadata: { + code_source: 'tssbox/juice-shop:master', + databases: ['SQLite'], + user_roles: { + roles: ['customer', 'deluxe', 'accounting', 'admin'] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/security.txt`, + headers: { 'X-Recruiting': '' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-snippets-challenge.test.ts b/.brightsec/tests/get-snippets-challenge.test.ts new file mode 100644 index 00000000000..d6677aa82b5 --- /dev/null +++ b/.brightsec/tests/get-snippets-challenge.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('GET /snippets/:challenge', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['test/api/vulnCodeSnippetSpec.ts', 'test/server/codeSnippetSpec.ts'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { + code_source: "tssbox/juice-shop:master", + databases: ["SQLite"], + user_roles: { + roles: ["customer", "deluxe", "accounting", "admin"] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/snippets/1` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-snippets-fixes-sample-key.test.ts b/.brightsec/tests/get-snippets-fixes-sample-key.test.ts new file mode 100644 index 00000000000..aed4f28adac --- /dev/null +++ b/.brightsec/tests/get-snippets-fixes-sample-key.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('GET /snippets/fixes/sampleKey', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['id_enumeration', 'lfi', 'xss', 'secret_tokens'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { + code_source: "tssbox/juice-shop:master", + databases: ["SQLite"], + user_roles: { + roles: ["customer", "deluxe", "accounting", "admin"] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/snippets/fixes/sampleKey` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-snippets-fixes-samplekey.test.ts b/.brightsec/tests/get-snippets-fixes-samplekey.test.ts new file mode 100644 index 00000000000..401c5144131 --- /dev/null +++ b/.brightsec/tests/get-snippets-fixes-samplekey.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('GET /snippets/fixes/sampleKey', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['id_enumeration', 'lfi', 'xss', 'full_path_disclosure'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { + code_source: "tssbox/juice-shop:master", + databases: ["SQLite"], + user_roles: { + roles: ["customer", "deluxe", "accounting", "admin"] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/snippets/fixes/sampleKey` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-snippets-sample-challenge.test.ts b/.brightsec/tests/get-snippets-sample-challenge.test.ts new file mode 100644 index 00000000000..ab82032aa26 --- /dev/null +++ b/.brightsec/tests/get-snippets-sample-challenge.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('GET /snippets/sample-challenge', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['xss', 'sqli', 'lfi'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { + code_source: 'tssbox/juice-shop:master', + databases: ['SQLite'], + user_roles: { + roles: ['customer', 'deluxe', 'accounting', 'admin'] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/snippets/sample-challenge` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-solve-challenges-server-side.test.ts b/.brightsec/tests/get-solve-challenges-server-side.test.ts new file mode 100644 index 00000000000..0512411f891 --- /dev/null +++ b/.brightsec/tests/get-solve-challenges-server-side.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('GET /solve/challenges/server-side', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['xss', 'csrf', 'ssrf', 'sqli', 'osi'], + attackParamLocations: [AttackParamLocation.QUERY], + starMetadata: { + code_source: "tssbox/juice-shop:master", + databases: ["SQLite"], + user_roles: { + roles: ["customer", "deluxe", "accounting", "admin"] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/solve/challenges/server-side?key=tRy_H4rd3r_n0thIng_iS_Imp0ssibl3` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-support-logs-access-log.test.ts b/.brightsec/tests/get-support-logs-access-log.test.ts new file mode 100644 index 00000000000..a52ed5ab227 --- /dev/null +++ b/.brightsec/tests/get-support-logs-access-log.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('GET /support/logs/access.log', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['lfi', 'full_path_disclosure', 'improper_asset_management', 'xss'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { + code_source: "tssbox/juice-shop:master", + databases: ["SQLite"], + user_roles: { + roles: ["customer", "deluxe", "accounting", "admin"] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/support/logs/access.log` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-support-logs-sample-log.test.ts b/.brightsec/tests/get-support-logs-sample-log.test.ts new file mode 100644 index 00000000000..f5808646879 --- /dev/null +++ b/.brightsec/tests/get-support-logs-sample-log.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('GET /support/logs/sample.log', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['lfi', 'full_path_disclosure', 'improper_asset_management', 'access_control'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { + code_source: "tssbox/juice-shop:master", + databases: ["SQLite"], + user_roles: { + roles: ["customer", "deluxe", "accounting", "admin"] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/support/logs/sample.log` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-the-devs-are-so-funny-they-hid-an-easter-egg-within-the-easter-egg.test.ts b/.brightsec/tests/get-the-devs-are-so-funny-they-hid-an-easter-egg-within-the-easter-egg.test.ts new file mode 100644 index 00000000000..0884af28005 --- /dev/null +++ b/.brightsec/tests/get-the-devs-are-so-funny-they-hid-an-easter-egg-within-the-easter-egg.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('GET /the/devs/are/so/funny/they/hid/an/easter/egg/within/the/easter/egg', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['improper_asset_management', 'full_path_disclosure', 'xss'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { + code_source: "tssbox/juice-shop:master", + databases: ["SQLite"], + user_roles: { + roles: ["customer", "deluxe", "accounting", "admin"] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/the/devs/are/so/funny/they/hid/an/easter/egg/within/the/easter/egg` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-this-page-is-hidden-behind-an-incredibly-high-paywall-that-could-only-be-unlocked-by-sending-1btc-to-us.test.ts b/.brightsec/tests/get-this-page-is-hidden-behind-an-incredibly-high-paywall-that-could-only-be-unlocked-by-sending-1btc-to-us.test.ts new file mode 100644 index 00000000000..fa51f71232c --- /dev/null +++ b/.brightsec/tests/get-this-page-is-hidden-behind-an-incredibly-high-paywall-that-could-only-be-unlocked-by-sending-1btc-to-us.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('GET /this/page/is/hidden/behind/an/incredibly/high/paywall/that/could/only/be/unlocked/by/sending/1btc/to/us', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'xss', 'unvalidated_redirect', 'improper_asset_management', 'sqli', 'ssrf', 'osi', 'secret_tokens'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { + code_source: "tssbox/juice-shop:master", + databases: ["SQLite"], + user_roles: { + roles: ["customer", "deluxe", "accounting", "admin"] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/this/page/is/hidden/behind/an/incredibly/high/paywall/that/could/only/be/unlocked/by/sending/1btc/to/us` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-video.test.ts b/.brightsec/tests/get-video.test.ts new file mode 100644 index 00000000000..65d99e07a0c --- /dev/null +++ b/.brightsec/tests/get-video.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('GET /video', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['xss', 'lfi', 'ssrf', 'csrf'], + attackParamLocations: [AttackParamLocation.HEADER], + starMetadata: { + code_source: 'tssbox/juice-shop:master', + databases: ['SQLite'], + user_roles: { + roles: ['customer', 'deluxe', 'accounting', 'admin'] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/video`, + headers: { 'X-Recruiting': 'We are hiring!' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-we-may-also-instruct-you-to-refuse-all-reasonably-necessary-responsibility.test.ts b/.brightsec/tests/get-we-may-also-instruct-you-to-refuse-all-reasonably-necessary-responsibility.test.ts new file mode 100644 index 00000000000..0ca29c0a5cd --- /dev/null +++ b/.brightsec/tests/get-we-may-also-instruct-you-to-refuse-all-reasonably-necessary-responsibility.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('GET /we/may/also/instruct/you/to/refuse/all/reasonably/necessary/responsibility', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['xss', 'csrf', 'http_method_fuzzing', 'full_path_disclosure', 'improper_asset_management', 'unvalidated_redirect'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { + code_source: "tssbox/juice-shop:master", + databases: ["SQLite"], + user_roles: { + roles: ["customer", "deluxe", "accounting", "admin"] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/we/may/also/instruct/you/to/refuse/all/reasonably/necessary/responsibility` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-well-known-security-txt.test.ts b/.brightsec/tests/get-well-known-security-txt.test.ts new file mode 100644 index 00000000000..85f13899e8f --- /dev/null +++ b/.brightsec/tests/get-well-known-security-txt.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('GET /.well-known/security.txt', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'improper_asset_management', 'full_path_disclosure', 'xss'], + attackParamLocations: [AttackParamLocation.HEADER], + starMetadata: { + code_source: 'tssbox/juice-shop:master', + databases: ['SQLite'], + user_roles: { + roles: ['customer', 'deluxe', 'accounting', 'admin'] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/.well-known/security.txt`, + headers: { 'X-Recruiting': '' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-well-known.test.ts b/.brightsec/tests/get-well-known.test.ts new file mode 100644 index 00000000000..8a5c92bd68c --- /dev/null +++ b/.brightsec/tests/get-well-known.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('GET /.well-known', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['improper_asset_management', 'full_path_disclosure', 'xss', 'csrf'], + attackParamLocations: [AttackParamLocation.HEADER], + starMetadata: { + code_source: 'tssbox/juice-shop:master', + databases: ['SQLite'], + user_roles: { + roles: ['customer', 'deluxe', 'accounting', 'admin'] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/.well-known`, + headers: { 'X-Recruiting': 'true' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/post-api-addresss.test.ts b/.brightsec/tests/post-api-addresss.test.ts new file mode 100644 index 00000000000..4cf297c9086 --- /dev/null +++ b/.brightsec/tests/post-api-addresss.test.ts @@ -0,0 +1,53 @@ +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/addresss', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['bopla', 'sqli', 'xss', 'csrf', 'nosql'], + attackParamLocations: [AttackParamLocation.BODY, AttackParamLocation.HEADER], + starMetadata: { + code_source: "tssbox/juice-shop:master", + databases: ["SQLite"], + user_roles: { + roles: ["customer", "deluxe", "accounting", "admin"] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.POST, + url: `${baseUrl}/api/Addresss`, + body: { + fullName: "Jim", + mobileNum: "9800000000", + zipCode: "NX 101", + streetAddress: "Bakers Street", + city: "NYC", + state: "NY", + country: "USA" + }, + headers: { + Authorization: "Bearer ", + 'Content-Type': 'application/json' + } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/post-api-basket-items.test.ts b/.brightsec/tests/post-api-basket-items.test.ts new file mode 100644 index 00000000000..251cd79a933 --- /dev/null +++ b/.brightsec/tests/post-api-basket-items.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/basket-items', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['bopla', 'sqli', 'xss', 'business_constraint_bypass', 'csrf'], + attackParamLocations: [AttackParamLocation.BODY], + starMetadata: { + code_source: 'tssbox/juice-shop:master', + databases: ['SQLite'], + user_roles: { + roles: ['customer', 'deluxe', 'accounting', 'admin'] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.POST, + url: `${baseUrl}/api/BasketItems`, + body: { + ProductId: 1, + BasketId: 1, + quantity: 2 + }, + headers: { 'Content-Type': 'application/json' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/post-api-cards.test.ts b/.brightsec/tests/post-api-cards.test.ts new file mode 100644 index 00000000000..a08beb425ef --- /dev/null +++ b/.brightsec/tests/post-api-cards.test.ts @@ -0,0 +1,49 @@ +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/cards', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['bopla', 'sqli', 'xss', 'csrf', 'date_manipulation'], + attackParamLocations: [AttackParamLocation.BODY], + starMetadata: { + code_source: "tssbox/juice-shop:master", + databases: ["SQLite"], + user_roles: { + roles: ["customer", "deluxe", "accounting", "admin"] + } + }, + skipStaticParams: false + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.POST, + url: `${baseUrl}/api/Cards`, + body: { + UserId: 1, + fullName: "John Doe", + cardNum: 1234567812345678, + expMonth: 12, + expYear: 2099 + }, + headers: { 'Content-Type': 'application/json' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/post-api-complaints.test.ts b/.brightsec/tests/post-api-complaints.test.ts new file mode 100644 index 00000000000..61ad35318d4 --- /dev/null +++ b/.brightsec/tests/post-api-complaints.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/complaints', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'file_upload', 'xss', 'sqli'], + attackParamLocations: [AttackParamLocation.BODY], + starMetadata: { + code_source: 'tssbox/juice-shop:master', + databases: ['SQLite'], + user_roles: { + roles: ['customer', 'deluxe', 'accounting', 'admin'] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.POST, + url: `${baseUrl}/api/Complaints`, + body: { + UserId: 123, + message: 'This is a sample complaint message.', + file: 'optional-file-path-or-url' + }, + headers: { 'Content-Type': 'application/json' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/post-api-feedbacks.test.ts b/.brightsec/tests/post-api-feedbacks.test.ts new file mode 100644 index 00000000000..f53ba5be255 --- /dev/null +++ b/.brightsec/tests/post-api-feedbacks.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/feedbacks', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['xss', 'csrf', 'sqli', 'nosql'], + attackParamLocations: [AttackParamLocation.BODY], + starMetadata: { + code_source: "tssbox/juice-shop:master", + databases: ["SQLite"], + user_roles: { + roles: ["customer", "deluxe", "accounting", "admin"] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.POST, + url: `${baseUrl}/api/Feedbacks`, + body: { + UserId: 1, + comment: "Great service!", + rating: 5 + }, + headers: { 'Content-Type': 'application/json' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/post-api-recycles.test.ts b/.brightsec/tests/post-api-recycles.test.ts new file mode 100644 index 00000000000..5f6fe0bf93a --- /dev/null +++ b/.brightsec/tests/post-api-recycles.test.ts @@ -0,0 +1,49 @@ +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/recycles', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['bopla', 'sqli', 'csrf', 'date_manipulation', 'id_enumeration'], + attackParamLocations: [AttackParamLocation.BODY], + starMetadata: { + code_source: "tssbox/juice-shop:master", + databases: ["SQLite"], + user_roles: { + roles: ["customer", "deluxe", "accounting", "admin"] + } + }, + skipStaticParams: false + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.POST, + url: `${baseUrl}/api/Recycles`, + body: { + UserId: 1, + AddressId: 1, + quantity: 10, + isPickup: true, + date: "2023-10-01T00:00:00Z" + }, + headers: { 'Content-Type': 'application/json' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/post-api-security-answers.test.ts b/.brightsec/tests/post-api-security-answers.test.ts new file mode 100644 index 00000000000..6388c85cec9 --- /dev/null +++ b/.brightsec/tests/post-api-security-answers.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/security-answers', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['bopla', 'id_enumeration', 'xss', 'sqli', 'csrf'], + attackParamLocations: [AttackParamLocation.BODY], + starMetadata: { + code_source: "tssbox/juice-shop:master", + databases: ["SQLite"], + user_roles: { + roles: ["customer", "deluxe", "accounting", "admin"] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.POST, + url: `${baseUrl}/api/SecurityAnswers`, + body: { + UserId: 123, + SecurityQuestionId: 456, + answer: "hashed_answer" + }, + headers: { 'Content-Type': 'application/json' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/post-api-users.test.ts b/.brightsec/tests/post-api-users.test.ts new file mode 100644 index 00000000000..b2f5a93beed --- /dev/null +++ b/.brightsec/tests/post-api-users.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', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['xss', 'csrf', 'sqli', 'nosql', 'email_injection'], + attackParamLocations: [AttackParamLocation.BODY], + starMetadata: { + code_source: 'tssbox/juice-shop:master', + databases: ['SQLite'], + user_roles: { + roles: ['customer', 'deluxe', 'accounting', 'admin'] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.POST, + url: `${baseUrl}/api/Users`, + body: { + email: 'user@example.com', + password: 'securePassword123', + passwordRepeat: 'securePassword123' + }, + headers: { 'Content-Type': 'application/json' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/post-b2b-v2-orders.test.ts b/.brightsec/tests/post-b2b-v2-orders.test.ts new file mode 100644 index 00000000000..a5c94bb4a91 --- /dev/null +++ b/.brightsec/tests/post-b2b-v2-orders.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 /b2b/v2/orders', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['osi', 'ssrf', 'sqli', 'xss', 'csrf', 'business_constraint_bypass'], + attackParamLocations: [AttackParamLocation.BODY, AttackParamLocation.HEADER], + starMetadata: { + code_source: 'tssbox/juice-shop:master', + databases: ['SQLite'], + user_roles: { + roles: ['customer', 'deluxe', 'accounting', 'admin'] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.POST, + url: `${baseUrl}/b2b/v2/orders`, + body: { + cid: 'exampleCID', + orderLinesData: 'exampleOrderLinesData' + }, + headers: { + 'Content-Type': 'application/json', + 'X-Recruiting': '' + } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/post-file-upload.test.ts b/.brightsec/tests/post-file-upload.test.ts new file mode 100644 index 00000000000..6bd225ab54c --- /dev/null +++ b/.brightsec/tests/post-file-upload.test.ts @@ -0,0 +1,42 @@ +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 /file-upload', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['file_upload', 'xxe', 'yaml_bomb', 'osi'], + attackParamLocations: [AttackParamLocation.BODY], + starMetadata: { + code_source: 'tssbox/juice-shop:master', + databases: ['SQLite'], + user_roles: { + roles: ['customer', 'deluxe', 'accounting', 'admin'] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.POST, + url: `${baseUrl}/file-upload`, + headers: { 'Content-Type': 'multipart/form-data' }, + body: `--boundary\r\nContent-Disposition: form-data; name="file"; filename="example.zip"\r\nContent-Type: application/zip\r\n\r\n\r\n--boundary--` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/post-profile-image-file.test.ts b/.brightsec/tests/post-profile-image-file.test.ts new file mode 100644 index 00000000000..46b2695d95d --- /dev/null +++ b/.brightsec/tests/post-profile-image-file.test.ts @@ -0,0 +1,42 @@ +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 /profile/image/file', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['file_upload', 'ssrf', 'xss', 'osi'], + attackParamLocations: [AttackParamLocation.BODY], + starMetadata: { + code_source: 'tssbox/juice-shop:master', + databases: ['SQLite'], + user_roles: { + roles: ['customer', 'deluxe', 'accounting', 'admin'] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.POST, + url: `${baseUrl}/profile/image/file`, + body: { file: '' }, + headers: { 'Content-Type': 'multipart/form-data' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/post-profile-image-url.test.ts b/.brightsec/tests/post-profile-image-url.test.ts new file mode 100644 index 00000000000..c1e1a4edb11 --- /dev/null +++ b/.brightsec/tests/post-profile-image-url.test.ts @@ -0,0 +1,44 @@ +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 /profile/image/url', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['ssrf', 'file_upload', 'xss'], + attackParamLocations: [AttackParamLocation.BODY], + starMetadata: { + code_source: "tssbox/juice-shop:master", + databases: ["SQLite"], + user_roles: { + roles: ["customer", "deluxe", "accounting", "admin"] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.POST, + url: `${baseUrl}/profile/image/url`, + body: { + imageUrl: 'https://example.com/image.jpg' + }, + headers: { 'Content-Type': 'application/json' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/post-profile.test.ts b/.brightsec/tests/post-profile.test.ts new file mode 100644 index 00000000000..a84497c1901 --- /dev/null +++ b/.brightsec/tests/post-profile.test.ts @@ -0,0 +1,44 @@ +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 /profile', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'bopla', 'xss', 'jwt'], + attackParamLocations: [AttackParamLocation.BODY], + starMetadata: { + code_source: 'tssbox/juice-shop:master', + databases: ['SQLite'], + user_roles: { + roles: ['customer', 'deluxe', 'accounting', 'admin'] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.POST, + url: `${baseUrl}/profile`, + body: { + username: 'newUsername' + }, + headers: { 'Content-Type': 'application/json' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/post-rest-basket-1-checkout.test.ts b/.brightsec/tests/post-rest-basket-1-checkout.test.ts new file mode 100644 index 00000000000..2589508fe07 --- /dev/null +++ b/.brightsec/tests/post-rest-basket-1-checkout.test.ts @@ -0,0 +1,51 @@ +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 /rest/basket/1/checkout', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['bopla', 'business_constraint_bypass', 'sqli', 'xss', 'csrf', 'date_manipulation'], + attackParamLocations: [AttackParamLocation.BODY, AttackParamLocation.HEADER], + starMetadata: { + code_source: "tssbox/juice-shop:master", + databases: ["SQLite"], + user_roles: { + roles: ["customer", "deluxe", "accounting", "admin"] + } + }, + skipStaticParams: false + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.POST, + url: `${baseUrl}/rest/basket/1/checkout`, + body: { + orderDetails: { + deliveryMethodId: 1, + paymentId: "wallet", + addressId: 123 + }, + UserId: 456, + couponData: "V01OU0RZMjAyMy0xNjc4MjQwMDAw" + }, + headers: { 'Content-Type': 'application/json' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/post-rest-chatbot-respond.test.ts b/.brightsec/tests/post-rest-chatbot-respond.test.ts new file mode 100644 index 00000000000..bea31f07f0f --- /dev/null +++ b/.brightsec/tests/post-rest-chatbot-respond.test.ts @@ -0,0 +1,45 @@ +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 /rest/chatbot/respond', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['jwt', 'xss', 'server_side_js_injection', 'csrf', 'osi'], + attackParamLocations: [AttackParamLocation.BODY, AttackParamLocation.HEADER], + starMetadata: { + code_source: "tssbox/juice-shop:master", + databases: ["SQLite"], + user_roles: { + roles: ["customer", "deluxe", "accounting", "admin"] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.POST, + url: `${baseUrl}/rest/chatbot/respond`, + body: { + action: "query", + query: "Hello, how are you?" + }, + headers: { 'Content-Type': 'application/json' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/post-rest-deluxe-membership.test.ts b/.brightsec/tests/post-rest-deluxe-membership.test.ts new file mode 100644 index 00000000000..4772878afc1 --- /dev/null +++ b/.brightsec/tests/post-rest-deluxe-membership.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 /rest/deluxe-membership', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['bopla', 'csrf', 'id_enumeration', 'sqli', 'xss'], + attackParamLocations: [AttackParamLocation.BODY], + starMetadata: { + code_source: "tssbox/juice-shop:master", + databases: ["SQLite"], + user_roles: { + roles: ["customer", "deluxe", "accounting", "admin"] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.POST, + url: `${baseUrl}/rest/deluxe-membership`, + body: { + UserId: 1, + paymentMode: "wallet", + paymentId: 123456 + }, + headers: { 'Content-Type': 'application/json' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/post-rest-memories.test.ts b/.brightsec/tests/post-rest-memories.test.ts new file mode 100644 index 00000000000..b456dbf91c9 --- /dev/null +++ b/.brightsec/tests/post-rest-memories.test.ts @@ -0,0 +1,45 @@ +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 /rest/memories', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['file_upload', 'bopla', 'xss', 'csrf'], + attackParamLocations: [AttackParamLocation.BODY], + starMetadata: { + code_source: "tssbox/juice-shop:master", + databases: ["SQLite"], + user_roles: { + roles: ["customer", "deluxe", "accounting", "admin"] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.POST, + url: `${baseUrl}/rest/memories`, + body: { + caption: "A day at the beach", + UserId: 1 + }, + headers: { 'Content-Type': 'application/json' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/post-rest-user-data-export.test.ts b/.brightsec/tests/post-rest-user-data-export.test.ts new file mode 100644 index 00000000000..95492c7a7b2 --- /dev/null +++ b/.brightsec/tests/post-rest-user-data-export.test.ts @@ -0,0 +1,42 @@ +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 /rest/user/data-export', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['bopla', 'id_enumeration', 'xss', 'ssrf', 'sqli'], + attackParamLocations: [AttackParamLocation.BODY, AttackParamLocation.HEADER], + starMetadata: { + code_source: "tssbox/juice-shop:master", + databases: ["SQLite"], + user_roles: { + roles: ["customer", "deluxe", "accounting", "admin"] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.POST, + url: `${baseUrl}/rest/user/data-export`, + body: { "UserId": 1 }, + headers: { 'Authorization': 'Bearer ', 'Content-Type': 'application/json' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/post-rest-user-login.test.ts b/.brightsec/tests/post-rest-user-login.test.ts new file mode 100644 index 00000000000..84a3dad5233 --- /dev/null +++ b/.brightsec/tests/post-rest-user-login.test.ts @@ -0,0 +1,45 @@ +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 /rest/user/login', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['sqli', 'xss', 'csrf', 'jwt', 'secret_tokens'], + attackParamLocations: [AttackParamLocation.BODY], + starMetadata: { + code_source: 'tssbox/juice-shop:master', + databases: ['SQLite'], + user_roles: { + roles: ['customer', 'deluxe', 'accounting', 'admin'] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.POST, + url: `${baseUrl}/rest/user/login`, + body: { + email: 'user@example.com', + password: 'securePassword123' + }, + headers: { 'Content-Type': 'application/json' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/post-rest-user-reset-password.test.ts b/.brightsec/tests/post-rest-user-reset-password.test.ts new file mode 100644 index 00000000000..e9c884c0041 --- /dev/null +++ b/.brightsec/tests/post-rest-user-reset-password.test.ts @@ -0,0 +1,47 @@ +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 /rest/user/reset-password', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'xss', 'sqli', 'email_injection'], + attackParamLocations: [AttackParamLocation.BODY], + starMetadata: { + code_source: 'tssbox/juice-shop:master', + databases: ['SQLite'], + user_roles: { + roles: ['customer', 'deluxe', 'accounting', 'admin'] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.POST, + url: `${baseUrl}/rest/user/reset-password`, + body: { + email: 'user@example.com', + answer: 'correct_answer', + new: 'new_password', + repeat: 'new_password' + }, + headers: { 'Content-Type': 'application/json' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/post-rest-web3-submit-key.test.ts b/.brightsec/tests/post-rest-web3-submit-key.test.ts new file mode 100644 index 00000000000..84665e4eb06 --- /dev/null +++ b/.brightsec/tests/post-rest-web3-submit-key.test.ts @@ -0,0 +1,44 @@ +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 /rest/web3/submitKey', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'xss', 'secret_tokens', 'osi', 'business_constraint_bypass'], + attackParamLocations: [AttackParamLocation.BODY], + starMetadata: { + code_source: "tssbox/juice-shop:master", + databases: ["SQLite"], + user_roles: { + roles: ["customer", "deluxe", "accounting", "admin"] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.POST, + url: `${baseUrl}/rest/web3/submitKey`, + body: { + privateKey: "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef" + }, + headers: { 'Content-Type': 'application/json' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/post-rest-web3-wallet-exploit-address.test.ts b/.brightsec/tests/post-rest-web3-wallet-exploit-address.test.ts new file mode 100644 index 00000000000..1e2a7697634 --- /dev/null +++ b/.brightsec/tests/post-rest-web3-wallet-exploit-address.test.ts @@ -0,0 +1,44 @@ +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 /rest/web3/walletExploitAddress', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['nosql', 'xss', 'csrf', 'osi', 'ssrf'], + attackParamLocations: [AttackParamLocation.BODY], + starMetadata: { + code_source: "tssbox/juice-shop:master", + databases: ["SQLite"], + user_roles: { + roles: ["customer", "deluxe", "accounting", "admin"] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.POST, + url: `${baseUrl}/rest/web3/walletExploitAddress`, + body: { + walletAddress: "0x1234567890abcdef1234567890abcdef12345678" + }, + headers: { 'Content-Type': 'application/json' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/post-rest-web3-wallet-nft-verify.test.ts b/.brightsec/tests/post-rest-web3-wallet-nft-verify.test.ts new file mode 100644 index 00000000000..3fd4b338aff --- /dev/null +++ b/.brightsec/tests/post-rest-web3-wallet-nft-verify.test.ts @@ -0,0 +1,44 @@ +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 /rest/web3/walletNFTVerify', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'nosql', 'xss', 'osi', 'secret_tokens'], + attackParamLocations: [AttackParamLocation.BODY], + starMetadata: { + code_source: "tssbox/juice-shop:master", + databases: ["SQLite"], + user_roles: { + roles: ["customer", "deluxe", "accounting", "admin"] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.POST, + url: `${baseUrl}/rest/web3/walletNFTVerify`, + body: { + walletAddress: "0x1234567890abcdef1234567890abcdef12345678" + }, + headers: { 'Content-Type': 'application/json' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/post-snippets-fixes.test.ts b/.brightsec/tests/post-snippets-fixes.test.ts new file mode 100644 index 00000000000..f6862bdd410 --- /dev/null +++ b/.brightsec/tests/post-snippets-fixes.test.ts @@ -0,0 +1,45 @@ +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 /snippets/fixes', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['bopla', 'nosql', 'osi', 'sqli', 'xss'], + attackParamLocations: [AttackParamLocation.BODY], + starMetadata: { + code_source: "tssbox/juice-shop:master", + databases: ["SQLite"], + user_roles: { + roles: ["customer", "deluxe", "accounting", "admin"] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.POST, + url: `${baseUrl}/snippets/fixes`, + body: { + key: "exampleKey", + selectedFix: 1 + }, + headers: { 'Content-Type': 'application/json' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/post-snippets-verdict.test.ts b/.brightsec/tests/post-snippets-verdict.test.ts new file mode 100644 index 00000000000..f9b8f8f7483 --- /dev/null +++ b/.brightsec/tests/post-snippets-verdict.test.ts @@ -0,0 +1,45 @@ +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 /snippets/verdict', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['xss', 'csrf'], + attackParamLocations: [AttackParamLocation.BODY], + starMetadata: { + code_source: "tssbox/juice-shop:master", + databases: ["SQLite"], + user_roles: { + roles: ["customer", "deluxe", "accounting", "admin"] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.POST, + url: `${baseUrl}/snippets/verdict`, + body: { + selectedLines: [1, 2, 3], + key: "restfulXssChallenge" + }, + headers: { 'Content-Type': 'application/json' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/put-api-addresses-1.test.ts b/.brightsec/tests/put-api-addresses-1.test.ts new file mode 100644 index 00000000000..4ff5dd6b5e6 --- /dev/null +++ b/.brightsec/tests/put-api-addresses-1.test.ts @@ -0,0 +1,51 @@ +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/addresses/1', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['bopla', 'sqli', 'xss', 'csrf', 'id_enumeration'], + attackParamLocations: [AttackParamLocation.BODY, AttackParamLocation.HEADER], + starMetadata: { + code_source: 'tssbox/juice-shop:master', + databases: ['SQLite'], + user_roles: { + roles: ['customer', 'deluxe', 'accounting', 'admin'] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.PUT, + url: `${baseUrl}/api/Addresses/1`, + body: { + UserId: 1, + fullName: 'John Doe', + mobileNum: 1234567890, + zipCode: '12345', + streetAddress: '123 Main St', + city: 'Metropolis', + state: 'NY', + country: 'USA' + }, + headers: { 'Content-Type': 'application/json' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/put-api-basket-items-1.test.ts b/.brightsec/tests/put-api-basket-items-1.test.ts new file mode 100644 index 00000000000..a4ed10cdfb2 --- /dev/null +++ b/.brightsec/tests/put-api-basket-items-1.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('PUT /api/basket-items/1', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['bopla', 'business_constraint_bypass', 'id_enumeration', 'sqli', 'xss'], + attackParamLocations: [AttackParamLocation.BODY], + starMetadata: { + code_source: 'tssbox/juice-shop:master', + databases: ['SQLite'], + user_roles: { + roles: ['customer', 'deluxe', 'accounting', 'admin'] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.PUT, + url: `${baseUrl}/api/BasketItems/1`, + body: { + ProductId: 1, + BasketId: 1, + quantity: 2 + }, + headers: { 'Content-Type': 'application/json' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/put-api-hints-1.test.ts b/.brightsec/tests/put-api-hints-1.test.ts new file mode 100644 index 00000000000..f55a70d904e --- /dev/null +++ b/.brightsec/tests/put-api-hints-1.test.ts @@ -0,0 +1,47 @@ +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/Hints/1', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['bopla', 'csrf', 'xss', 'sqli', 'id_enumeration'], + attackParamLocations: [AttackParamLocation.BODY, AttackParamLocation.PATH], + starMetadata: { + code_source: "tssbox/juice-shop:master", + databases: ["SQLite"], + user_roles: { + roles: ["customer", "deluxe", "accounting", "admin"] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.PUT, + url: `${baseUrl}/api/Hints/1`, + body: { + ChallengeId: 1, + text: "Sample hint text", + order: 1, + unlocked: true + }, + headers: { 'Content-Type': 'application/json' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/put-rest-order-history-id-delivery-status.test.ts b/.brightsec/tests/put-rest-order-history-id-delivery-status.test.ts new file mode 100644 index 00000000000..1fb53a26115 --- /dev/null +++ b/.brightsec/tests/put-rest-order-history-id-delivery-status.test.ts @@ -0,0 +1,44 @@ +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 /rest/order-history/:id/delivery-status', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['bopla', 'id_enumeration', 'sqli', 'csrf', 'xss'], + attackParamLocations: [AttackParamLocation.BODY, AttackParamLocation.PATH], + starMetadata: { + code_source: "tssbox/juice-shop:master", + databases: ["SQLite"], + user_roles: { + roles: ["customer", "deluxe", "accounting", "admin"] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.PUT, + url: `${baseUrl}/rest/order-history/123/delivery-status`, + body: { + deliveryStatus: true + }, + headers: { 'Content-Type': 'application/json' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/put-rest-products-123-reviews.test.ts b/.brightsec/tests/put-rest-products-123-reviews.test.ts new file mode 100644 index 00000000000..8972b925e28 --- /dev/null +++ b/.brightsec/tests/put-rest-products-123-reviews.test.ts @@ -0,0 +1,45 @@ +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 /rest/products/123/reviews', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['bopla', 'nosql', 'xss'], + attackParamLocations: [AttackParamLocation.BODY], + starMetadata: { + code_source: 'tssbox/juice-shop:master', + databases: ['SQLite'], + user_roles: { + roles: ['customer', 'deluxe', 'accounting', 'admin'] + } + } + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.PUT, + url: `${baseUrl}/rest/products/123/reviews`, + body: { + message: 'Great product!', + author: 'user@example.com' + }, + headers: { 'Content-Type': 'application/json' } + }); +}); \ No newline at end of file diff --git a/.github/workflows/bright.yml b/.github/workflows/bright.yml new file mode 100644 index 00000000000..9cdc91c30af --- /dev/null +++ b/.github/workflows/bright.yml @@ -0,0 +1,57 @@ +name: Bright + +on: + pull_request: + branches: + - '**' + +permissions: + checks: write + contents: read + id-token: write + +jobs: + test: + runs-on: ubuntu-latest + steps: + - name: Check out Git repository + uses: actions/checkout@v4 + + - name: Use Node.js 22 + uses: actions/setup-node@v4 + with: + node-version: 22 + + - name: Install application dependencies + run: | + npm install + + - name: Start the application + run: | + npm start & + + - name: Probe application readiness + run: | + for i in {1..30}; do nc -z 127.0.0.1 3000 && exit 0 || sleep 5; done; exit 1 + + - 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: development.playground.brightsec.com + BRIGHT_PROJECT_ID: xagvSFR3EMYf1Yhma8dxEJ + BRIGHT_TOKEN: ${{ secrets.BRIGHT_TOKEN }} + + - name: Run security tests + env: + BRIGHT_HOSTNAME: development.playground.brightsec.com + BRIGHT_PROJECT_ID: xagvSFR3EMYf1Yhma8dxEJ + BRIGHT_AUTH_ID: wEfwSeetcm3JFpHqQAS5Sp + 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/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index 8c09281f61b..00000000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,358 +0,0 @@ -name: "CI/CD Pipeline" -on: - push: - branches-ignore: - - l10n_develop - - gh-pages - paths-ignore: - - '*.md' - - 'LICENSE' - - 'monitoring/grafana-dashboard.json' - - 'screenshots/**' - tags-ignore: - - '*' - pull_request: - paths-ignore: - - '*.md' - - 'LICENSE' - - 'data/static/i18n/*.json' - - 'frontend/src/assets/i18n/*.json' -env: - NODE_DEFAULT_VERSION: 22 - NODE_OPTIONS: "--max_old_space_size=4096" - CYCLONEDX_NPM_VERSION: '^2.0.0||^3.0.0' -jobs: - lint: - runs-on: ubuntu-latest - steps: - - name: "Check out Git repository" - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2 - - name: "Use Node.js 22" - uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af #v4.1.0 - with: - node-version: ${{ env.NODE_DEFAULT_VERSION }} - - name: "Install application minimalistically" - run: | - npm install --ignore-scripts - cd frontend - npm install --ignore-scripts --legacy-peer-deps - - name: "Lint source code" - run: npm run lint - - name: "Lint customization configs" - run: > - npm run lint:config -- -f ./config/7ms.yml && - npm run lint:config -- -f ./config/addo.yml && - npm run lint:config -- -f ./config/bodgeit.yml && - npm run lint:config -- -f ./config/ctf.yml && - npm run lint:config -- -f ./config/default.yml && - npm run lint:config -- -f ./config/fbctf.yml && - npm run lint:config -- -f ./config/juicebox.yml && - npm run lint:config -- -f ./config/mozilla.yml && - npm run lint:config -- -f ./config/oss.yml && - npm run lint:config -- -f ./config/quiet.yml && - npm run lint:config -- -f ./config/tutorial.yml && - npm run lint:config -- -f ./config/unsafe.yml - coding-challenge-rsn: - runs-on: windows-latest - steps: - - name: "Check out Git repository" - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2 - - name: "Use Node.js 22" - uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af #v4.1.0 - with: - node-version: ${{ env.NODE_DEFAULT_VERSION }} - - name: "Install application" - run: npm install - - name: "Check coding challenges for accidental code discrepancies" - run: npm run rsn - test: - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-latest, macos-latest] # FIXME: Removed "windows-latest" due to 'Error: ENOENT: no such file or directory, open' error breaking at least on Node 20.0 constantly - node-version: [20, 22, 24] - steps: - - name: "Check out Git repository" - if: github.repository == 'juice-shop/juice-shop' || (github.repository != 'juice-shop/juice-shop' && matrix.os == 'ubuntu-latest' && matrix.node-version == '22') - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2 - - name: "Use Node.js ${{ matrix.node-version }}" - if: github.repository == 'juice-shop/juice-shop' || (github.repository != 'juice-shop/juice-shop' && matrix.os == 'ubuntu-latest' && matrix.node-version == '22') - uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af #v4.1.0 - with: - node-version: ${{ matrix.node-version }} - - name: "Install application" - if: github.repository == 'juice-shop/juice-shop' || (github.repository != 'juice-shop/juice-shop' && matrix.os == 'ubuntu-latest' && matrix.node-version == '22') - run: npm install - - name: "Execute unit tests" - if: github.repository == 'juice-shop/juice-shop' || (github.repository != 'juice-shop/juice-shop' && matrix.os == 'ubuntu-latest' && matrix.node-version == '22') - uses: nick-invision/retry@7152eba30c6575329ac0576536151aca5a72780e #v3.0.0 - with: - timeout_minutes: 15 - max_attempts: 3 - command: npm test - - name: "Copy unit test coverage data" - if: github.repository == 'juice-shop/juice-shop' && github.event_name == 'push' && matrix.os == 'ubuntu-latest' && matrix.node-version == '22' - run: | - cp build/reports/coverage/frontend-tests/lcov.info frontend-lcov.info - cp build/reports/coverage/server-tests/lcov.info server-lcov.info - sed -i s/SF:/SF:frontend\\//g frontend-lcov.info - shell: bash - - name: "Upload unit test coverage data" - if: github.repository == 'juice-shop/juice-shop' && github.event_name == 'push' && matrix.os == 'ubuntu-latest' && matrix.node-version == '22' - uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b #v4.5.0 - with: - name: unit-test-lcov - path: | - frontend-lcov.info - server-lcov.info - api-test: - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-latest, windows-latest, macos-latest] - node-version: [20, 22, 24] - steps: - - name: "Check out Git repository" - if: github.repository == 'juice-shop/juice-shop' || (github.repository != 'juice-shop/juice-shop' && matrix.os == 'ubuntu-latest' && matrix.node-version == '22') - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2 - - name: "Use Node.js ${{ matrix.node-version }}" - if: github.repository == 'juice-shop/juice-shop' || (github.repository != 'juice-shop/juice-shop' && matrix.os == 'ubuntu-latest' && matrix.node-version == '22') - uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af #v4.1.0 - with: - node-version: ${{ matrix.node-version }} - - name: "Install application" - if: github.repository == 'juice-shop/juice-shop' || (github.repository != 'juice-shop/juice-shop' && matrix.os == 'ubuntu-latest' && matrix.node-version == '22') - run: npm install - - name: "Execute integration tests" - if: github.repository == 'juice-shop/juice-shop' || (github.repository != 'juice-shop/juice-shop' && matrix.os == 'ubuntu-latest' && matrix.node-version == '22') - uses: nick-invision/retry@7152eba30c6575329ac0576536151aca5a72780e #v3.0.0 - env: - NODE_ENV: test - with: - timeout_minutes: 5 - max_attempts: 3 - command: npm run frisby - - name: "Copy API test coverage data" - if: github.repository == 'juice-shop/juice-shop' && github.event_name == 'push' && matrix.os == 'ubuntu-latest' && matrix.node-version == '22' - run: cp build/reports/coverage/api-tests/lcov.info api-lcov.info - - name: "Upload API test coverage data" - if: github.repository == 'juice-shop/juice-shop' && github.event_name == 'push' && matrix.os == 'ubuntu-latest' && matrix.node-version == '22' - uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b #v4.5.0 - with: - name: api-test-lcov - path: | - api-lcov.info - coverage-report: - needs: [test, api-test] - runs-on: ubuntu-latest - if: github.repository == 'juice-shop/juice-shop' && github.event_name == 'push' - steps: - - name: "Check out Git repository" - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2 - - name: "Download unit test coverage data" - uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 #v4.1.8 - with: - name: unit-test-lcov - - name: "Download API test coverage data" - uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 #v4.1.8 - with: - name: api-test-lcov - - name: "Publish coverage to Coveralls" - uses: coverallsapp/github-action@v2 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - files: frontend-lcov.info server-lcov.info api-lcov.info - custom-config-test: - runs-on: ubuntu-latest - steps: - - name: "Check out Git repository" - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2 - - name: "Use Node.js 22" - uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af #v4.1.0 - with: - node-version: ${{ env.NODE_DEFAULT_VERSION }} - - name: "Install application" - if: github.repository == 'juice-shop/juice-shop' || (github.repository != 'juice-shop/juice-shop' && matrix.os == 'ubuntu-latest' && matrix.node-version == '22') - run: npm install - - name: "Execute server tests for each custom configuration" - uses: nick-invision/retry@7152eba30c6575329ac0576536151aca5a72780e #v3.0.0 - with: - timeout_minutes: 30 - max_attempts: 3 - command: > - NODE_ENV=7ms npm run test:server && - NODE_ENV=addo npm run test:server && - NODE_ENV=bodgeit npm run test:server && - NODE_ENV=ctf npm run test:server && - NODE_ENV=fbctf npm run test:server && - NODE_ENV=juicebox npm run test:server && - NODE_ENV=mozilla npm run test:server && - NODE_ENV=oss npm run test:server && - NODE_ENV=quiet npm run test:server && - NODE_ENV=tutorial npm run test:server && - NODE_ENV=unsafe npm run test:server - e2e: - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-latest, macos-latest] - browser: [chrome] # FIXME Switch back to [chrome, firefox] after debugging extreme flakiness of Firefox on CI/CD - fail-fast: false - steps: - - name: "Check out Git repository" - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2 - - name: "Use Node.js 22" - uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af #v4.1.0 - with: - node-version: ${{ env.NODE_DEFAULT_VERSION }} - - name: "Install CLI tools" - run: npm install -g @angular/cli - - name: "Install application" - run: npm install - - name: "Execute end-to-end tests on Ubuntu" - if: ${{ matrix.os == 'ubuntu-latest' }} - uses: cypress-io/github-action@57b70560982e6a11d23d4b8bec7f8a487cdbb71b #v6.7.8 - with: - install: false - browser: ${{ matrix.browser }} - start: npm start - wait-on: http://localhost:3000 - record: true - group: ${{ matrix.browser }} @ ${{ matrix.os }} - env: - SOLUTIONS_WEBHOOK: ${{ secrets.E2E_SOLUTIONS_WEBHOOK }} - CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: "Execute end-to-end tests on Mac" - if: ${{ matrix.os == 'macos-latest' }} - uses: cypress-io/github-action@57b70560982e6a11d23d4b8bec7f8a487cdbb71b #v6.7.8 - with: - install: false - browser: ${{ matrix.browser }} - start: npm start - wait-on: http://localhost:3000 - record: true - group: ${{ matrix.browser }} @ ${{ matrix.os }} - env: - CYPRESS_CACHE_FOLDER: /Users/runner/Library/Caches/Cypress - CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - smoke-test: - runs-on: ubuntu-latest - steps: - - name: "Check out Git repository" - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2 - - name: "Use Node.js 22" - uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af #v4.1.0 - with: - node-version: ${{ env.NODE_DEFAULT_VERSION }} - - name: "Install CLI tools" - run: | - npm install -g @cyclonedx/cyclonedx-npm@$CYCLONEDX_NPM_VERSION - npm install -g grunt-cli - - name: "Set packaging options for Grunt" - run: | - echo "PCKG_OS_NAME=linux" >> $GITHUB_ENV - echo "PCKG_NODE_VERSION=18" >> $GITHUB_ENV - echo "PCKG_CPU_ARCH=x64" >> $GITHUB_ENV - - name: "Package application" - run: | - npm install --production - npm run package:ci - - name: "Unpack application archive" - run: | - cd dist - tar -zxf juice-shop-*.tgz - - name: "Execute smoke test" - run: | - cd dist/juice-shop_* - npm start & - cd ../.. - chmod +x test/smoke/smoke-test.sh - test/smoke/smoke-test.sh http://localhost:3000 - docker-test: - runs-on: ubuntu-latest - steps: - - name: "Check out Git repository" - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2 - - name: "Execute smoke test on Docker" - run: docker compose -f docker-compose.test.yml up --exit-code-from sut - docker: - if: github.repository == 'juice-shop/juice-shop' && github.event_name == 'push' && (github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/master') - needs: [test, api-test, e2e, custom-config-test, docker-test] - runs-on: ubuntu-latest - steps: - - name: "Check out Git repository" - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2 - - name: "Set up QEMU" - uses: docker/setup-qemu-action@49b3bc8e6bdd4a60e6116a5414239cba5943d3cf #v3.2.0 - - name: "Set up Docker Buildx" - uses: docker/setup-buildx-action@6524bf65af31da8d45b59e8c27de4bd072b392f5 #v3.8.0 - - name: "Login to DockerHub" - uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 #v3.3.0 - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - name: "Set tag & labels for ${{ github.ref }}" - run: | - if [ "$GITHUB_REF" == "refs/heads/master" ]; then - echo "DOCKER_TAG=latest" >> $GITHUB_ENV - else - echo "DOCKER_TAG=snapshot" >> $GITHUB_ENV - fi - echo "VCS_REF=`git rev-parse --short HEAD`" >> $GITHUB_ENV - echo "BUILD_DATE=`date -u +”%Y-%m-%dT%H:%M:%SZ”`" >> $GITHUB_ENV - - name: "Build and push for AMD64 and ARM64 processors" - uses: docker/build-push-action@48aba3b46d1b1fec4febb7c5d0c644b249a11355 #v6.1.0 - with: - context: . - file: ./Dockerfile - platforms: linux/amd64,linux/arm64 - push: true - tags: | - bkimminich/juice-shop:${{ env.DOCKER_TAG }} - build-args: | - VCS_REF=${{ env.VCS_REF }} - BUILD_DATE=${{ env.BUILD_DATE }} - CYCLONEDX_NPM_VERSION=${{ env.CYCLONEDX_NPM_VERSION }} - heroku: - if: github.repository == 'juice-shop/juice-shop' && github.event_name == 'push' && (github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/master') - needs: [test, api-test, e2e, custom-config-test] - runs-on: ubuntu-latest - steps: - - name: "Check out Git repository" - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2 - - name: "Install Heroku CLI" - run: curl https://cli-assets.heroku.com/install.sh | sh - - name: "Set Heroku app & branch for ${{ github.ref }}" - run: | - if [ "$GITHUB_REF" == "refs/heads/master" ]; then - echo "HEROKU_APP=juice-shop" >> $GITHUB_ENV - echo "HEROKU_BRANCH=master" >> $GITHUB_ENV - else - echo "HEROKU_APP=juice-shop-staging" >> $GITHUB_ENV - echo "HEROKU_BRANCH=develop" >> $GITHUB_ENV - fi - - name: "Deploy ${{ github.ref }} to Heroku" - uses: akhileshns/heroku-deploy@581dd286c962b6972d427fcf8980f60755c15520 #v3.13.15 - with: - heroku_api_key: ${{ secrets.HEROKU_API_KEY }} - heroku_app_name: ${{ env.HEROKU_APP }} - heroku_email: bjoern.kimminich@owasp.org - branch: ${{ env.HEROKU_BRANCH }} - notify-slack: - if: github.repository == 'juice-shop/juice-shop' && github.event_name == 'push' && (success() || failure()) - needs: - - docker - - heroku - - lint - - coding-challenge-rsn - - smoke-test - - coverage-report - runs-on: ubuntu-latest - steps: - - name: "Slack workflow notification" - uses: Gamesight/slack-workflow-status@68bf00d0dbdbcb206c278399aa1ef6c14f74347a #v1.3.0 - with: - repo_token: ${{ secrets.GITHUB_TOKEN }} - slack_webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }} diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml deleted file mode 100644 index fe353eb0ee5..00000000000 --- a/.github/workflows/codeql-analysis.yml +++ /dev/null @@ -1,33 +0,0 @@ -name: "CodeQL Scan" - -on: - push: - pull_request: - -jobs: - analyze: - name: Analyze - runs-on: ubuntu-latest - permissions: - actions: read - contents: read - security-events: write - strategy: - fail-fast: false - matrix: - language: [ 'javascript-typescript' ] - steps: - - name: Checkout repository - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2 - - name: Initialize CodeQL - uses: github/codeql-action/init@v3 - with: - languages: ${{ matrix.language }} - queries: security-extended - config: | - paths-ignore: - - 'data/static/codefixes' - - name: Autobuild - uses: github/codeql-action/autobuild@v3 - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v3 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 00000000000..84983846b0d --- /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 diff --git a/.github/workflows/lint-fixer.yml b/.github/workflows/lint-fixer.yml deleted file mode 100644 index 907f841e1b8..00000000000 --- a/.github/workflows/lint-fixer.yml +++ /dev/null @@ -1,29 +0,0 @@ -name: "Let me lint:fix that for you" - -on: [push] - -jobs: - LMLFTFY: - runs-on: ubuntu-latest - steps: - - name: "Check out Git repository" - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2 - - name: "Use Node.js 22" - uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af #v4.1.0 - with: - node-version: 22 - - name: "Install application" - run: | - npm install --ignore-scripts - cd frontend - npm install --ignore-scripts --legacy-peer-deps - - name: "Fix everything which can be fixed" - run: 'npm run lint:fix' - - uses: stefanzweifel/git-auto-commit-action@8621497c8c39c72f3e2a999a26b4ca1b5058a842 #v5.0.1 - with: - commit_message: "Auto-fix linting issues" - branch: ${{ github.head_ref }} - commit_options: '--signoff' - commit_user_name: JuiceShopBot - commit_user_email: 61591748+JuiceShopBot@users.noreply.github.com - commit_author: JuiceShopBot <61591748+JuiceShopBot@users.noreply.github.com> diff --git a/.github/workflows/lock.yml b/.github/workflows/lock.yml deleted file mode 100644 index 9d79216d828..00000000000 --- a/.github/workflows/lock.yml +++ /dev/null @@ -1,22 +0,0 @@ -name: 'Lock Threads' - -on: - schedule: - - cron: '0 0 * * *' - -permissions: - issues: write - pull-requests: write - -jobs: - action: - runs-on: ubuntu-latest - steps: - - uses: dessant/lock-threads@1bf7ec25051fe7c00bdd17e6a7cf3d7bfb7dc771 #v5.0.1 - with: - issue-lock-comment: > - This thread has been automatically locked because it has not had - recent activity after it was closed. :lock: Please open a new issue - for regressions or related bugs. - issue-lock-reason: '' - pr-lock-reason: '' diff --git a/.github/workflows/rebase.yml b/.github/workflows/rebase.yml deleted file mode 100644 index f999d22edf1..00000000000 --- a/.github/workflows/rebase.yml +++ /dev/null @@ -1,26 +0,0 @@ -name: Automatic Rebase - -on: - issue_comment: - types: [created] - -jobs: - rebase: - name: Rebase - if: github.event.issue.pull_request != '' && contains(github.event.comment.body, '/rebase') - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2 - with: - fetch-depth: 0 - - name: Automatic Rebase - uses: cirrus-actions/rebase@b87d48154a87a85666003575337e27b8cd65f691 #v1.8 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # https://github.community/t5/GitHub-Actions/Workflow-is-failing-if-no-job-can-be-ran-due-to-condition/m-p/38186#M3250 - always_job: - name: Always run job - runs-on: ubuntu-latest - steps: - - name: Always run - run: echo "This job is used to prevent the workflow to fail when all other jobs are skipped." diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index 4aad876031e..00000000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,95 +0,0 @@ -name: "Release Pipeline" -on: - push: - tags: - - v* -env: - CYCLONEDX_NPM_VERSION: '^2.0.0||^3.0.0' -jobs: - package: - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-latest, windows-latest, macos-latest] - node-version: [20, 22, 24] - fail-fast: false - steps: - - name: "Check out Git repository" - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2 - - name: "Use Node.js ${{ matrix.node-version }}" - uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af #v4.1.0 - with: - node-version: ${{ matrix.node-version }} - - name: "Install CLI tools" - run: | - npm install -g @cyclonedx/cyclonedx-npm@$CYCLONEDX_NPM_VERSION - npm install -g grunt-cli - - name: "Set packaging options for Grunt" - run: | - if [ "$RUNNER_OS" == "Windows" ]; then - echo "PCKG_OS_NAME=win32" >> $GITHUB_ENV - elif [ "$RUNNER_OS" == "macOS" ]; then - echo "PCKG_OS_NAME=darwin" >> $GITHUB_ENV - else - echo "PCKG_OS_NAME=linux" >> $GITHUB_ENV - fi - echo "PCKG_CPU_ARCH=x64" >> $GITHUB_ENV - echo "PCKG_NODE_VERSION=${{ matrix.node-version }}" >> $GITHUB_ENV - shell: bash - - name: "Package application" - run: | - npm install --production - npm run package:ci - - name: 'Attach packaged archive to tag release' - uses: softprops/action-gh-release@da05d552573ad5aba039eaac05058a918a7bf631 #v2.2.2 - with: - draft: true - files: dist/* - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - docker: - runs-on: ubuntu-latest - steps: - - name: "Check out Git repository" - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2 - - name: "Set up QEMU" - uses: docker/setup-qemu-action@49b3bc8e6bdd4a60e6116a5414239cba5943d3cf #v3.2.0 - - name: "Set up Docker Buildx" - uses: docker/setup-buildx-action@6524bf65af31da8d45b59e8c27de4bd072b392f5 #v3.8.0 - - name: "Login to DockerHub" - uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 #v3.3.0 - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - name: "Get tag name" - id: tag - uses: dawidd6/action-get-tag@727a6f0a561be04e09013531e73a3983a65e3479 #v1.1.0 TODO Action is archived and should be replaced eventually - - name: "Set labels for ${{ github.ref }}" - run: | - echo "VCS_REF=`git rev-parse --short HEAD`" >> $GITHUB_ENV - echo "BUILD_DATE=`date -u +”%Y-%m-%dT%H:%M:%SZ”`" >> $GITHUB_ENV - - name: "Build and push for AMD64 and ARM64 processors" - uses: docker/build-push-action@48aba3b46d1b1fec4febb7c5d0c644b249a11355 #v6.1.0 - with: - context: . - file: ./Dockerfile - platforms: linux/amd64,linux/arm64 - push: true - tags: | - bkimminich/juice-shop:${{ steps.tag.outputs.tag }} - build-args: | - VCS_REF=${{ env.VCS_REF }} - BUILD_DATE=${{ env.BUILD_DATE }} - CYCLONEDX_NPM_VERSION=${{ env.CYCLONEDX_NPM_VERSION }} - notify-slack: - if: always() - needs: - - package - - docker - runs-on: ubuntu-latest - steps: - - name: "Slack workflow notification" - uses: Gamesight/slack-workflow-status@68bf00d0dbdbcb206c278399aa1ef6c14f74347a #v1.3.0 - with: - repo_token: ${{ secrets.GITHUB_TOKEN }} - slack_webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }} diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml deleted file mode 100644 index 0519859a7b5..00000000000 --- a/.github/workflows/stale.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: 'Close stale issues and PR' -on: - schedule: - - cron: '30 1 * * *' - -jobs: - stale: - runs-on: ubuntu-latest - steps: - - uses: actions/stale@28ca1036281a5e5922ead5184a1bbf96e5fc984e #v9.0.0 - with: - stale-issue-message: > - This issue has been automatically marked as `stale` because it has not had - recent activity. :calendar: It will be _closed automatically_ in one week if no further activity occurs. - stale-pr-message: > - This PR has been automatically marked as `stale` because it has not had - recent activity. :calendar: It will be _closed automatically_ in two weeks if no further activity occurs. - close-issue-message: This issue was closed because it has been stalled for 7 days with no activity. - close-pr-message: This PR was closed because it has been stalled for 14 days with no activity. - days-before-stale: 14 - days-before-close: 7 - days-before-pr-close: 14 - exempt-issue-labels: 'critical,technical debt' - exempt-assignees: bkimminich diff --git a/.github/workflows/update-challenges-ebook.yml b/.github/workflows/update-challenges-ebook.yml deleted file mode 100644 index 9810a5ab503..00000000000 --- a/.github/workflows/update-challenges-ebook.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: "Update challenges in Companion Guide" - -on: - push: - branches: [ master, develop ] - paths: - - 'data/static/challenges.yml' - -jobs: - UpdateChallengesOnWebsite: - if: github.repository == 'juice-shop/juice-shop' - runs-on: ubuntu-latest - steps: - - name: Check out Git repository - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2 - with: - token: ${{ secrets.BOT_TOKEN }} - repository: juice-shop/pwning-juice-shop - ref: ${{ github.ref_name }} - - name: Update challenges.yml - run: | - cd docs/modules/ROOT/assets/data - rm challenges.yml - wget https://raw.githubusercontent.com/juice-shop/juice-shop/${{ github.ref_name }}/data/static/challenges.yml - - uses: stefanzweifel/git-auto-commit-action@8621497c8c39c72f3e2a999a26b4ca1b5058a842 #v5.0.1 - with: - commit_message: "Auto-update challenges.yml from ${{ github.sha }}" - branch: ${{ github.ref_name }} - commit_options: '--signoff' - - # Optional commit user and author settings - commit_user_name: JuiceShopBot - commit_user_email: 61591748+JuiceShopBot@users.noreply.github.com - commit_author: JuiceShopBot <61591748+JuiceShopBot@users.noreply.github.com> diff --git a/.github/workflows/update-challenges-www.yml b/.github/workflows/update-challenges-www.yml deleted file mode 100644 index caaa7405bf1..00000000000 --- a/.github/workflows/update-challenges-www.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: "Update challenges on owasp-juice.shop" - -on: - push: - branches: [ master ] - paths: - - 'data/static/challenges.yml' - -jobs: - UpdateChallengesOnWebsite: - if: github.repository == 'juice-shop/juice-shop' - runs-on: ubuntu-latest - steps: - - name: Check out Git repository - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2 - with: - token: ${{ secrets.BOT_TOKEN }} - repository: OWASP/www-project-juice-shop - ref: master - - name: Update challenges.yml - run: | - cd _data/ - rm challenges.yml - wget https://raw.githubusercontent.com/juice-shop/juice-shop/master/data/static/challenges.yml - - uses: stefanzweifel/git-auto-commit-action@8621497c8c39c72f3e2a999a26b4ca1b5058a842 #v5.0.1 - with: - commit_message: "Auto-update challenges.yml from ${{ github.sha }}" - branch: master - commit_options: '--signoff' - - # Optional commit user and author settings - commit_user_name: JuiceShopBot - commit_user_email: 61591748+JuiceShopBot@users.noreply.github.com - commit_author: JuiceShopBot <61591748+JuiceShopBot@users.noreply.github.com> diff --git a/.github/workflows/update-news-www.yml b/.github/workflows/update-news-www.yml deleted file mode 100644 index 26757465a1a..00000000000 --- a/.github/workflows/update-news-www.yml +++ /dev/null @@ -1,29 +0,0 @@ -name: "Update news on owasp-juice.shop" - -on: - release: - types: [ published ] - -jobs: - UpdateNewsOnWebsite: - runs-on: ubuntu-latest - steps: - - name: Check out Git repository - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2 - with: - token: ${{ secrets.BOT_TOKEN }} - repository: OWASP/www-project-juice-shop - branch: master - - name: Update tab_news.md - run: | - sed -i 's//\n* ${{ github.event.release.published_at }}: juice-shop [`${{ github.event.release.tag_name }}`](https:\/\/github.com\/juice-shop\/juice-shop\/releases\/tag\/${{ github.event.release.tag_name }})/' tab_news.md - - uses: stefanzweifel/git-auto-commit-action@8621497c8c39c72f3e2a999a26b4ca1b5058a842 #v5.0.1 - with: - commit_message: "Add juice-shop ${{ github.event.release.tag_name }} release notes to tab_news.md" - branch: master - commit_options: '--signoff' - - # Optional commit user and author settings - commit_user_name: JuiceShopBot - commit_user_email: 61591748+JuiceShopBot@users.noreply.github.com - commit_author: JuiceShopBot <61591748+JuiceShopBot@users.noreply.github.com> diff --git a/.github/workflows/zap_scan.yml b/.github/workflows/zap_scan.yml deleted file mode 100644 index 44117a146b3..00000000000 --- a/.github/workflows/zap_scan.yml +++ /dev/null @@ -1,22 +0,0 @@ -name: "ZAP Baseline Scan" - -on: - schedule: - - cron: '0 18 * * 6' - -jobs: - zap_scan: - runs-on: ubuntu-latest - name: Scan Juice Shop preview instance on Heroku - steps: - - name: Check out Git repository - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2 - with: - ref: develop - - name: ZAP Scan - uses: zaproxy/action-baseline@7c4deb10e6261301961c86d65d54a516394f9aed # v0.14.0 - with: - token: ${{ secrets.GITHUB_TOKEN }} - target: 'https://preview.owasp-juice.shop' - rules_file_name: '.zap/rules.tsv' - cmd_options: '-a -j' diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml deleted file mode 100644 index 7b5f3c01b0a..00000000000 --- a/.gitlab-ci.yml +++ /dev/null @@ -1,7 +0,0 @@ -include: - - template: Auto-DevOps.gitlab-ci.yml - -variables: - SAST_EXCLUDED_PATHS: "frontend/src/assets/private/**" - TEST_DISABLED: "true" - DAST_DISABLED: "true" diff --git a/routes/order.ts b/routes/order.ts index be0693b30df..39c387c55ea 100644 --- a/routes/order.ts +++ b/routes/order.ts @@ -144,6 +144,7 @@ export function placeOrder () { }) } else { next(new Error('Insufficient wallet balance.')) + return } } WalletModel.increment({ balance: totalPoints }, { where: { UserId: req.body.UserId } }).catch((error: unknown) => { diff --git a/server.ts b/server.ts index c58efa5f54c..d79b1ca7ca3 100644 --- a/server.ts +++ b/server.ts @@ -31,6 +31,7 @@ import securityTxt from 'express-security.txt' import { rateLimit } from 'express-rate-limit' import { getStream } from 'file-stream-rotator' import type { Request, Response, NextFunction } from 'express' +import { AsyncLocalStorage } from 'node:async_hooks' import { sequelize } from './models' import { UserModel } from './models/user' @@ -174,6 +175,25 @@ restoreOverwrittenFilesWithOriginals().then(() => { app.locals.abused_ssti_bug = false app.locals.abused_ssrf_bug = false + /* Unhandled rejections handling with AsyncLocalStorage */ + const als = new AsyncLocalStorage() + app.use((req: Request, res: Response, next: NextFunction) => { + als.run({ res }, () => { next() }) + }) + const onFatal = (reason: any) => { + console.error('[unhandledRejection]', reason) + + const store = als.getStore() as { res?: Response } | undefined + const res = store?.res + + if (res && !res.headersSent && !res.writableEnded) { + res.status(500).json({ error: 'Internal server error' }) + } + } + + process.on('uncaughtException', onFatal) + process.on('unhandledRejection', onFatal) + /* Compression for all requests */ app.use(compression())