Overview

API attacks are structurally different from web application attacks. A web application has a rendered HTML interface that constrains what a user can submit; a browser form with five fields is hard to extend beyond those five fields without developer tools. An API has no such constraint — a TPP, a mobile SDK, or an attacker all interact with the same JSON over HTTPS, and the only constraint is the application’s own input validation. This makes API attacks more frequently exploiting business logic flaws than memory corruption or injection — an attacker iterates account IDs until they find one that belongs to another customer, they POST a payment with an amount field they were not supposed to be able to set, they call an admin endpoint that the documentation did not mention but the server answers anyway.

The OWASP API Security Top 10 (2023 edition) is not a list of injection payloads to block with a regex. It is a threat model — a catalogue of the design and implementation failures that produce real API breaches at financial institutions. Each item requires a different mitigation layer: some are addressable at the gateway, some require application-layer fixes, and one (BOLA) cannot be prevented by a WAF at all.

The defence-in-depth model for a SAMA-regulated API estate has three layers: the perimeter WAF (Kong + CRS rules blocking known attack patterns), the API gateway authorization layer (scope validation, DPoP, rate limits, OAS schema validation), and the application layer (ownership checks, consent verification, data access controls). A perimeter WAF that blocks 100% of traffic is not security — it is downtime. The goal is to reduce the attack surface to what the application must own, and ensure the application actually owns it.

OWASP API Top 10 is a threat model, not a WAF rule list

Each item in the OWASP API Top 10 represents a class of vulnerability with a root cause and a mitigation pattern. A WAF rule that blocks SQLi payloads helps with API8 (Security Misconfiguration) but does nothing for API1 (BOLA) or API3 (BOPLA). Do not treat the Top 10 as a checklist of things to block at the gateway — treat it as a risk inventory that maps to your specific API estate, then assign a mitigation layer to each risk. Items that cannot be mitigated at the gateway must have an application-layer control or they remain open.

API1: Broken Object Level Authorization (BOLA)

BOLA is the most prevalent and the most misunderstood API vulnerability. The attack is simple: the client accesses a resource by supplying an ID in the URL (GET /accounts/123456789/transactions), and the server returns data for account 123456789 without verifying that the authenticated caller is the owner of that account. An attacker with a valid access token for their own account iterates the account ID and reads other customers’ transaction data.

This is horizontal privilege escalation. The attacker is not escalating to admin — they are accessing data at the same privilege level but for a different subject. Because the attacker presents a valid token with valid credentials, no authentication check catches this. Because the ID is a valid account number (just not theirs), no input validation catches this. Only an ownership check catches this: does the authenticated principal own, or have explicit consent to access, the resource identified by this ID?

BOLA cannot be prevented by a WAF

A WAF operates on request syntax and patterns. It cannot know that account 123456789 belongs to customer A and that customer B is accessing it. BOLA prevention requires application-layer authorization checks on every data access: extract the authenticated principal from the token, look up which account IDs that principal owns or has consent to access, and reject any request for an ID not in that set. At the gateway, the only tool is anomaly detection on the response: a single access token accessing a high volume of distinct account IDs in a short window is a BOLA signal, not a WAF block. Alert on it and send to SIEM with TPP identity.

Kong’s response transformer plugin can strip sensitive fields from API responses if the ownership check passed but the response still contains data beyond the consented scope (related to API3/BOPLA). For BOLA anomaly detection, use Kong’s plugin SDK to count distinct resource IDs accessed per access token per 60-second window and emit a log event when the count exceeds a threshold (e.g. >20 distinct account IDs for a single AIS token in 60 seconds — typical legitimate use is 1–5).

API2: Broken Authentication

Broken authentication covers a wide range of failures: missing OAuth2 scope validation (the token says scope: openid but the resource server accepts it for a payment endpoint), long-lived tokens without refresh rotation, JWT algorithm confusion attacks (alg: none bypasses signature validation if the library is misconfigured), and JWT secret brute force (symmetric HS256 JWTs with weak secrets are offline-crackable).

