Skip to main content

api-gate-keeper

PyPI Python Versions License: MIT

Python-based API test harness for web application security and reliability checks.

Contents

About

apptest is a CLI that discovers a web app's API surface from its live OpenAPI schema and runs a broad set of security and reliability checks against it — authentication robustness, injection, authorization/IDOR, JWT misuse, mass assignment, SSRF, rate limiting, and more — with safe-by-default execution and CI-friendly reporting (JSON, Markdown, JUnit, SARIF).

It's built for teams that want a repeatable, automatable security signal in CI/CD without standing up a full scanning platform.

What It Does

  • Discovers API endpoints automatically from OpenAPI specs (or manually seeded paths)
  • Supports multiple auth strategies: auto, bearer/API key, basic, username/password login, or none
  • Runs 20+ security test categories (auth, authz/BOLA, JWT, SSRF, mass assignment, schema conformance, workflow chains, soak/reliability profiling, and more)
  • Classifies every check as pass, fail, skipped, or error — with conservative defaults to keep CI signal trustworthy
  • Emits JSON, Markdown (summary/detail/failures), JUnit XML, and SARIF reports for CI gating and dashboards
  • Ships quick / standard / strict profiles so you can start fast and dial up coverage over time

Quick Start

First-time run should only require three choices:

  • target URL (--base-url)
  • auth type (API key, username/password, or no auth)
  • profile (quick, standard, or strict)

60-Second Path

Use this if you just want a first successful run with minimal setup.

pip install api-gate-keeper
apptest --base-url https://your-target.example --api-key <your-api-key> --profile quick

api-gate-keeper is published on PyPI, so a virtualenv is optional (recommended, but not required) for a quick trial run.

Demo

$ apptest --base-url https://api.example.com --api-key $API_KEY --profile standard

Web App API Security Runner v0.1.0
Profile: standard (categories: auth_robustness, authz, baseline, bola_matrix,
contract_conformance, error_leakage_and_debug_surface, file_upload_security,
jwt_security, mass_assignment, owasp, pen_test, privilege_escalation,
rate_limit_and_resource_abuse, schema_contract_and_validation, security_misc,
soak_profile, sql_injection, ssrf_and_redirects, token_security,
workflow_chains)
Target: https://api.example.com
Unsafe execution disabled (POST/PUT/PATCH/DELETE will be skipped)

Run Summary
Passed: 664
Failed: 27
Skipped: 462
Errors: 0
JSON report:     reports/api.example.com-<timestamp>-api-security-report.json
Summary report:  reports/api.example.com-<timestamp>-api-security-summary.md
Detail report:   reports/api.example.com-<timestamp>-api-security-detail.md
Failures report:  reports/api.example.com-<timestamp>-api-security-failures.md

The failures report leads with a prioritized Remediation Plan table (High/Medium/Low, deduplicated by fix) before the per-test evidence — see Test Categories for what each finding category means and why it matters.

Installing From Source

If you're developing on the tool itself, or want the latest unreleased changes:

python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
pip install -e .

Recommended first command (safe defaults):

apptest --base-url https://your-target.example --api-key <your-api-key> --profile quick

If the target does not expose an OpenAPI spec, you can seed known endpoints manually:

apptest --base-url https://your-target.example --api-key <your-api-key> \
	--seed-endpoint GET:/api/v1/resources.json \
	--seed-endpoint GET:/api/v1/accounts.json \
	--profile quick

Run multiple targets in one command (parallel):

apptest --targets https://service-a.example,https://service-b.example --api-key <your-api-key> --profile quick

Which Profile Should I Pick?

Profile Use this when Typical first use
quick Fast feedback and first-time validation Local smoke run
standard Broader routine coverage without aggressive behavior Daily or pre-merge checks
strict Deepest and most assertive coverage Security hardening and release gates

Auth alternatives:

# username/password
apptest --base-url https://your-target.example --username user@example.com --password secret --profile quick

# public endpoints only
apptest --base-url https://your-target.example --profile quick --config apptest.yaml

If you use the no-auth flow, set this in apptest.yaml:

auth:
	type: none

Minimal starter apptest.yaml (onboarding-focused):

base_url: https://your-target.example
auth:
	type: bearer
	header: "Authorization: Bearer ${TARGET_TOKEN}"
profile: quick

Common First-Run Issues

  • 401/403 responses on most checks: verify API key/token, or switch to username/password auth.
  • Connection or DNS failures: confirm --base-url is reachable from your environment.
  • TLS/certificate errors in non-production environments: retry with --insecure only for test environments.
  • Very few tests executed: ensure auth is valid and avoid auth.type: none unless testing public endpoints.

Advanced Usage

Authentication

Supported auth modes:

Auto (default):

  • Uses --api-key if provided.
  • Otherwise attempts login with --username/--password.

Bearer / API key header:

apptest --base-url https://your-target.example --api-key <your-api-key>

Username + password login:

apptest --base-url https://your-target.example --username user@example.com --password secret

HTTP basic auth (via config):

auth:
	type: basic
	username: ${APP_USERNAME}
	password: ${APP_PASSWORD}

No auth (public API checks only):

auth:
	type: none

Browser-copied session headers / cookies:

apptest \
	--base-url https://your-target.example \
	--request-header 'X-Requested-With: XMLHttpRequest' \
	--cookie-header 'sessionid=abc123; other_cookie=value' \
	--profile quick

Environment variable fallback is supported (precedence: CLI args > env vars > built-in defaults):

  • APPTEST_BASE_URL
  • APPTEST_API_KEY
  • APPTEST_USERNAME
  • APPTEST_PASSWORD
  • APPTEST_AUTH_TYPE
  • APPTEST_AUTH_HEADER
  • APPTEST_AUTH_USERNAME
  • APPTEST_AUTH_PASSWORD
  • APPTEST_CATEGORIES
  • APPTEST_SOAK_SAMPLES
  • APPTEST_SOAK_MAX_5XX_RATE
  • APPTEST_SOAK_MAX_EXCEPTION_RATE
  • APPTEST_SOAK_MAX_P95_MS

Example using env vars only:

APPTEST_BASE_URL=https://your-target.example \
APPTEST_USERNAME=your-user@example.com \
APPTEST_PASSWORD=your-password \
apptest

Config File (apptest.yaml)

If apptest.yaml exists in the current directory, it is auto-loaded. You can also pass a custom path with --config.

Precedence is:

  • CLI args
  • Environment variables
  • apptest.yaml
  • Built-in defaults

Example apptest.yaml:

base_url: https://your-target.example
auth:
	type: bearer
	header: "Authorization: Bearer ${TARGET_TOKEN}"
profile: quick
timeout: 20
output_dir: reports
include_unsafe: false
unsafe_categories: all
categories: all
soak_samples: 12
soak_max_5xx_rate: 0.15
soak_max_exception_rate: 0.05
soak_max_p95_ms: 2500

Auth modes for auth.type: auto, bearer, api_key, basic, none.

For bearer and api_key, set auth.header (for example Authorization: Bearer <token> or x-api-key: <key>).

For browser-driven apps that require session cookies or extra request headers, you can also set:

