BROKEN_AUTHENTICATION

TypeScript
import {
  GenTestEndpoint,
  TestBuilder,
  TestStepBuilder,
  AssertionType,
} from "@metlo/testing"

export default {
  name: "BROKEN_AUTHENTICATION",
  version: 1,
  builder: (endpoint: GenTestEndpoint) => {
    if (!endpoint.authConfig) {
      throw new Error(`No auth config defined for host: "${endpoint.host}"...`)
    }

    return new TestBuilder()
      .setMeta({
        name: `${endpoint.path} Broken Authentication`,
        severity: "HIGH",
        tags: ["BROKEN_AUTHENTICATION"],
      })
      .addTestStep(
        TestStepBuilder.sampleRequest(endpoint).assert({
          type: AssertionType.JS,
          value: "resp.status < 300",
        }),
      )
      .addTestStep(
        TestStepBuilder.sampleRequestWithoutAuth(endpoint).assert({
          type: AssertionType.EQ,
          key: "resp.status",
          value: [401, 403],
        }),
      )
  },
}

BOLA

TypeScript
import {
  GenTestEndpoint,
  TestBuilder,
  TestStepBuilder,
  AssertionType,
} from "@metlo/testing"

export default {
  name: "BOLA",
  version: 1,
  builder: (endpoint: GenTestEndpoint) => {
    if (!endpoint.authConfig) {
      throw new Error(`No auth config defined for host: "${endpoint.host}"...`)
    }

    return new TestBuilder()
      .setMeta({
        name: `${endpoint.path} BOLA`,
        severity: "HIGH",
        tags: ["BOLA"],
      })
      .addTestStep(
        TestStepBuilder.sampleRequest(endpoint, "USER_A").assert({
          type: AssertionType.JS,
          value: "resp.status < 300",
        }),
      )
      .addTestStep(
        TestStepBuilder.sampleRequestWithoutAuth(endpoint, "USER_A")
          .addAuth(endpoint, "USER_B")
          .assert({
            type: AssertionType.EQ,
            key: "resp.status",
            value: [401, 403],
          }),
      )
      .addTestStep(
        TestStepBuilder.sampleRequestWithoutAuth(endpoint, "USER_B")
          .addAuth(endpoint, "USER_A")
          .assert({
            type: AssertionType.EQ,
            key: "resp.status",
            value: [401, 403],
          }),
      )
  },
}

BOLA_ADMIN

TypeScript
import {
  GenTestEndpoint,
  TestBuilder,
  TestStepBuilder,
  AssertionType,
} from "@metlo/testing";

export default {
  name: "BOLA_ADMIN",
  version: 1,
  builder: (endpoint: GenTestEndpoint) => {
    if (!endpoint.authConfig) {
      throw new Error(`No auth config defined for host: "${endpoint.host}"...`);
    }

    return new TestBuilder()
      .setMeta({
        name: `${endpoint.path} BOLA_ADMIN`,
        severity: "HIGH",
        tags: ["BOLA", "ADMIN"],
      })
      .addTestStep(
        TestStepBuilder.sampleRequest(endpoint, "ADMIN_USER").assert({
          type: AssertionType.enum.JS,
          value: "resp.status < 300",
        })
      )
      .addTestStep(
        TestStepBuilder.sampleRequestWithoutAuth(endpoint, "ADMIN_USER")
          .addAuth(endpoint, "NON_ADMIN_USER")
          .assert({
            type: AssertionType.enum.EQ,
            key: "resp.status",
            value: [401, 403, 404],
          })
      );
  },
};

BOLA_MULTI_TENANT

TypeScript
import {
  GenTestEndpoint,
  TestBuilder,
  TestStepBuilder,
  AssertionType,
} from "@metlo/testing";