Kong’s OIDC plugin mitigates most of these at the gateway: it rejects unsigned or algorithm-none JWTs, validates token signature against the JWKS endpoint, checks expiry, and performs scope validation per route. For payment endpoints, configure the OIDC plugin to require scope: payments and check that the authorization_details claim covers the requested operation. Introspect every token on every request rather than relying on local JWT validation alone — a revoked token that has not expired yet is only caught by introspection.

API3: Broken Object Property Level Authorization (BOPLA)

BOPLA has two failure modes. Mass assignment: the API accepts a POST or PATCH body and the application binds it directly to an object without filtering, allowing a client to set fields they were not supposed to set (e.g. {"status": "approved", "amount": 1} in a loan application). Excessive data exposure: the API returns the full database object and relies on the client to filter out sensitive fields — a change to the business logic that adds a field (e.g. creditScore) is automatically exposed to every API consumer without review.

Kong’s OAS Validation plugin (configured for both request and response validation) addresses both failure modes: it validates incoming request bodies against the OpenAPI spec schema, rejecting any field not defined as a writable property, and it validates response bodies against the spec schema, alerting (or blocking in strict mode) on fields not in the spec. The response transformer plugin can strip fields from responses that should not be returned to external callers, enforced at the gateway layer regardless of what the application returns.

API6 & API8: Sensitive Business Flows, Injection & Misconfiguration

API6 (Unrestricted Access to Sensitive Business Flows) covers automation abuse: a bot submitting payment initiations at machine speed, scraping account data faster than any human could, or probing for valid account numbers by iterating IDs. The WAF layer addresses this via rate limiting per consumer and bot detection — but the business flow rate limit must align with the API class. PIS payment initiation has a legitimate rate of <1 per second per PSU; a token initiating 100 payments per minute is anomalous regardless of whether it passes all authentication checks.

API8 (Security Misconfiguration) includes injection vulnerabilities reachable via API parameters. Query parameter injection, HTTP header injection (X-Forwarded-For spoofing, CRLF injection in custom headers), and SSRF via webhook URL parameters are all injection vectors. ModSecurity OWASP CRS 4.0 rules address these at Paranoia Level 1 (PL1) — the default level that prioritizes low false positives for API traffic — including rules for SQL injection (SQLi), cross-site scripting (XSS), remote code execution (RCE), SSRF detection, and scanner user-agent detection. PL2–PL4 add increasingly aggressive rules with higher false-positive rates, not recommended for production API traffic without extensive tuning.

Never rely on obscurity for API endpoint protection