auth:
	type: none
	cookie_header: ${TARGET_COOKIE_HEADER}
	extra_headers:
		X-Requested-With: XMLHttpRequest
		Accept: application/json

CLI --request-header values override auth.extra_headers entries with the same header name.

Run with auto-loaded config:

apptest

Run with explicit config path:

apptest --config ./apptest.yaml

Initialize a starter config file:

apptest init

Initialize at custom path:

apptest init --path ./config/apptest.yaml

Overwrite existing config:

apptest init --force

Default Runtime Parameters

  • base URL: https://your-target.example
  • auth mode: auto
  • username: your-user@example.com (used by auto login fallback)
  • password: your-password (used by auto login fallback)

Example Commands

Run with defaults (safe mode — skips mutating methods):

apptest --base-url https://your-target.example

Run with profile presets:

# reduced category set, safe mode
apptest --profile quick --base-url https://your-target.example

# all categories, safe mode
apptest --profile standard --base-url https://your-target.example

# all categories, unsafe enabled by default
apptest --profile strict --base-url https://your-target.example

Run specific categories only:

apptest --base-url https://your-target.example --categories auth_robustness
apptest --base-url https://your-target.example --categories token_security
apptest --base-url https://your-target.example --categories privilege_escalation
apptest --base-url https://your-target.example --categories file_upload_security --include-unsafe --unsafe-categories file_upload_security
apptest --base-url https://your-target.example --categories ssrf_and_redirects --include-unsafe --unsafe-categories ssrf_and_redirects
apptest --base-url https://your-target.example --categories rate_limit_and_resource_abuse
apptest --base-url https://your-target.example --categories error_leakage_and_debug_surface
apptest --base-url https://your-target.example --categories mass_assignment --include-unsafe --unsafe-categories mass_assignment
apptest --base-url https://your-target.example --categories schema_contract_and_validation --include-unsafe --unsafe-categories schema_contract_and_validation
apptest --base-url https://your-target.example --categories jwt_security
apptest --base-url https://your-target.example --categories contract_conformance
apptest --base-url https://your-target.example --categories bola_matrix
apptest --base-url https://your-target.example --categories workflow_chains --include-unsafe --unsafe-categories workflow_chains
apptest --base-url https://your-target.example --categories soak_profile
apptest --base-url https://your-target.example --categories baseline,owasp,authz

Tune soak profile thresholds/samples (CLI):

apptest \
	--base-url https://your-target.example \
	--categories soak_profile \
	--soak-samples 8 \
	--soak-max-5xx-rate 0.25 \
	--soak-max-exception-rate 0.10 \
	--soak-max-p95-ms 3500

Soak tuning precedence is:

  • CLI flags
  • environment variables
  • config file keys
  • category defaults

Tune soak profile thresholds via environment variables:

APPTEST_SOAK_SAMPLES=8 \
APPTEST_SOAK_MAX_5XX_RATE=0.25 \
APPTEST_SOAK_MAX_EXCEPTION_RATE=0.10 \
APPTEST_SOAK_MAX_P95_MS=3500 \
apptest --base-url https://your-target.example --categories soak_profile

Run with API key instead of username/password:

apptest --base-url https://your-target.example --api-key <your-api-key>

Run with explicit auth header from config/env:

APPTEST_AUTH_TYPE=bearer \
APPTEST_AUTH_HEADER="Authorization: Bearer <token>" \
apptest --base-url https://your-target.example

Run with custom target and creds:

apptest --base-url https://your-target.example --username your-user --password your-pass

Run with unsafe methods enabled for specific categories:

apptest --base-url https://your-target.example --include-unsafe --unsafe-categories baseline

Run with all categories fully unlocked:

apptest --base-url https://your-target.example --include-unsafe --unsafe-categories all

Disable TLS verification (only for test environments):

apptest --base-url https://your-target.example --insecure

Fail CI when findings are present:

apptest --base-url https://your-target.example --fail-on-findings

Fail CI only when thresholds are exceeded:

apptest --base-url https://your-target.example --max-failed 0 --max-errors 0

Generate JUnit XML output for CI test dashboards:

apptest --base-url https://your-target.example --junit-out reports/apptest-junit.xml

Generate SARIF output for GitHub code scanning:

apptest --base-url https://your-target.example --sarif-out reports/apptest.sarif.json

Write reports to explicit paths:

apptest \
	--base-url https://your-target.example \
	--categories auth_robustness \
	--json-out reports/auth_robustness.json \
	--md-summary-out reports/auth_robustness.summary.md \
	--md-detail-out reports/auth_robustness.detail.md \
	--sarif-out reports/auth_robustness.sarif.json

Upload SARIF to GitHub Code Scanning:

- name: Run apptest with SARIF
	run: |
		apptest \
			--base-url "$APPTEST_BASE_URL" \
			--api-key "$APPTEST_API_KEY" \
			--sarif-out reports/apptest.sarif.json

- name: Upload SARIF to GitHub Code Scanning
	if: always()
	uses: github/codeql-action/upload-sarif@v3
	with:
		sarif_file: reports/apptest.sarif.json

Output

Reports are written to reports/ — four files per run, prefixed with the target hostname:

  • <target-host>-<timestamp>-api-security-report.json — raw results
  • <target-host>-<timestamp>-api-security-summary.md — per-category totals
  • <target-host>-<timestamp>-api-security-detail.md — per-test detail table with PASS/FAIL/SKIP
  • <target-host>-<timestamp>-api-security-failures.md — failures/errors only, with a prioritized Remediation Plan summary followed by the detail table

Categories Implemented

  • baseline API execution
  • penetration payload probes
  • SQL injection probes
  • OWASP-oriented checks
  • additional security checks (CORS, basic rate probe)
  • authorization and IDOR checks
  • authentication robustness checks (invalid credential rejection, failed-login throttle signal)
  • token security checks (malformed token, tampered token, missing Bearer prefix; skipped when bearer token auth is not in use)
  • privilege escalation checks (likely admin endpoint access with current token)
  • file upload security checks (multipart endpoint discovery, unsafe filename traversal and absolute path probes)
  • SSRF and redirect checks (ServiceNow instance URL rejection for internal targets, redirect-style parameter discovery)
  • rate-limit and resource-abuse checks (burst probes and oversized pagination or time-window requests)
  • error leakage and debug surface checks (debug route exposure, unauthenticated debug access, stack-trace/internal error leakage markers)
  • mass assignment checks (sensitive writable fields on authenticated JSON mutation endpoints)
  • schema contract and validation checks (missing required fields, wrong types, unknown fields)
  • JWT-specific token misuse checks (alg:none, stripped signatures, future nbf, kid abuse patterns)
  • response contract conformance checks (status-code drift, undocumented response fields, missing required response fields)
  • BOLA matrix checks with harvested live IDs (neighbor ID probes and cross-service ID references)
  • workflow lifecycle chain checks (create-read-update-delete flow health and auth enforcement)
  • soak profile checks on safe endpoints (repeated request stability and latency thresholds; auth-required endpoints with no successful responses are classified as skipped to reduce false positives)

GitHub Actions Integration