export default {
  name: "BOLA_MULTI_TENANT",
  version: 1,
  builder: (endpoint: GenTestEndpoint) => {
    if (!endpoint.authConfig) {
      throw new Error(`No auth config defined for host: "${endpoint.host}"...`);
    }

    return new TestBuilder()
      .setMeta({
        name: `${endpoint.path} BOLA_MULTI_TENANT`,
        severity: "HIGH",
        tags: ["BOLA", "MULTI-TENANT"],
      })
      .addTestStep(
        TestStepBuilder.sampleRequest(endpoint, "TENANT_A").assert({
          type: AssertionType.enum.JS,
          value: "resp.status < 300",
        })
      )
      .addTestStep(
        TestStepBuilder.sampleRequestWithoutAuth(endpoint, "TENANT_A")
          .addAuth(endpoint, "TENANT_B")
          .assert({
            type: AssertionType.enum.EQ,
            key: "resp.status",
            value: [404],
          })
      )
      .addTestStep(
        TestStepBuilder.sampleRequestWithoutAuth(endpoint, "TENANT_B")
          .addAuth(endpoint, "TENANT_A")
          .assert({
            type: AssertionType.enum.EQ,
            key: "resp.status",
            value: [404],
          })
      );
  },
};

HSTS

TypeScript
import {
  GenTestEndpoint,
  TestBuilder,
  TestStepBuilder,
  AssertionType,
} from "@metlo/testing";

export default {
  name: "HSTS",
  version: 1,
  builder: (endpoint: GenTestEndpoint) => {
    return new TestBuilder()
      .setMeta({
        name: `${endpoint.path} Has HSTS Headers`,
        severity: "MEDIUM",
        tags: ["HSTS"],
      })
      .addTestStep(
        TestStepBuilder.sampleRequest(endpoint).assert({
          type: AssertionType.JS,
          value: "resp.headers['strict-transport-security']",
        })
      );
  },
};

SQLI_TIME_BASED

TypeScript
import { GenTestEndpoint, TestBuilder, TestStepBuilder } from "@metlo/testing";

export default {
  name: "SQLI_TIME_BASED",
  version: 1,
  builder: (endpoint: GenTestEndpoint) =>
    new TestBuilder()
      .setMeta({
        name: `${endpoint.path} SQLI TIME BASED`,
        severity: "HIGH",
        tags: ["SQLI_TIME_BASED"],
      })
      .setOptions({
        stopOnFailure: true,
      })
      .addTestStep(
        TestStepBuilder.sampleRequest(endpoint)
          .addPayloads({
            key: "SQLI_PAYLOAD",
            value: "SQLI_TIME",
          })
          .modifyRequest((req) => {
            if (req.query && req.query.length > 0) {
              req.query[0].value = "{{SQLI_PAYLOAD}}";
              return req;
            }
            if (req.form && req.form.length > 0) {
              req.form[0].value = "{{SQLI_PAYLOAD}}";
              return req;
            }
            if (
              req.data &&
              req.headers?.find((e) => e.name == "Content-Type")?.value ==
                "application/json"
            ) {
              const parsed = JSON.parse(req.data);
              const keys = Object.keys(parsed);
              if (keys.length > 0) {
                parsed[keys[0]] = "{{SQLI_PAYLOAD}}";
              }
              req.data = JSON.stringify(parsed, null, 4);
              return req;
            }
            return req;
          })
          .assert("resp.duration < 1000")
      ),
};

CSP

TypeScript
import {
  GenTestEndpoint,
  TestBuilder,
  TestStepBuilder,
  AssertionType,
} from "@metlo/testing";

export default {
  name: "CSP",
  version: 1,
  builder: (endpoint: GenTestEndpoint) => {
    return new TestBuilder()
      .setMeta({
        name: `${endpoint.path} Has CSP Headers`,
        severity: "LOW",
        tags: ["CSP"],
      })
      .addTestStep(
        TestStepBuilder.sampleRequest(endpoint).assert({
          type: AssertionType.JS,
          value: "resp.headers['content-security-policy']",
        })
      );
  },
};

GENERIC

TypeScript
import {
  GenTestEndpoint,
  TestBuilder,
  TestStepBuilder,
  AssertionType,
} from "@metlo/testing";

export default {
  name: "GENERIC",
  version: 1,
  builder: (endpoint: GenTestEndpoint) =>
    new TestBuilder()
      .setMeta({
        name: `${endpoint.path} Test`,
        severity: "LOW",
        tags: ["GENERIC"],
      })
      .addTestStep(
        TestStepBuilder.sampleRequest(endpoint).assert({
          type: AssertionType.JS,
          value: "resp.status < 300",
        })
      ),
};