Security through obscurity is not a SAMA-acceptable control. An API endpoint that requires authentication cannot substitute “undocumented” for “authenticated” — automated scanners discover undocumented endpoints within minutes of exposure. Every endpoint that the API gateway routes — including internal health endpoints, debug endpoints, and admin endpoints — must either require authentication or be blocked at the gateway before they are reachable from outside the internal network. Use Kong’s OAS Validation plugin to reject requests to paths not defined in the OpenAPI spec (API9: Improper Inventory Management) and block all requests to paths matching /actuator/*, /debug/*, and /admin/* at the route level.

Kong WAF Plugin Configuration

Kong 3.7’s WAF enforcement stack for a SAMA Open Banking API route is a chain of plugins applied in order: rate-limiting-advanced (token bucket per consumer), bot-detection (user-agent and fingerprint checks), request-size-limiting (maximum body size per endpoint class), OAS Validation (request + response schema), and the custom ModSecurity CRS plugin. The order matters — rate limiting and bot detection run first to eliminate noise before the more expensive schema validation and CRS rule evaluation.

kong-waf-plugins.yamlyaml
# Kong OAS Validation plugin — request + response validation
- name: oas-validation
  config:
    api_spec_encoded: false
    api_spec: "https://spec.openbanking.saib.sa/pis/v1/openapi.yaml"
    validate_request_body: true
    validate_request_header_params: true
    validate_request_query_params: true
    validate_request_uri_params: true
    validate_response_body: true      # blocks BOPLA (excess data exposure)
    notify_only_request_body_validation_failure: false
    notify_only_response_body_validation_failure: true   # log but don't block on response (perf)
    include_base_path: false
    query_param_checks:
      allowed_params_in_spec_only: true   # reject undocumented query params

# Rate-limiting-advanced — sliding window per TPP consumer
- name: rate-limiting-advanced
  config:
    limit: [10, 100, 2000]             # per minute, per hour, per day
    window_size: [60, 3600, 86400]
    identifier: consumer
    sync_rate: 10                        # sync to Redis every 10 s
    namespace: pis-rate
    strategy: redis
    redis:
      host: redis-cluster.infra.svc
      port: 6379
      ssl: true
    hide_client_headers: false           # TPPs need X-RateLimit-* headers for compliance

# Bot detection — user-agent and fingerprint checks
- name: bot-detection
  config:
    deny:
      - "*(curl|wget|python-requests|go-http-client|libwww-perl)*"    # scanner UAs
      - "*(masscan|nikto|nmap|sqlmap|dirb|dirbuster)*"
    allow:
      - "*(kong-.*|internal-monitor)*"

# Request-size-limiting
- name: request-size-limiting
  config:
    allowed_payload_size: 128            # kilobytes; PIS payload is small
    size_unit: kilobytes
    require_content_length: true

# IP restriction — block Tor exit nodes (updated daily via threat intel feed)
- name: ip-restriction
  config:
    deny:
      - "0.0.0.0/0"                        # default deny-all (override with allow list for TPP IP ranges)
    allow:
      - "10.0.0.0/8"                       # internal services
      - "203.0.113.0/24"                   # example: SAMA-registered TPP IP range

OWASP CRS 4.0 Rules

OWASP Core Rule Set 4.0 with ModSecurity 3 runs inside the Kong gateway as a Lua plugin (or as an Nginx module in front of Kong, depending on deployment topology). The CRS evaluates incoming requests against hundreds of rules and computes an anomaly score; when the score exceeds a threshold, the request is blocked (in blocking mode) or logged (in detection-only mode). PL1 activates the core rules with the lowest false-positive rate — appropriate for production API traffic. PL2–PL4 add progressively more rules that flag more patterns, at the cost of blocking more legitimate requests.

For SAMA Open Banking APIs, the key CRS tuning decisions are: PL1 for the default rule set, with specific exclusions for SAMA-mandated header formats (the x-fapi-interaction-id header, the x-jws-signature header, and Arabic-character values in name fields that PL2 might flag). The anomaly score threshold should be 5 (PL1 default) for detection mode and 10 for blocking mode during the initial 30-day tuning phase, then narrowed to 5 for blocking after false positives are catalogued and excluded.

crs-config.confapache
# ModSecurity CRS 4.0 configuration for SAMA Open Banking API
SecRuleEngine On                          # blocking mode; use DetectionOnly during tuning
SecAuditEngine RelevantOnly               # log only blocked/anomalous requests
SecAuditLog /var/log/modsecurity/audit.log
SecAuditLogParts ABCEFHIJKZ

# Paranoia Level 1 — low false positives for API traffic
SecAction \
  "id:900000,phase:1,nolog,pass,setvar:tx.paranoia_level=1"

# Detection anomaly threshold (score above this triggers alert/block)
SecAction \
  "id:900110,phase:1,nolog,pass,\
   setvar:tx.inbound_anomaly_score_threshold=5,\
   setvar:tx.outbound_anomaly_score_threshold=4"

# API-specific: allow SAMA FAPI headers without triggering header injection rules
SecRuleUpdateTargetByTag "attack-injection-http" \
  "!REQUEST_HEADERS:x-fapi-interaction-id"
SecRuleUpdateTargetByTag "attack-injection-http" \
  "!REQUEST_HEADERS:x-jws-signature"
SecRuleUpdateTargetByTag "attack-injection-http" \
  "!REQUEST_HEADERS:x-idempotency-key"

# Exclusion for Arabic name fields (SAMA KYC data) that may trigger PL2 rules
SecRuleUpdateTargetById 942100 \
  "!REQUEST_BODY:creditor.name"
SecRuleUpdateTargetById 942100 \
  "!REQUEST_BODY:debtor.name"

# Enable SSRF detection rules (PL1 includes 931100, 931110, 931120)
# Covers webhook URL parameters that could trigger internal SSRF
SecRuleEngine On

# Content-Type enforcement for JSON APIs
SecRule REQUEST_METHOD "!@streq GET" \
  "id:990001,phase:1,deny,status:415,log,\
   msg:'Expected Content-Type application/json',\
   chain"
  SecRule REQUEST_HEADERS:Content-Type "!@beginsWith application/json" \
    "t:lowercase"

Bot Detection and Rate Limit Bypass Prevention

In a SAMA Open Banking context, the primary bot threat is not generic web scraping — it is TPP automation misuse: a TPP that registered legitimately through the SAMA Open Banking Directory but is querying account data at machine speed, initiating test payments in production, or probing for valid account numbers. The TPP identity (client_id from the SAMA directory) is the anchor for all rate limiting and anomaly detection.

Effective bot detection for Open Banking APIs uses a dual-signal model. The primary signal is the OAuth 2.0 client_id (the TPP identifier from the SAMA directory) — rate limits and anomaly thresholds are enforced per client_id, not per IP. The secondary signal is the source IP — a client_id appearing from many different IPs simultaneously may indicate credential theft or a distributed TPP deployment that should have been registered separately. Alert when a single client_id originates from more than five distinct IP subnets in a 10-minute window.

The X-Device-ID custom header (sent by TPP mobile SDKs) provides a third signal: device fingerprint. A single device ID associated with multiple PSU accounts in rapid succession is a BOLA pattern. Correlate device ID with PSU identity in the access log and alert when one device ID accesses more than three distinct PSU accounts within five minutes.

WAF Incident Response

A WAF in blocking mode that fires incorrectly blocks legitimate TPP traffic. A blocked payment initiation from a legitimate TPP is a service outage, not a security event. WAF incident response must treat false positives with the same urgency as application outages — not as an acceptable consequence of security controls.

The incident response process: WAF logs ship to the SIEM (Splunk or IBM QRadar) in real time via the Kong logging plugin, tagged with the CRS rule ID that triggered, the anomaly score, the request URI, and the TPP client_id. Alert on any CRS rule score above threshold for a TPP that has had no prior WAF events (first-time block for a known-good TPP is almost certainly a false positive). Alert on any block that correlates with a drop in successful API calls from the same TPP (indicates a real production impact, not a test probe being blocked). The SLA for investigating a WAF false positive affecting a SAMA-registered TPP is 30 minutes during business hours; escalation to the API security team is immediate.

SAMA’s Cyber Security Framework requires that internet-facing API security events be logged with the TPP identity, incident type, timestamps, and disposition (blocked / allowed / alerted). The WAF log record must include the client_id from the OAuth token (extracted by Kong before the WAF plugin) so that every security event is attributable to a specific SAMA-registered TPP. Generic IP-based logging is insufficient for SAMA examination purposes.

API#NameWAF addressable?Application layer fixKong pluginDetection signal
API1Broken Object Level AuthorizationNo — business logicOwnership check on every data accessResponse logging — anomaly alertOne token accessing many distinct resource IDs
API2Broken AuthenticationPartiallyScope validation per endpoint; token introspectionOIDC + introspectionalg:none tokens; expired tokens; invalid scopes
API3Broken Object Property Level AuthorizationPartiallyAllowlist writable fields; filter response fieldsOAS Validation + Response TransformerExtra fields in request body; unexpected fields in response
API4Unrestricted Resource ConsumptionYesResource-type rate limitsrate-limiting-advancedVolumetric spike above consent-class limit
API5Broken Function Level AuthorizationPartiallyRole-based function access; admin endpoint authACL + OAS ValidationNon-admin token on admin-path
API6Unrestricted Access to Sensitive Business FlowsPartiallyBusiness-flow rate limits; step validationrate-limiting-advanced + bot-detectionAutomation velocity pattern
API7Server-Side Request ForgeryYesValidate webhook URLs against allowlistCRS 4.0 rule 931100Internal IP or metadata endpoint in URL param
API8Security MisconfigurationPartiallyHarden config; disable debug; enforce TLSOAS Validation + CRSDebug params; non-HTTPS; unlisted endpoint access
API9Improper Inventory ManagementPartiallyAPI inventory; deprecation policyOAS Validation (reject unknown paths)Requests to undocumented paths
API10Unsafe Consumption of APIsNoValidate & sanitise third-party API responsesResponse Transformer (content-type check)Unexpected content-type from upstream

Production Checklist

  1. Map OWASP API Top 10 to your API estate. For each item, identify which APIs are exposed to the relevant threat, what the current mitigation is, and what the gap is. BOLA and API10 gaps are application-layer responsibilities — assign owners in the API team, not the security team alone.
  2. Enable OAS Validation on all external routes. Request body, query parameters, and URI parameters. Response body validation in notification-only mode initially. Move to blocking mode for response validation after a 30-day baseline period confirms no false positives.
  3. Deploy CRS 4.0 in detection-only mode first. Run for 30 days, catalogue false positives by rule ID, write exclusions for SAMA-specific header formats and Arabic character fields. Switch to blocking mode only after FP rate is below 0.01% of legitimate traffic.
  4. Set rate limits per consent class. PIS: 10 initiations per TPP per minute. AIS: 4 calls per second per TPP per account. CoF: 30 calls per minute per merchant. Rate limits must be enforced in a distributed counter (Redis) — a per-Kong-node counter is trivially bypassed by sending traffic to multiple nodes.
  5. Configure SIEM integration. All WAF block events, CRS score-threshold events, and BOLA anomaly events must reach the SIEM with TPP client_id, source IP, rule ID, request URI, and timestamp. SAMA examination requires a complete security event log attributable to specific SAMA-registered TPPs.
  6. Establish a false-positive SLA. 30 minutes from detection to WAF rule exclusion for a confirmed FP affecting a SAMA-registered TPP. False positive triage must be part of the on-call runbook, not an ad-hoc process. Document every exclusion with rule ID, justification, approver, and date.
  7. Block all undocumented paths. Configure Kong to reject requests to paths not defined in the OpenAPI spec. Log every such request — they are either API9 (deprecated endpoint still in use) or an active probe. Alert if any undocumented path receives more than 5 requests in 60 seconds.
  1. OWASP API Top 10 risk inventory mapped to API estate; owners assigned per item.
  2. OAS Validation active on all external-facing routes; request blocking enabled; response logging enabled.
  3. CRS 4.0 at PL1 active in blocking mode; anomaly score threshold 5; FP exclusions documented.
  4. Rate-limiting-advanced on Redis Cluster; per-client_id limits by consent class.
  5. Bot-detection plugin active; scanner UA patterns deny-listed; legitimate TPP SDKs in allow list.
  6. Request-size-limiting per endpoint class (PIS: 128 KB, AIS: 64 KB, document upload: 10 MB).
  7. IP restriction blocking Tor exit nodes (updated daily via threat intel feed).
  8. WAF logs to SIEM; TPP client_id in every security event record.
  9. BOLA anomaly detection: alert when one token accesses >20 distinct resource IDs per 60 s.
  10. False-positive SLA: 30 minutes to WAF rule exclusion during business hours; on-call for critical TPPs.
  11. All WAF exclusions documented with rule ID, justification, approver, date; reviewed quarterly.
  12. Undocumented path access logged and alerted; >5 requests / 60 s triggers SIEM alert.