Sample workflow (.github/workflows/apptest-scan.yml):

name: Web App Security Scan (apptest)

on:
	pull_request:
		branches: [ main, develop ]
	push:
		branches: [ main, develop ]
	workflow_dispatch:
		inputs:
			base_url:
				description: "Target web app base URL"
				required: false
				default: "https://your-target.example"

jobs:
	apptest-scan:
		runs-on: ubuntu-latest
		timeout-minutes: 30

		env:
			DEFAULT_BASE_URL: https://your-target.example

		steps:
			- name: Checkout
				uses: actions/checkout@v4

			- name: Set up Python
				uses: actions/setup-python@v5
				with:
					python-version: "3.11"

			- name: Install apptest
				run: |
					python -m pip install --upgrade pip
					pip install -e .

			- name: Resolve target URL
				id: target
				shell: bash
				run: |
					if [ -n "${{ github.event.inputs.base_url }}" ]; then
						echo "base_url=${{ github.event.inputs.base_url }}" >> "$GITHUB_OUTPUT"
					elif [ -n "${{ vars.APPTEST_BASE_URL }}" ]; then
						echo "base_url=${{ vars.APPTEST_BASE_URL }}" >> "$GITHUB_OUTPUT"
					else
						echo "base_url=${DEFAULT_BASE_URL}" >> "$GITHUB_OUTPUT"
					fi

			- name: Run apptest (API key preferred)
				shell: bash
				env:
					APPTEST_API_KEY: ${{ secrets.APPTEST_API_KEY }}
					APPTEST_USERNAME: ${{ secrets.APPTEST_USERNAME }}
					APPTEST_PASSWORD: ${{ secrets.APPTEST_PASSWORD }}
				run: |
					set -euo pipefail
					BASE_URL="${{ steps.target.outputs.base_url }}"

					if [ -n "${APPTEST_API_KEY:-}" ]; then
						apptest \
							--base-url "$BASE_URL" \
							--api-key "$APPTEST_API_KEY" \
							--include-unsafe \
							--unsafe-categories baseline
					else
						apptest \
							--base-url "$BASE_URL" \
							--username "${APPTEST_USERNAME}" \
							--password "${APPTEST_PASSWORD}" \
							--include-unsafe \
							--unsafe-categories baseline
					fi

			- name: Enforce gate from JSON report
				shell: bash
				run: |
					set -euo pipefail
					python - <<'PY'
					import json, glob, sys
					report = sorted(glob.glob("reports/*-api-security-report.json"))[-1]
					data = json.load(open(report))
					failed = data.get("summary", {}).get("failed", 0)
					errors = data.get("summary", {}).get("errors", 0)
					print(f"Gate check: failed={failed}, errors={errors}")
					if failed > 0 or errors > 0:
							sys.exit(1)
					PY

			- name: Upload reports
				if: always()
				uses: actions/upload-artifact@v4
				with:
					name: apptest-reports
					path: reports/

Required repository configuration:

  • Secret APPTEST_API_KEY (recommended), or both APPTEST_USERNAME and APPTEST_PASSWORD
  • Optional repository variable APPTEST_BASE_URL

Simple Workflow (URL + Username + Password Only)

Use this minimal option if you want the easiest integration path.

name: apptest-simple

on:
	workflow_dispatch:
	pull_request:
		branches: [ main ]

jobs:
	apptest:
		runs-on: ubuntu-latest
		steps:
			- uses: actions/checkout@v4

			- uses: actions/setup-python@v5
				with:
					python-version: "3.11"

			- name: Install
				run: |
					python -m pip install --upgrade pip
					pip install -e .

			- name: Run apptest
				env:
					APPTEST_BASE_URL: ${{ secrets.APPTEST_BASE_URL }}
					APPTEST_USERNAME: ${{ secrets.APPTEST_USERNAME }}
					APPTEST_PASSWORD: ${{ secrets.APPTEST_PASSWORD }}
				run: |
					apptest \
						--base-url "$APPTEST_BASE_URL" \
						--username "$APPTEST_USERNAME" \
						--password "$APPTEST_PASSWORD"

			- name: Upload reports
				if: always()
				uses: actions/upload-artifact@v4
				with:
					name: apptest-reports
					path: reports/

Required secrets for the simple workflow:

  • APPTEST_BASE_URL
  • APPTEST_USERNAME
  • APPTEST_PASSWORD

Test Categories

Every test category in API Gate Keeper: what it checks, how it works, and why it matters. Each section ends with a Test Matrix table listing the exact runtime test_name identifiers, trigger/scope, expected secure outcome, and implementation notes.

1. Baseline

Category name: baseline

What it is

A smoke-test pass over every discovered API endpoint using the configured authentication credentials, with no payload injection or modification.

What it does

  • Iterates every endpoint discovered from the OpenAPI schemas across all configured services.
  • Fires each endpoint exactly as documented — correct method, a synthetic-but-valid sample body where needed, and live auth headers.
  • Records the raw status code, response time, and any error conditions.

Why we need it

Baseline validates that the service is reachable, auth is working, and the test harness can communicate correctly before any attack-surface probes run. It also surfaces endpoints that return 5xx errors under normal conditions — a sign of pre-existing instability that should be investigated regardless of security intent. Without a baseline pass, failures in other categories are harder to interpret.

Test Matrix

Test Name Trigger/Scope Expected Secure Outcome Notes
baseline_request All discovered endpoints No server-side failure under normal request construction Unsafe methods are skipped unless unsafe execution is enabled for the category

2. OWASP Core Controls

Category name: owasp

What it is

Checks for two fundamental OWASP API Security Top 10 controls: missing HTTP security headers and unauthenticated access to authenticated endpoints.

What it does

Security headers check (security_headers_check):

  • Selects up to 6 representative GET endpoints (preferring public paths like /health, /openapi, /docs).
  • Fires a GET and inspects the response headers for the following required headers:
    • X-Frame-Options — prevents clickjacking.
    • X-Content-Type-Options — prevents MIME sniffing.
    • Content-Security-Policy — restricts resource loading.
    • Strict-Transport-Security — enforces HTTPS.
  • Fails if any of these headers are missing from responses.

Authentication requirement check (auth_required_check):

  • For every endpoint marked as requiring authentication in the OpenAPI spec, fires the request with no Authorization header.
  • Expects a 401 or 403 response. A 2xx response is a failure — the endpoint is openly accessible without credentials.

Why we need it

Missing security headers are low-effort wins for attackers. Absent X-Frame-Options enables UI redressing attacks. Absent Content-Security-Policy expands XSS blast radius. Absent Strict-Transport-Security allows downgrade attacks on HTTPS enforcement. These headers are easily added and have no performance cost; their absence is always a regression.

The auth requirement check catches endpoints that slip past authentication middleware — a top-ranked OWASP API Security vulnerability (API2 — Broken Authentication). Even a single authenticated endpoint accidentally exposed without checks can be a critical finding.

Test Matrix

Test Name Trigger/Scope Expected Secure Outcome Notes
security_headers_check Representative GET endpoints Required security headers are present Missing headers are reported as failures
auth_required_check Endpoints marked requires_auth Unauthenticated requests are denied (401/403) A 2xx without auth is a failure

