diff --git a/.brightsec/.gitkeep b/.brightsec/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/.brightsec/tests/delete-logout.test.ts b/.brightsec/tests/delete-logout.test.ts new file mode 100644 index 0000000..1fed62a --- /dev/null +++ b/.brightsec/tests/delete-logout.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 /logout', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'http_method_fuzzing', 'unvalidated_redirect'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { + code_source: 'NeuraLegion/ruby-example-app:master', + databases: ['PostgreSQL'], + user_roles: [] + }, + poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.DELETE, + url: `${baseUrl}/logout`, + auth: process.env.BRIGHT_AUTH_ID + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/delete-posts-1-json.test.ts b/.brightsec/tests/delete-posts-1-json.test.ts new file mode 100644 index 0000000..edfae55 --- /dev/null +++ b/.brightsec/tests/delete-posts-1-json.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 /posts/1.json', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'bopla', 'sqli', 'id_enumeration', 'xss'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { + code_source: 'NeuraLegion/ruby-example-app:master', + databases: ['PostgreSQL'], + user_roles: [] + }, + poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.DELETE, + url: `${baseUrl}/posts/1.json`, + headers: { 'Content-Type': 'application/json' }, + auth: process.env.BRIGHT_AUTH_ID + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/delete-posts-1.test.ts b/.brightsec/tests/delete-posts-1.test.ts new file mode 100644 index 0000000..062042a --- /dev/null +++ b/.brightsec/tests/delete-posts-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 /posts/1', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'bopla', 'id_enumeration', 'sqli'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { + code_source: "NeuraLegion/ruby-example-app:master", + databases: ["PostgreSQL"], + user_roles: [] + }, + poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.DELETE, + url: `${baseUrl}/posts/1`, + headers: { 'Content-Type': 'application/json' }, + auth: process.env.BRIGHT_AUTH_ID + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/delete-users-1-json.test.ts b/.brightsec/tests/delete-users-1-json.test.ts new file mode 100644 index 0000000..8efdb64 --- /dev/null +++ b/.brightsec/tests/delete-users-1-json.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 /users/1.json', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'bopla', 'id_enumeration', 'sqli'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { + code_source: 'NeuraLegion/ruby-example-app:master', + databases: ['PostgreSQL'], + user_roles: [] + }, + poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.DELETE, + url: `${baseUrl}/users/1.json`, + headers: { 'Content-Type': 'application/json' }, + auth: process.env.BRIGHT_AUTH_ID + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/delete-users-1.test.ts b/.brightsec/tests/delete-users-1.test.ts new file mode 100644 index 0000000..1d76dd3 --- /dev/null +++ b/.brightsec/tests/delete-users-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 /users/1', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'bopla', 'id_enumeration', 'sqli'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { + code_source: 'NeuraLegion/ruby-example-app:master', + databases: ['PostgreSQL'], + user_roles: [] + }, + poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.DELETE, + url: `${baseUrl}/users/1`, + auth: process.env.BRIGHT_AUTH_ID + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-login.test.ts b/.brightsec/tests/get-login.test.ts new file mode 100644 index 0000000..4902023 --- /dev/null +++ b/.brightsec/tests/get-login.test.ts @@ -0,0 +1,40 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('GET /login', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'xss', 'sqli', 'secret_tokens', 'full_path_disclosure'], + attackParamLocations: [AttackParamLocation.PATH, AttackParamLocation.QUERY], + starMetadata: { + code_source: "NeuraLegion/ruby-example-app:master", + databases: ["PostgreSQL"], + user_roles: [] + }, + poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/login`, + auth: process.env.BRIGHT_AUTH_ID + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-posts-1-edit.test.ts b/.brightsec/tests/get-posts-1-edit.test.ts new file mode 100644 index 0000000..bd621cd --- /dev/null +++ b/.brightsec/tests/get-posts-1-edit.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 /posts/1/edit', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'bopla', 'id_enumeration', 'sqli'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { + code_source: 'NeuraLegion/ruby-example-app:master', + databases: ['PostgreSQL'], + user_roles: [] + }, + poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/posts/1/edit`, + headers: { 'Content-Type': 'application/json' }, + auth: process.env.BRIGHT_AUTH_ID + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-posts-1-json.test.ts b/.brightsec/tests/get-posts-1-json.test.ts new file mode 100644 index 0000000..35896f8 --- /dev/null +++ b/.brightsec/tests/get-posts-1-json.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 /posts/1.json', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'id_enumeration', 'sqli', 'xss'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { + code_source: "NeuraLegion/ruby-example-app:master", + databases: ["PostgreSQL"], + user_roles: [] + }, + poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/posts/1.json`, + headers: { 'Content-Type': 'application/json' }, + auth: process.env.BRIGHT_AUTH_ID + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-posts-1.test.ts b/.brightsec/tests/get-posts-1.test.ts new file mode 100644 index 0000000..2514aff --- /dev/null +++ b/.brightsec/tests/get-posts-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 /posts/1', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'id_enumeration', 'bopla', 'sqli', 'xss'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { + code_source: 'NeuraLegion/ruby-example-app:master', + databases: ['PostgreSQL'], + user_roles: [] + }, + poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/posts/1`, + headers: { 'Content-Type': 'application/json' }, + auth: process.env.BRIGHT_AUTH_ID + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-posts-json-user-id-1.test.ts b/.brightsec/tests/get-posts-json-user-id-1.test.ts new file mode 100644 index 0000000..18c9a0f --- /dev/null +++ b/.brightsec/tests/get-posts-json-user-id-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 /posts.json?user_id=1', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['bopla', 'id_enumeration', 'sqli', 'xss'], + attackParamLocations: [AttackParamLocation.QUERY], + starMetadata: { + code_source: 'NeuraLegion/ruby-example-app:master', + databases: ['PostgreSQL'], + user_roles: [] + }, + poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/posts.json?user_id=1`, + auth: process.env.BRIGHT_AUTH_ID + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-posts-new.test.ts b/.brightsec/tests/get-posts-new.test.ts new file mode 100644 index 0000000..64baf7d --- /dev/null +++ b/.brightsec/tests/get-posts-new.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 /posts/new', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'xss', 'bopla'], + attackParamLocations: [AttackParamLocation.HEADER], + starMetadata: { + code_source: 'NeuraLegion/ruby-example-app:master', + databases: ['PostgreSQL'], + user_roles: [] + }, + poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/posts/new`, + headers: { 'Content-Type': 'application/json' }, + auth: process.env.BRIGHT_AUTH_ID + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-posts-search.test.ts b/.brightsec/tests/get-posts-search.test.ts new file mode 100644 index 0000000..f61a5a6 --- /dev/null +++ b/.brightsec/tests/get-posts-search.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 /posts/search', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['sqli', 'xss', 'csrf', 'id_enumeration'], + attackParamLocations: [AttackParamLocation.QUERY], + starMetadata: { + code_source: 'NeuraLegion/ruby-example-app:master', + databases: ['PostgreSQL'], + user_roles: [] + }, + poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/posts/search?search_term=example`, + headers: { Authorization: 'Bearer ' }, + auth: process.env.BRIGHT_AUTH_ID + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-posts-user-id-1.test.ts b/.brightsec/tests/get-posts-user-id-1.test.ts new file mode 100644 index 0000000..1d1dbf1 --- /dev/null +++ b/.brightsec/tests/get-posts-user-id-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 /posts?user_id=1', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['bopla', 'id_enumeration', 'sqli', 'csrf', 'xss'], + attackParamLocations: [AttackParamLocation.QUERY], + starMetadata: { + code_source: 'NeuraLegion/ruby-example-app:master', + databases: ['PostgreSQL'], + user_roles: [] + }, + poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/posts?user_id=1`, + headers: { 'Content-Type': 'application/json' }, + auth: process.env.BRIGHT_AUTH_ID + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-users-1-edit.test.ts b/.brightsec/tests/get-users-1-edit.test.ts new file mode 100644 index 0000000..c5dac3d --- /dev/null +++ b/.brightsec/tests/get-users-1-edit.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 /users/1/edit', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'bopla', 'id_enumeration', 'xss'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { + code_source: 'NeuraLegion/ruby-example-app:master', + databases: ['PostgreSQL'], + user_roles: [] + }, + poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/users/1/edit`, + auth: process.env.BRIGHT_AUTH_ID + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-users-1.test.ts b/.brightsec/tests/get-users-1.test.ts new file mode 100644 index 0000000..d367bc6 --- /dev/null +++ b/.brightsec/tests/get-users-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 /users/1', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['id_enumeration', 'bopla', 'sqli', 'xss', 'csrf'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { + code_source: "NeuraLegion/ruby-example-app:master", + databases: ["PostgreSQL"], + user_roles: [] + }, + poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/users/1`, + auth: process.env.BRIGHT_AUTH_ID + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-users-123-edit.test.ts b/.brightsec/tests/get-users-123-edit.test.ts new file mode 100644 index 0000000..cfba349 --- /dev/null +++ b/.brightsec/tests/get-users-123-edit.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 /users/123/edit', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'bopla', 'id_enumeration', 'xss'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { + code_source: 'NeuraLegion/ruby-example-app:master', + databases: ['PostgreSQL'], + user_roles: [] + }, + poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/users/123/edit`, + auth: process.env.BRIGHT_AUTH_ID + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-users-json.test.ts b/.brightsec/tests/get-users-json.test.ts new file mode 100644 index 0000000..f648063 --- /dev/null +++ b/.brightsec/tests/get-users-json.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 /users.json', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['bopla', 'id_enumeration', 'improper_asset_management', 'sqli', 'xss'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { + code_source: 'NeuraLegion/ruby-example-app:master', + databases: ['PostgreSQL'], + user_roles: [] + }, + poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/users.json`, + auth: process.env.BRIGHT_AUTH_ID + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-users-new.test.ts b/.brightsec/tests/get-users-new.test.ts new file mode 100644 index 0000000..f16b90d --- /dev/null +++ b/.brightsec/tests/get-users-new.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 /users/new', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'xss', 'html_injection'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { + code_source: 'NeuraLegion/ruby-example-app:master', + databases: ['PostgreSQL'], + user_roles: [] + }, + poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/users/new`, + auth: process.env.BRIGHT_AUTH_ID + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-users.test.ts b/.brightsec/tests/get-users.test.ts new file mode 100644 index 0000000..e65f93b --- /dev/null +++ b/.brightsec/tests/get-users.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 /users', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'id_enumeration', 'business_constraint_bypass', 'xss', 'sqli'], + attackParamLocations: [AttackParamLocation.QUERY], + starMetadata: { + code_source: 'NeuraLegion/ruby-example-app:master', + databases: ['PostgreSQL'], + user_roles: [] + }, + poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/users`, + auth: process.env.BRIGHT_AUTH_ID + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/patch-posts-1-json.test.ts b/.brightsec/tests/patch-posts-1-json.test.ts new file mode 100644 index 0000000..3f8edb5 --- /dev/null +++ b/.brightsec/tests/patch-posts-1-json.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('PATCH /posts/1.json', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'bopla', 'sqli', 'xss', 'id_enumeration'], + attackParamLocations: [AttackParamLocation.BODY], + starMetadata: { + code_source: 'NeuraLegion/ruby-example-app:master', + databases: ['PostgreSQL'], + user_roles: [] + }, + poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.PATCH, + url: `${baseUrl}/posts/1.json`, + body: { + post: { + title: 'Updated Title', + content: 'Updated content of the post.', + public: true + } + }, + headers: { 'Content-Type': 'application/json' }, + auth: process.env.BRIGHT_AUTH_ID + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/patch-posts-1.test.ts b/.brightsec/tests/patch-posts-1.test.ts new file mode 100644 index 0000000..a7a25ba --- /dev/null +++ b/.brightsec/tests/patch-posts-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('PATCH /posts/1', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'bopla', 'sqli', 'xss', 'id_enumeration'], + attackParamLocations: [AttackParamLocation.BODY, AttackParamLocation.HEADER], + starMetadata: { + code_source: 'NeuraLegion/ruby-example-app:master', + databases: ['PostgreSQL'], + user_roles: [] + }, + poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.PATCH, + url: `${baseUrl}/posts/1`, + body: { + title: 'Updated Title', + content: 'Updated content of the post.', + public: true + }, + headers: { 'Content-Type': 'application/json' }, + auth: process.env.BRIGHT_AUTH_ID + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/patch-users-1-json.test.ts b/.brightsec/tests/patch-users-1-json.test.ts new file mode 100644 index 0000000..57cfee5 --- /dev/null +++ b/.brightsec/tests/patch-users-1-json.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('PATCH /users/1.json', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'sqli', 'xss', 'secret_tokens'], + attackParamLocations: [AttackParamLocation.BODY, AttackParamLocation.HEADER], + starMetadata: { + "code_source": "NeuraLegion/ruby-example-app:master", + "databases": ["PostgreSQL"], + "user_roles": [] + }, + poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.PATCH, + url: `${baseUrl}/users/1.json`, + body: { + user: { + email: "example@example.com", + password: "securepassword", + password_digest: "$2a$12$KIXQ1Y1rZ1u1Z1u1Z1u1Z.1Z1u1Z1u1Z1u1Z1u1Z1u1Z1u1Z1u", + admin: false + } + }, + headers: { 'Content-Type': 'application/json' }, + auth: process.env.BRIGHT_AUTH_ID + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/patch-users-1.test.ts b/.brightsec/tests/patch-users-1.test.ts new file mode 100644 index 0000000..44b3028 --- /dev/null +++ b/.brightsec/tests/patch-users-1.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('PATCH /users/1', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['bopla', 'csrf', 'sqli', 'xss'], + attackParamLocations: [AttackParamLocation.BODY], + starMetadata: { + code_source: 'NeuraLegion/ruby-example-app:master', + databases: ['PostgreSQL'], + user_roles: [] + }, + poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.PATCH, + url: `${baseUrl}/users/1`, + body: { + user: { + email: 'user@example.com', + password: 'securepassword', + password_digest: '$2a$12$KIXQ1Yf2Z1u1Q', + admin: false + } + }, + headers: { 'Content-Type': 'application/json' }, + auth: process.env.BRIGHT_AUTH_ID + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/patch-users-123.test.ts b/.brightsec/tests/patch-users-123.test.ts new file mode 100644 index 0000000..dab54f8 --- /dev/null +++ b/.brightsec/tests/patch-users-123.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('PATCH /users/123', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'sqli', 'xss', 'id_enumeration'], + attackParamLocations: [AttackParamLocation.BODY, AttackParamLocation.PATH], + starMetadata: { + code_source: 'NeuraLegion/ruby-example-app:master', + databases: ['PostgreSQL'], + user_roles: [] + }, + poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.PATCH, + url: `${baseUrl}/users/123`, + body: { + email: 'user@example.com', + password: 'securepassword', + password_digest: '$2a$12$KIXQ1Y1rZ1u1Z1u1Z1u1Z.1Z1u1Z1u1Z1u1Z1u1Z1u1Z1u1Z1u1Z1u', + admin: false + }, + headers: { 'Content-Type': 'application/json' }, + auth: process.env.BRIGHT_AUTH_ID + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/post-posts.test.ts b/.brightsec/tests/post-posts.test.ts new file mode 100644 index 0000000..6c0b017 --- /dev/null +++ b/.brightsec/tests/post-posts.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 /posts', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'xss', 'sqli', 'bopla', 'business_constraint_bypass'], + attackParamLocations: [AttackParamLocation.BODY], + starMetadata: { + code_source: 'NeuraLegion/ruby-example-app:master', + databases: ['PostgreSQL'], + user_roles: [] + }, + poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.POST, + url: `${baseUrl}/posts`, + body: { + post: { + title: 'Sample Post Title', + content: 'This is a sample post content.', + public: true + } + }, + headers: { 'Content-Type': 'application/json' }, + auth: process.env.BRIGHT_AUTH_ID + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/post-users-1-posts-json.test.ts b/.brightsec/tests/post-users-1-posts-json.test.ts new file mode 100644 index 0000000..3f585cf --- /dev/null +++ b/.brightsec/tests/post-users-1-posts-json.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 /users/1/posts.json', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'sqli', 'bopla', 'xss', 'id_enumeration'], + attackParamLocations: [AttackParamLocation.BODY], + starMetadata: { + code_source: 'NeuraLegion/ruby-example-app:master', + databases: ['PostgreSQL'], + user_roles: [] + }, + poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.POST, + url: `${baseUrl}/users/1/posts.json`, + body: { + post: { + title: 'Sample Title', + content: 'This is a sample post content.', + public: true + } + }, + headers: { 'Content-Type': 'application/json' }, + auth: process.env.BRIGHT_AUTH_ID + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/post-users-1-posts.test.ts b/.brightsec/tests/post-users-1-posts.test.ts new file mode 100644 index 0000000..2b8ec5e --- /dev/null +++ b/.brightsec/tests/post-users-1-posts.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 /users/1/posts', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'sqli', 'xss', 'bopla', 'business_constraint_bypass'], + attackParamLocations: [AttackParamLocation.BODY], + starMetadata: { + code_source: 'NeuraLegion/ruby-example-app:master', + databases: ['PostgreSQL'], + user_roles: [] + }, + poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.POST, + url: `${baseUrl}/users/1/posts`, + body: { + title: 'Sample Post Title', + content: 'This is a sample post content.', + public: true + }, + headers: { 'Content-Type': 'application/json' }, + auth: process.env.BRIGHT_AUTH_ID + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/post-users-json.test.ts b/.brightsec/tests/post-users-json.test.ts new file mode 100644 index 0000000..a9a296d --- /dev/null +++ b/.brightsec/tests/post-users-json.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 /users.json', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'bopla', 'sqli', 'xss', 'secret_tokens'], + attackParamLocations: [AttackParamLocation.BODY], + starMetadata: { + code_source: 'NeuraLegion/ruby-example-app:master', + databases: ['PostgreSQL'], + user_roles: [] + }, + poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.POST, + url: `${baseUrl}/users.json`, + body: { + user: { + email: 'example@example.com', + password: 'password123', + password_digest: '$2a$12$KIXQ1Y1rZPO1uY1rZPO1uO', + admin: false + } + }, + headers: { 'Content-Type': 'application/json' }, + auth: process.env.BRIGHT_AUTH_ID + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/post-users.test.ts b/.brightsec/tests/post-users.test.ts new file mode 100644 index 0000000..0d3fc09 --- /dev/null +++ b/.brightsec/tests/post-users.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 /users', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'bopla', 'sqli', 'xss', 'email_injection', 'osi'], + attackParamLocations: [AttackParamLocation.BODY], + starMetadata: { + code_source: 'NeuraLegion/ruby-example-app:master', + databases: ['PostgreSQL'], + user_roles: [] + }, + poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.POST, + url: `${baseUrl}/users`, + body: { + email: 'example@example.com', + password: 'securepassword', + password_digest: '$2a$12$KIXQ1Y1rZ1u1u1u1u1u1uO', + admin: false + }, + headers: { 'Content-Type': 'application/json' }, + auth: process.env.BRIGHT_AUTH_ID + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/put-posts-1-json.test.ts b/.brightsec/tests/put-posts-1-json.test.ts new file mode 100644 index 0000000..73b2d5a --- /dev/null +++ b/.brightsec/tests/put-posts-1-json.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 /posts/1.json', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'bopla', 'sqli', 'xss'], + attackParamLocations: [AttackParamLocation.BODY], + starMetadata: { + code_source: 'NeuraLegion/ruby-example-app:master', + databases: ['PostgreSQL'], + user_roles: [] + }, + poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.PUT, + url: `${baseUrl}/posts/1.json`, + body: { + title: 'Updated Post Title', + content: 'Updated content of the post.', + public: true + }, + headers: { 'Content-Type': 'application/json' }, + auth: process.env.BRIGHT_AUTH_ID + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/put-posts-1.test.ts b/.brightsec/tests/put-posts-1.test.ts new file mode 100644 index 0000000..0615964 --- /dev/null +++ b/.brightsec/tests/put-posts-1.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('PUT /posts/1', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['bopla', 'csrf', 'sqli', 'xss'], + attackParamLocations: [AttackParamLocation.BODY], + starMetadata: { + code_source: 'NeuraLegion/ruby-example-app:master', + databases: ['PostgreSQL'], + user_roles: [] + }, + poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.PUT, + url: `${baseUrl}/posts/1`, + body: { + post: { + title: 'Updated Title', + content: 'Updated content of the post.', + public: true + } + }, + headers: { 'Content-Type': 'application/json' }, + auth: process.env.BRIGHT_AUTH_ID + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/put-users-1-json.test.ts b/.brightsec/tests/put-users-1-json.test.ts new file mode 100644 index 0000000..9e53611 --- /dev/null +++ b/.brightsec/tests/put-users-1-json.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('PUT /users/1.json', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['bopla', 'csrf', 'sqli', 'xss'], + attackParamLocations: [AttackParamLocation.BODY], + starMetadata: { + code_source: 'NeuraLegion/ruby-example-app:master', + databases: ['PostgreSQL'], + user_roles: [] + }, + poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.PUT, + url: `${baseUrl}/users/1.json`, + body: { + user: { + email: 'example@example.com', + password: 'securepassword', + password_digest: '$2a$12$KIXQ1Y1rZ1u1u1u1u1u1uO', + admin: false + } + }, + headers: { 'Content-Type': 'application/json' }, + auth: process.env.BRIGHT_AUTH_ID + }); +}); \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/bright.yml similarity index 58% rename from .github/workflows/ci.yml rename to .github/workflows/bright.yml index 4e2a120..f2c2720 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/bright.yml @@ -1,10 +1,14 @@ -name: ci +name: Bright on: - push: - branches: - - main pull_request: + branches: + - '**' + +permissions: + checks: write + contents: read + id-token: write jobs: test: @@ -80,45 +84,48 @@ jobs: - name: Install gems run: bundle install - - name: Wait for postgres - run: | - for i in $(seq 1 30); do - pg_isready -h "$PGHOST" -p "$PGPORT" -d "$PGDATABASE" && break - sleep 2 - done - bundle exec ruby -e "require 'pg'; PG.connect(host: ENV['PGHOST'], port: ENV['PGPORT'].to_i, dbname: ENV['PGDATABASE'], user: ENV['PGUSER'], password: ENV['PGPASSWORD']);" - - name: Setup database run: bundle exec rake db:create db:migrate db:seed - - name: Start server + - name: Start application + env: + DATABASE_URL: postgres://postgres:postgres@postgres:5432/blog_development + PGDATABASE: blog_development + PGHOST: postgres + PGPASSWORD: postgres + PGPORT: 5432 + PGUSER: postgres run: | bundle exec rails server -b 0.0.0.0 -p 3000 >rails.log 2>&1 & - - name: Wait for server readiness + - name: Probe application readiness run: | - READY=0 - for i in $(seq 1 30); do - echo "Attempt ${i}/30: checking http://localhost:3000" - if curl -sSfL http://localhost:3000 >/dev/null; then - echo "Server responded successfully on attempt ${i}." - READY=1 - break - fi - echo "Server still starting up, waiting 2s before retry." - sleep 2 - done - if [ "$READY" -ne 1 ]; then - echo "Server failed to start" - tail -n 200 rails.log || true - exit 1 - fi - echo "Server is ready; last 200 lines of rails.log:" - tail -n 200 rails.log || true - - - name: Check homepage + i=1; while [ "$i" -le 30 ]; do curl -sS -o /dev/null http://127.0.0.1:3000 && exit 0; sleep 5; i=$((i + 1)); done; exit 1 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 22.x + + - name: Install SecTesterJS dependencies + run: | + npm i --save=false --prefix .brightsec @sectester/core@0.49.0 @sectester/repeater@0.49.0 @sectester/scan@0.49.0 @sectester/runner@0.49.0 @sectester/reporter@0.49.0 + + - name: Authenticate with Bright + uses: ./.github/workflows/composite/configure-bright-credentials + with: + BRIGHT_HOSTNAME: development.playground.brightsec.com + BRIGHT_PROJECT_ID: 5naKKxNc3e4Akp1GuEdmiK + BRIGHT_TOKEN: ${{ secrets.BRIGHT_TOKEN }} + + - name: Run security tests + env: + BRIGHT_HOSTNAME: development.playground.brightsec.com + BRIGHT_PROJECT_ID: 5naKKxNc3e4Akp1GuEdmiK + BRIGHT_AUTH_ID: m8XBzLrw8pWSjHQDhKQgCr + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + BRIGHT_TOKEN: ${{ env.BRIGHT_TOKEN }} + BRIGHT_TARGET_URL: http://127.0.0.1:3000 + SECTESTER_SCAN_POOL_SIZE: ${{ vars.SECTESTER_SCAN_POOL_SIZE }} run: | - if ! curl -sSfL http://localhost:3000 | grep -F "Home"; then - echo "Homepage check failed" - exit 1 - fi + node --experimental-transform-types --experimental-strip-types --experimental-detect-module --disable-warning=MODULE_TYPELESS_PACKAGE_JSON --disable-warning=ExperimentalWarning --test-force-exit --test-concurrency=4 --test .brightsec/tests/*.test.ts \ No newline at end of file diff --git a/.github/workflows/composite/configure-bright-credentials/action.yaml b/.github/workflows/composite/configure-bright-credentials/action.yaml new file mode 100644 index 0000000..8498384 --- /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