3. SQL Injection

Category name: sql_injection

What it is

Injects classic SQL injection payloads into every discovered endpoint to detect whether the API reflects or processes raw SQL input without sanitization.

What it does

  • Applies two representative injection strings to every discovered endpoint:
    • ' OR '1'='1 — boolean-based injection that tests if the WHERE clause is bypassable.
    • admin' -- — comment-based injection that tests if a login or filter query can be truncated.
  • Passes each payload as the attack_payload to the shared executor, which injects it into available query parameters and body fields.
  • A 2xx response containing reflected payload content, or unexpected data being returned, is a failure signal.

Why we need it

SQL injection remains one of the most impactful and frequently exploited API vulnerabilities (OWASP A03 — Injection). A single unsanitized input can expose entire database tables, bypass authentication, or enable data destruction. APIs that handle filter parameters, search queries, or ID lookups are particularly at risk. Even when an ORM is used, raw query construction or improper parameterization in edge cases can re-introduce the vulnerability.

Test Matrix

Test Name Trigger/Scope Expected Secure Outcome Notes
sqli_payload:' OR '1'='1 All discovered endpoints with injected payload Payload is rejected or safely handled Parameterized SQLi variant
sqli_payload:admin' -- All discovered endpoints with injected payload Payload is rejected or safely handled Comment-truncation SQLi variant

4. Penetration Test Payloads

Category name: pen_test

What it is

A broader injection sweep covering path traversal, command injection, and cross-site scripting (XSS) payloads across every endpoint.

What it does

Applies three payloads to every discovered endpoint:

Payload Threat
../../../../etc/passwd Path/directory traversal — attempts to read files outside the web root
$(cat /etc/passwd) Command injection — attempts OS command execution via shell substitution
<script>alert('xss')</script> Reflected XSS — tests if user-supplied markup is reflected unescaped

Each payload is injected into query parameters and request bodies via the shared executor's attack_payload mechanism. Responses are checked for reflection or unexpected execution signals.

Why we need it

APIs that accept filenames, paths, or shell-like strings in parameters are vulnerable to path traversal and command injection, which can lead to server compromise. APIs that reflect input into responses (especially in error messages or rich outputs) are vulnerable to XSS, which can enable session hijacking in browser-based clients. This category catches the broadest injection attack classes beyond SQL with minimal probe count.

Test Matrix

Test Name Trigger/Scope Expected Secure Outcome Notes
pentest_payload:../../../../etc/passwd All discovered endpoints with payload injection Traversal payload is rejected or sanitized Path traversal probe
pentest_payload:$(cat /etc/passwd) All discovered endpoints with payload injection Command-like payload is not executed/reflected unsafely Command injection probe
pentest_payload:<script>alert('xss')</script> All discovered endpoints with payload injection Script payload is encoded/rejected Reflected XSS probe

5. Security Miscellaneous

Category name: security_misc

What it is

Targeted checks for two frequently overlooked but critical controls: overly permissive CORS configuration and basic rate-limit health on the most stable endpoint.

What it does

CORS wildcard check (cors_wildcard_check):

  • Sends an OPTIONS preflight request to the login endpoint (/api/data/auth/login) with Origin: https://evil.example.
  • Fails if the server responds with Access-Control-Allow-Origin: * — indicating any origin can make cross-origin requests, including malicious ones.

Basic rate probe (basic_rate_probe):

  • Fires 5 rapid GET requests to the first discovered /health endpoint.
  • Passes if all return non-5xx. A 5xx burst result indicates instability in the healthcheck path, which downstream health monitoring relies on.

Why we need it

A wildcard CORS policy on an authentication endpoint is a critical misconfiguration — it allows arbitrary web pages to make authenticated API calls on behalf of any user (CSRF/CORS abuse). This is especially damaging for APIs that use cookie-based or implicit-flow auth. The rate probe provides a confidence check that the service is robustly responsive under even trivial load, which is a prerequisite for trusting other category results.

Test Matrix

Test Name Trigger/Scope Expected Secure Outcome Notes
cors_wildcard_check Login preflight (OPTIONS) No wildcard Access-Control-Allow-Origin on sensitive auth flow * is a failure
basic_rate_probe First discovered health endpoint No 5xx under short rapid sequence Lightweight stability signal

6. Authorization (AuthZ)

Category name: authz

What it is

Verifies two fundamental authorization controls: unauthenticated access blocking and Insecure Direct Object Reference (IDOR) resistance.

What it does

Unauthenticated access check (authz_unauthenticated_access_check):

  • For every authenticated endpoint, fires the request with no Authorization header.
  • Expects 401 or 403. A 2xx is a failure.

IDOR path tamper check (idor_path_tamper_check):

  • For each endpoint whose URL path contains parameters with ID-like names (id, user, account, tenant, org, customer, project), replaces all such parameters with the synthetic value 999999.
  • Fires the request with the current user's valid token.
  • Expects 401, 403, or 404 — the resource doesn't belong to this user or doesn't exist.
  • A 2xx response is a potential IDOR: an authenticated user is accessing a resource that likely belongs to another tenant or user.

Why we need it

IDOR is the top-ranked OWASP API Security vulnerability (API1 — Broken Object Level Authorization). It occurs when an API uses predictable IDs in paths but doesn't verify that the requesting user actually owns the referenced resource. Tenants accessing other tenants' data, users modifying other users' records, or any cross-account data leak all stem from IDOR. This category catches horizontal privilege escalation — one of the highest-impact class of findings in multi-tenant SaaS APIs.

Test Matrix

Test Name Trigger/Scope Expected Secure Outcome Notes
authz_unauthenticated_access_check Endpoints marked requires_auth Unauthenticated access is denied Uses no auth header
idor_path_tamper_check Auth-required ID-like path endpoints Tampered object access is denied/hidden Path params replaced with synthetic ID

7. Authentication Robustness

Category name: auth_robustness

What it is

Validates that the login/authentication endpoint correctly rejects invalid credentials and shows signs of throttling on repeated failures.

What it does

Invalid credentials rejection (invalid_credentials_rejection_check):

  • Locates the login endpoint by path/operation name heuristics (login, signin, auth, token, session).
  • Inspects its JSON body schema to construct a realistic-looking but invalid payload (wrong email format + clearly wrong password).
  • Fires the POST. Expects 400, 401, 403, 422, or 429. A 2xx is a failure — the API must not accept invalid credentials.

Failed login throttle signal (failed_login_throttle_signal_check):

  • Sends 5 invalid login requests in rapid succession.
  • Passes if any 429 response is observed, indicating rate limiting on authentication failures.
  • Marks as skipped if no throttle signal is seen (absence of 429 is informational, not a hard failure, since some implementations use CAPTCHA or delay strategies instead).

Why we need it

An authentication endpoint that accepts invalid credentials is a critical vulnerability. Login throttling is a key defense against credential stuffing and brute-force attacks — without it, attackers can iterate millions of credential combinations until they succeed. OWASP API Security API2 (Broken Authentication) specifically identifies missing brute-force protection as a top risk. This category validates that the most sensitive endpoint in the API enforces minimum authentication hygiene.

Test Matrix

Test Name Trigger/Scope Expected Secure Outcome Notes
invalid_credentials_rejection_check Discovered login-like endpoint Invalid credentials are rejected (non-2xx) Primary auth hardening check
failed_login_throttle_signal_check Repeated invalid login attempts Throttle/lockout signal appears or absence is clearly marked 429 is pass; no signal is informational skip
auth_endpoint_discovery Category startup Login-like endpoint exists for checks Skipped if no suitable endpoint is discovered

8. Token Security

Category name: token_security

What it is

Validates that the API correctly rejects malformed, tampered, and improperly formatted bearer tokens. This category only executes token-manipulation probes when runtime auth provides a bearer token context.

What it does

For up to 20 authenticated GET/HEAD/OPTIONS endpoints:

Test What it sends Expected result
malformed_bearer_token_check Authorization: Bearer not-a-valid-bearer-token 400/401/403
tampered_bearer_token_check The live token with its last character changed 400/401/403
missing_bearer_prefix_check The raw token string with no Bearer prefix 400/401/403
jwt_format_detection N/A — skipped if token is not JWT-shaped Informational

A 2xx for any of the above is a failure.

If bearer token context is unavailable (for example auth.type: basic or auth.type: none), the category emits a skipped result explaining that bearer-token checks are not applicable for the current auth mode.

Why we need it

Token validation is a core part of API security. Implementations that accept tampered or structurally invalid tokens may be skipping signature verification, relying only on token presence rather than validity, or delegating validation inconsistently across services. A tampered token that returns 200 is a critical finding — it means the API is not verifying token integrity. These checks catch implementation bugs in JWT middleware, token parsing shortcuts, and missing validation paths that don't surface in happy-path testing.

Test Matrix

Test Name Trigger/Scope Expected Secure Outcome Notes
malformed_bearer_token_check Safe auth-required endpoints Malformed bearer token is rejected 400/401/403 expected
tampered_bearer_token_check Safe auth-required endpoints Tampered bearer token is rejected Last token char is modified
missing_bearer_prefix_check Safe auth-required endpoints Improper auth header format is rejected Missing Bearer prefix
jwt_format_detection Token-shape check JWT/non-JWT applicability is identified Informational skip when token is not JWT-shaped
token_security_token_presence Category startup Bearer token context exists Skipped in non-bearer auth modes
token_security_target_discovery Category startup Suitable endpoints are available for token probes Skipped if no targets found

9. Privilege Escalation

Category name: privilege_escalation

What it is

Checks whether a non-admin user can access admin-designated API endpoints using their standard token.

What it does

  • Locates authenticated GET/HEAD/OPTIONS endpoints whose path or operation name contains admin-hint keywords: admin, role, permission, rbac, tenant-admin, superuser.
  • Decodes the live JWT payload (without signature verification) and inspects role/permissions claims. If the current token already appears to be admin-privileged, all checks are skipped to avoid false positives.
  • For non-admin tokens: fires each admin-hint endpoint. Expects 401, 403, or 404. A 2xx is a failure — a non-admin user reached an admin resource.

Why we need it

Vertical privilege escalation — a non-admin user gaining access to admin functionality — is a critical class of authorization failure (OWASP API5 — Broken Function Level Authorization). Admin endpoints frequently expose bulk operations, tenant management, user management, configuration changes, or data exports that can be catastrophically abused. This category checks that role-based access control is enforced at the endpoint level, not just in the UI layer.

Test Matrix

Test Name Trigger/Scope Expected Secure Outcome Notes
privileged_endpoint_access_check Admin-hint safe endpoints Non-admin token cannot access privileged routes If current token appears admin, category skips to avoid false positives

10. File Upload Security

Category name: file_upload_security

What it is

Tests that file upload endpoints reject filenames that attempt to write outside the intended directory using path traversal or absolute path techniques.

What it does

For each discovered multipart/form-data upload endpoint (up to 10):

Test Filename used Attack it mimics
upload_path_traversal_filename_check ../../../../tmp/__apptest_upload_traversal__.py Writing outside the upload directory via ../ sequences
upload_absolute_path_filename_check /etc/__apptest_upload_absolute__.py Overwriting system files via absolute path

Both tests first resolve a live application_id from the assets API to ensure the request has a valid context. The file content is a harmless Python print statement. Expects 400/403/404/413/415/422. A 2xx response with the traversal filename accepted is a failure.

Why we need it

Unvalidated file upload paths are a server-side path traversal vector. If a server uses the client-supplied filename to construct a filesystem path and doesn't sanitize it, an attacker can write arbitrary files to any location the process has write access to — including overwriting server configuration, planting web shells, or corrupting system files. File upload endpoints are also often more permissive by design (they expect binary input), making them a common gap in API input validation.

Test Matrix

Test Name Trigger/Scope Expected Secure Outcome Notes
upload_path_traversal_filename_check Authenticated multipart upload endpoints Traversal filename is rejected/sanitized Uses ../../.. filename variant
upload_absolute_path_filename_check Authenticated multipart upload endpoints Absolute-path filename is rejected/sanitized Uses /etc/... filename variant
file_upload_target_discovery Category startup Upload endpoints are discoverable Skipped when no multipart targets exist
file_upload_application_context_discovery Category startup Required application_id context is discoverable Skipped when upload context cannot be resolved

11. Mass Assignment

Category name: mass_assignment

What it is

Tests whether API mutation endpoints silently accept and apply privileged fields that are not documented in their request schema.

What it does

For each authenticated POST/PUT/PATCH endpoint with a JSON body schema (up to 20):

  • Builds a valid sample payload from the declared schema properties.

  • Injects additional fields that are not in the schema but represent privileged intent:

    Injected field Sentinel value
    role __apptest_mass_assignment_role__
    roles ["__apptest_mass_assignment_roles__"]
    is_admin true
    admin true
    tenant_id __apptest_mass_assignment_tenant__
    owner_id __apptest_mass_assignment_owner__
    permissions ["__apptest_mass_assignment_permissions__"]
    status __apptest_mass_assignment_status__
    user_id __apptest_mass_assignment_user__
    organization_id __apptest_mass_assignment_org__
  • If the response is 2xx and any sentinel value is reflected in the response body, it is a fail — the server accepted and likely stored the injected field.

  • If the response is 2xx but no sentinel is reflected, it is skipped — the field may have been silently dropped, which is safer but still informational.

  • If the response is 4xx/422, it is a pass — the API correctly rejected undeclared fields.

Why we need it

Mass assignment (OWASP API3 — Broken Object Property Level Authorization) occurs when an API automatically binds all properties in a request body to the underlying data model without filtering. An attacker can set is_admin: true or role: admin on their own profile, elevate their privileges, or corrupt data ownership. This is especially common in frameworks that auto-bind request bodies to ORM models (Django REST Framework, ActiveRecord, etc.) when allowlisting is not explicitly configured.

Test Matrix

Test Name Trigger/Scope Expected Secure Outcome Notes
mass_assignment_sensitive_field_probe Authenticated JSON mutation endpoints Sensitive undeclared fields are rejected or safely ignored Reflection of sentinel values is a failure signal
mass_assignment_target_discovery Category startup Suitable JSON mutation endpoints are discoverable Skipped when no valid targets exist

12. Schema Contract and Validation

Category name: schema_contract_and_validation

What it is

Validates the strength of server-side input validation by testing how mutation endpoints respond to missing required fields, wrong-type values, and completely undocumented fields.

What it does

For each authenticated POST/PUT/PATCH endpoint with a JSON body schema (up to 20):

Test What is sent Expected
required_field_validation_check Valid payload with the first required field removed 400/422 rejection
wrong_type_validation_check Valid payload with the first typed field replaced by the wrong type (e.g., string "wrong-type" for an integer field) 400/422 rejection
unknown_field_handling_check Valid payload with an extra __apptest_unknown_field__: "__apptest_unknown_value__" injected 400/422 preferred; 2xx with no reflection is skipped; 2xx with reflection is fail

Why we need it

APIs that silently accept missing required fields, wrong types, or completely unknown fields signal weak or absent server-side validation. This creates several risks:

  • Data integrity: Incomplete objects stored without required fields corrupt database state and downstream processing.
  • Type confusion: Wrong types in business logic fields (e.g., passing a string where a count is expected) can cause unexpected behavior, bypasses, or crashes.
  • Information leakage: Unknown fields accepted and reflected in responses reveal that the API is not using a strict allowlist, which means mass assignment defenses are likely also absent.

Robust schema validation is also a prerequisite for reliable API contracts — a poorly validating API is harder to maintain and extend safely.

Test Matrix

Test Name Trigger/Scope Expected Secure Outcome Notes
required_field_validation_check Authenticated JSON mutation endpoints Missing required fields are rejected 400/422 style validation expected
wrong_type_validation_check Authenticated JSON mutation endpoints Wrong-type field values are rejected Type confusion defense check
unknown_field_handling_check Authenticated JSON mutation endpoints Unknown fields are rejected or safely ignored Reflection of unknown field token is a failure signal
schema_validation_target_discovery Category startup Suitable JSON mutation endpoints are discoverable Skipped when no valid targets exist

13. SSRF and Redirects

Category name: ssrf_and_redirects

What it is

Tests whether the API accepts external URLs that point to private network addresses or cloud metadata endpoints — the primary SSRF (Server-Side Request Forgery) attack vectors.

What it does

Private address rejection (ssrf_private_address_rejection_check):

  • Sends PATCH /api/data/integrations/servicenow/instance-url with instance_url: http://127.0.0.1:80/__apptest_ssrf_private__.
  • This simulates an attacker configuring an integration to point back at the server's own loopback interface.
  • Fetches the current instance_url before the probe and restores it after if unsafe methods are enabled.
  • Expects rejection (400/401/403/404/422). A 2xx indicates the server accepted the private address.

Cloud metadata address rejection (ssrf_metadata_address_rejection_check):

  • Same flow, but uses http://169.254.169.254/latest/meta-data/ — the AWS EC2 Instance Metadata Service (IMDS) address.
  • A server that fetches this URL on behalf of a user request can expose cloud credentials, IAM roles, and instance configuration.

Redirect target discovery (redirect_target_discovery):

  • Scans all discovered endpoint parameters and JSON body fields for redirect-style names (redirect, redirect_uri, return_url, return_to, callback_url, next).
  • Reports count for analyst awareness without actively probing open redirect behavior (informational).

Why we need it

SSRF is ranked OWASP API7 and is consistently exploited in cloud environments. Integration management endpoints that accept arbitrary URLs are the most common SSRF entry point in SaaS APIs. If an integration platform fetches the attacker-supplied URL server-side, the attacker can:

  • Reach internal services not exposed to the internet.
  • Access cloud instance metadata to steal IAM credentials.
  • Pivot to other internal APIs and databases.

In a multi-tenant platform, SSRF via integration URL configuration is a high-severity vector because it bypasses both tenant isolation and network perimeter controls.

Test Matrix

Test Name Trigger/Scope Expected Secure Outcome Notes
ssrf_private_address_rejection_check ServiceNow instance URL mutation flow Private/loopback target is rejected Unsafe mutation flow
ssrf_metadata_address_rejection_check ServiceNow instance URL mutation flow Cloud metadata target is rejected Unsafe mutation flow
redirect_target_discovery Endpoint parameter/schema scan Redirect-style targets are inventoried Informational discovery check
ssrf_target_discovery Category startup SSRF-capable mutation target is discoverable Skipped when no supported target exists
ssrf_instance_url_context_discovery Category startup Restorable integration context is discoverable Skipped when safe restore context is unavailable

14. Rate Limit and Resource Abuse

Category name: rate_limit_and_resource_abuse

What it is

Tests whether the API enforces rate limiting under burst conditions and rejects requests that specify absurdly large resource windows.

What it does

Burst rate limit signal (burst_rate_limit_signal_check):

  • Selects up to 6 qualifying authenticated GET endpoints (no path params, path/operation hints match resource-heavy surfaces like scans, reports, audit, applications, heatmap).
  • Sends 12 requests in rapid succession to each target.
  • Passes if any 429 response or Retry-After header appears. Fails if any 5xx occurs (burst causing server errors). Skipped if no throttle signal (informational).

Oversized pagination/window check (oversized_pagination_window_check):

  • Selects up to 6 qualifying GET endpoints that accept pagination or time-range parameters (page_size, limit, offset, days).
  • Sends a single request with extreme values: page_size=1,000,000, limit=1,000,000, offset=1,000,000, days=5000.
  • Expects 400/413/414/422 rejection. A 5xx is a failure (the request caused a server error). A 2xx is skipped (the server may have silently capped the value; deeper investigation needed).

Why we need it

APIs without rate limiting are vulnerable to denial-of-service, credential brute-forcing, and data enumeration attacks (OWASP API4 — Unrestricted Resource Consumption). Even authenticated APIs can be abused by a malicious tenant exhausting shared compute or database resources, degrading service for other users. Oversized pagination parameters are a common vector for memory exhaustion — querying millions of rows in a single request can crash database connections, exhaust heap, and cause service outages. These checks validate infrastructure-level defenses, not just application logic.

Test Matrix

Test Name Trigger/Scope Expected Secure Outcome Notes
burst_rate_limit_signal_check Selected authenticated GET endpoints Throttle signal appears and no instability is induced 429/Retry-After indicates active limiting
oversized_pagination_window_check Endpoints with window/pagination params Abusive ranges are rejected/bounded 5xx under oversized request is a failure
rate_limit_target_discovery Category startup Suitable abuse-probe endpoints are discoverable Skipped when no candidates exist

15. Error Leakage and Debug Surface

Category name: error_leakage_and_debug_surface

What it is

Detects debug routes that should not be publicly exposed and tests whether error responses contain internal system details that aid attackers.

What it does

Debug route exposure check (debug_route_public_exposure_check):

  • Scans all discovered endpoints for the keyword debug in the path or operation ID.
  • If any such endpoint is marked as not requiring authentication, it fails immediately — a public debug route is a critical finding.
  • If all debug routes are auth-protected, reports pass with count.

Debug route unauthenticated access check (debug_route_unauthenticated_access_check):

  • Fires the first authenticated debug-route GET endpoint without an Authorization header.
  • Expects 401/403/404. A 2xx means the auth protection on the debug route is not enforced.

Error response information leak check (error_response_information_leak_check):

  • Sends a probe payload (__apptest_error_probe__'"<script>alert(1)</script>) to up to 24 safe GET/HEAD/OPTIONS endpoints, prioritizing those with more query parameters (higher chance of triggering validation errors).
  • Scans responses for high-confidence leak markers (immediate fail):
    • Python tracebacks (Traceback (most recent call last))
    • SQLAlchemy/psycopg2/SQLite3 exceptions
    • Java stack traces (java.lang., NullPointerException)
    • Filesystem paths (file "/...)
    • OS-level permission errors
  • Scans for medium-confidence markers (skipped — informational):
    • Generic exception, error while processing, internal server error, debug

Why we need it

Error leakage and exposed debug surfaces are classified under OWASP API8 — Security Misconfiguration and OWASP API9 — Improper Inventory Management.

Debug routes left enabled in production have provided root-level access, configuration dumps, memory inspection, and live query execution capabilities to attackers. Stack traces and exception messages in error responses reveal:

  • Framework type and version (narrows available exploits).
  • Database driver and query structure (enables targeted injection).
  • Internal file paths and module structure (aids further reconnaissance).
  • ORM model field names (aids mass assignment attacks).

All of this information is freely handed to an attacker without requiring any authentication. Conservative severity tiers (fail only on high-confidence markers, skipped on ambiguous signals) ensure this category produces actionable findings rather than noise.

Test Matrix

Test Name Trigger/Scope Expected Secure Outcome Notes
debug_route_public_exposure_check Schema inventory for debug routes No public debug routes are exposed Public debug route is immediate failure
debug_route_unauthenticated_access_check Authenticated debug-route target Unauthenticated debug access is denied 2xx without auth is failure
error_response_information_leak_check Safe endpoint payload probes Error responses avoid sensitive internals High-confidence leak markers fail; medium markers skip
error_leakage_target_discovery Category startup Suitable leak-probe endpoints are discoverable Skipped when no safe targets exist

16. JWT Security

Category name: jwt_security

What it is

JWT-specific token-hardening checks that go beyond basic malformed-token validation.

What it does

For bearer/JWT-auth contexts, sends targeted manipulated token variants to authenticated safe endpoints, including:

  • alg:none / alg:None header variants
  • stripped-signature token forms
  • expired and future-nbf claim variants
  • kid traversal and SQL-like injection header variants
  • algorithm-confusion probe when token shape allows it

The category fails when manipulated tokens receive successful access responses and skips when bearer/JWT context is not available.

Why we need it

JWT breakages commonly occur in algorithm selection, signature verification, and header handling paths. These failures can allow token forgery or bypass despite apparently correct auth middleware.

Test Matrix

Test Name Trigger/Scope Expected Secure Outcome Notes
jwt_alg_none JWT-auth safe endpoints alg:none token variant is rejected Header tampering probe
jwt_alg_none_capital JWT-auth safe endpoints alg:None variant is rejected Case-variant parser hardening probe
jwt_signature_stripped JWT-auth safe endpoints Signature-stripped token is rejected Signature verification probe
jwt_expired_claim JWT-auth safe endpoints Expired token claim is rejected Temporal validation probe
jwt_nbf_future_claim JWT-auth safe endpoints Future nbf claim token is rejected Temporal validation probe
jwt_kid_path_traversal JWT-auth safe endpoints Unsafe kid path traversal header is rejected Header abuse probe
jwt_kid_sql_injection JWT-auth safe endpoints Unsafe kid SQL-like header is rejected Header abuse probe
jwt_alg_confusion_rsa_to_hmac JWT-auth safe endpoints (asymmetric original alg only) RS/ES/PS to HS256 confusion variant is rejected Conditional probe
jwt_security_token_presence Category startup Bearer token context exists Skipped in non-bearer auth modes
jwt_security_format_detection Category startup JWT-shaped token format is detected Skipped when access token is not JWT-shaped
jwt_security_target_discovery Category startup Suitable safe auth targets are discoverable Skipped when no targets exist

17. Contract Conformance

Category name: contract_conformance

What it is

Response-level OpenAPI contract validation for status maps and payload structure.

What it does

  • Verifies runtime status codes are declared in each endpoint's OpenAPI responses map
  • Detects undocumented top-level response fields
  • Detects missing required response fields

Why we need it

Contract drift weakens client safety assumptions and can quietly expose new data fields. It also reduces confidence in downstream policy and validation layers that rely on stable response schemas.

Test Matrix

Test Name Trigger/Scope Expected Secure Outcome Notes
response_status_code_conformance Safe endpoints with response schemas Runtime status is declared in OpenAPI responses map Undocumented status is failure
response_undocumented_fields 2xx JSON object responses with schema properties No undeclared top-level fields appear Extra fields are failure
response_missing_required_fields 2xx JSON object responses with required fields All required fields are present Missing required fields are failure
contract_conformance_target_discovery Category startup Suitable schema-backed targets are discoverable Skipped when no targets exist

18. BOLA Matrix

Category name: bola_matrix

What it is

Object-level authorization probing that uses harvested IDs from real API responses.

What it does

  • Harvests ID-like values from collection/list responses
  • Applies neighbor-ID mutation patterns where applicable
  • Reuses harvested IDs across compatible ID-bearing endpoints
  • Flags suspicious cross-object successful access patterns as potential BOLA/IDOR

Why we need it

Live object-ID probing provides stronger signal than synthetic path tampering alone and better matches real attacker behavior for horizontal authorization abuse.

Test Matrix

Test Name Trigger/Scope Expected Secure Outcome Notes
bola_neighbor_id_enumeration ID-bearing GET endpoints with harvested IDs Adjacent/neighbor IDs are denied/hidden Enumeration resistance probe
bola_cross_service_id_probe ID-bearing GET endpoints with cross-service IDs Cross-service object IDs are denied/isolated Domain-isolation probe
bola_uuid_variant_probe UUID-shaped harvested IDs UUID variants are denied/hidden Guessability/authorization probe
bola_matrix_id_harvest Category startup Real object IDs can be harvested Skipped when harvest pool is empty
bola_matrix_target_discovery Category startup Suitable GET ID-path targets are discoverable Skipped when no targets exist

19. Workflow Chains

Category name: workflow_chains

What it is

Stateful lifecycle testing across create, read, update, and delete flows.

What it does

  • Discovers resource-shaped endpoint groups
  • Executes chained CRUD-style operations using extracted IDs
  • Tests auth enforcement on step transitions
  • Attempts cleanup of created resources when delete routes exist

Why we need it

Many authorization and state-management vulnerabilities only appear over multi-step workflows, not in isolated single-endpoint probes.

Test Matrix

Test Name Trigger/Scope Expected Secure Outcome Notes
workflow_create Per-resource chain create step Resource create behaves safely and consistently Starts chain lifecycle
workflow_id_extraction Post-create response parsing Created resource ID is extractable for chain continuation Skip if ID cannot be extracted
workflow_read Per-resource chain read step Created resource read behaves as expected Includes missing-resource signal when unexpected
workflow_read_authz Unauthenticated read of created resource Access is denied without auth 2xx without auth is failure
workflow_update Per-resource chain update step Authorized update behaves safely 400/422 may be informational skip
workflow_update_authz Unauthenticated update attempt Access is denied without auth 2xx without auth is failure
workflow_delete_authz Unauthenticated delete attempt Access is denied without auth 2xx without auth is failure
workflow_delete Authorized delete/cleanup step Created resource is removed or safely handled Cleanup confirmation step
workflow_chains_unsafe_gate Category startup Unsafe mode is explicitly enabled Skipped when --include-unsafe is not enabled
workflow_chains_target_discovery Category startup Resource chain candidates are discoverable Skipped when no chain candidates are found

20. Soak Profile

Category name: soak_profile

What it is

Light sustained-load profiling for safe endpoints to capture reliability and latency behavior.

What it does

  • Replays safe methods repeatedly per endpoint
  • Measures status distribution, exception rate, 5xx rate, and p95 latency
  • Applies threshold-based pass/fail with auth-inaccessible endpoint skipping to avoid false failures
  • Supports tuning via CLI/env/config values (soak_samples, soak_max_5xx_rate, soak_max_exception_rate, soak_max_p95_ms)

Why we need it

Unstable endpoints can hide or distort security results. A soak profile adds confidence in test signal quality and highlights reliability regressions early.

Test Matrix

Test Name Trigger/Scope Expected Secure Outcome Notes
soak_endpoint_stability Repeated safe requests per endpoint Exception/5xx rates remain within configured thresholds Default stable outcome path
soak_endpoint_latency Repeated safe requests per endpoint p95 latency remains within configured threshold Raised when latency threshold is breached
soak_endpoint_access Auth-required endpoints with zero successful responses Result is marked skipped to reduce false-fail noise Evaluated before reliability thresholds
soak_profile_target_discovery Category startup Suitable safe targets are discoverable Skipped when no safe endpoints are available

21. NoSQL Injection

Category name: nosql_injection

What it is

Injects MongoDB-style query operator payloads into JSON request bodies to detect whether the API reflects or processes raw operator input without sanitization — the NoSQL analog of the sql_injection category.

What it does

  • Selects up to 20 discovered endpoints that accept a JSON request body.

  • Replaces the first body field's value with an operator payload instead of a normal scalar value:

    Test Injected value Threat
    nosql_operator_ne {"$ne": null} Not-equal bypass — matches any document where the field isn't exactly this value, commonly used to bypass password/ID equality checks
    nosql_operator_gt {"$gt": ""} Greater-than bypass — matches any non-empty value, another equality-check bypass pattern
    nosql_operator_where {"$where": "1 == 1"} Server-side JavaScript execution — if evaluated, runs arbitrary logic against the database
    nosql_operator_regex {"$regex": ".*"} Regex bypass — matches any string value, another equality-check bypass pattern
  • Only runs against POST/PUT/PATCH endpoints, so — like mass_assignment and schema_contract_and_validation — it requires --include-unsafe (or unsafe_categories including nosql_injection) to actually execute; without it, requests are skipped rather than silently omitted.

Why we need it

NoSQL databases (MongoDB and similar) parse query operators directly from JSON input. Where SQL injection relies on string concatenation, NoSQL injection exploits APIs that pass client-supplied JSON straight into a query filter without validating that fields are the expected scalar type. A login endpoint that accepts {"password": {"$ne": null}} instead of a string password can authenticate without knowing any valid password — a critical authentication bypass. This class of bug doesn't show up in SQL-focused testing and is easy to miss because the payload is syntactically valid JSON, not an escaped string.

Test Matrix

Test Name Trigger/Scope Expected Secure Outcome Notes
nosql_operator_ne JSON-body mutation endpoints with tampered first field $ne operator payload is rejected or type-validated Requires --include-unsafe
nosql_operator_gt JSON-body mutation endpoints with tampered first field $gt operator payload is rejected or type-validated Requires --include-unsafe
nosql_operator_where JSON-body mutation endpoints with tampered first field $where operator payload is rejected or type-validated Requires --include-unsafe
nosql_operator_regex JSON-body mutation endpoints with tampered first field $regex operator payload is rejected or type-validated Requires --include-unsafe
nosql_injection_target_discovery Category startup Suitable JSON-body endpoints are discoverable Skipped when no eligible targets exist

Summary Table

# Category OWASP Reference Safe by Default Requires include_unsafe
1 baseline Yes No
2 owasp API2, general headers Yes No
3 sql_injection API1, A03 Injection Yes No
4 pen_test A03 Injection, XSS Yes No
5 security_misc CORS, general Yes No
6 authz API1, API5 Partial Yes (PATCH/DELETE IDOR probes)
7 auth_robustness API2 Yes No
8 token_security API2 Yes No
9 privilege_escalation API5 Yes No
10 file_upload_security A03, path traversal No Yes (POST/PUT/PATCH)
11 mass_assignment API3 No Yes (POST/PUT/PATCH)
12 schema_contract_and_validation API3, input validation No Yes (POST/PUT/PATCH)
13 ssrf_and_redirects API7 Partial Yes (PATCH + restore)
14 rate_limit_and_resource_abuse API4 Yes No
15 error_leakage_and_debug_surface API8, API9 Yes No
16 jwt_security API2 Yes No
17 contract_conformance API9, API10 Yes No
18 bola_matrix API1 Yes No
19 workflow_chains API1, API5 No Yes (stateful POST/PUT/PATCH/DELETE flows)
20 soak_profile API4 (operational resilience) Yes No
21 nosql_injection API1, A03 Injection No Yes (POST/PUT/PATCH)

Release files for api-gate-keeper 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for api-gate-keeper 0.1.1
File Size Uploaded
api_gate_keeper-0.1.1.tar.gz 106.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for api-gate-keeper 0.1.1
File Interpreter ABI Platform
api_gate_keeper-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 194.8 kB

Release files / api_gate_keeper-0.1.1.tar.gz

Download URL api_gate_keeper-0.1.1.tar.gz
Size 106.9 kB
Tags Source
SHA-256 checksum
How to use checksums
e149a69d9c615cd3b6213acdaf8f84b59c12efc6ed4739f30f3daf0e53943897
BLAKE2b-256 checksum
How to use checksums
8a653a93acc5ef6cd4b9a5c0096a3a404b623a652522360042fd11099ad258e8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 18, 2026.

Transparency log

Release files / api_gate_keeper-0.1.1-py3-none-any.whl

Download URL api_gate_keeper-0.1.1-py3-none-any.whl
Size 87.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b0eec8e0b3ec8a7675c0552f9bbb4961797517d5314447e5b5010c98cbbcb12b
BLAKE2b-256 checksum
How to use checksums
66e4d2c6d8c9a5c209de68bc1c0432f73b8a6651d09946cce5da73d778b0f136
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 18, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page