APIs are often the most direct route into an application, its data, and the services behind it. For development teams, that makes API security testing a practical part of release quality, not a separate exercise reserved for later. A well-run checklist helps you catch weak authentication, broken authorisation, excessive data exposure, and integration mistakes before they become production issues.
This article is aimed at technical practitioners working in UK SMEs who need a repeatable way to test APIs during development and pre-release. It is deliberately focused on controls that can be verified in code, in test environments, and in CI/CD pipelines. It is not a substitute for a full application security programme, but it gives you a solid baseline for day-to-day engineering work.
Used properly, this checklist fits into the secure development lifecycle and supports the same risk-based thinking used in frameworks such as OWASP ASVS and Microsoft SDL. If your team already runs security testing as part of release pipelines, this checklist can become the API-specific layer that sits underneath your broader automation.
Key takeaways
- Test API security as part of the SDLC and release pipeline, not as a one-off activity after development is finished.
- Focus on authentication, authorisation, schema enforcement, rate limiting, logging, and transport security because those controls most often determine real exposure.
- Use contract tests, negative tests, and gateway-aware checks to catch regressions before they reach production.
- Treat secrets, webhooks, OAuth scopes, and third-party integrations as part of the API attack surface, not separate concerns.
What this checklist is for and when to use it
The purpose of an API security testing checklist is to make sure the same classes of weakness are checked consistently across releases. That matters because API defects are often introduced by small changes: a new field in a response, a missing role check on one endpoint, or a token validation rule that is too permissive.
Use the checklist at three points. First, during design and implementation, when the API contract is still changing. Second, during pull request review and automated testing, when you can still block a release cheaply. Third, before production release, when you want to confirm that the deployed build behaves as expected in a realistic environment.
The checklist applies to REST APIs, GraphQL endpoints, and internal service-to-service interfaces. The exact mechanics differ, but the control objectives are the same: prove that only the right caller can reach the right function, with the right data, at the right rate, over a trusted channel.
Define the API attack surface before testing
Before you test controls, you need a complete view of what is actually exposed. Many API security failures start with incomplete inventory. Teams test the documented endpoints and miss admin routes, legacy versions, webhook handlers, or internal methods that are still reachable from a wider network segment than intended.
Build an inventory of endpoints, methods, authentication requirements, and data classes. Include the HTTP method, route pattern, expected roles, whether the endpoint is public or private, and whether it processes personal data, financial data, or operational data. For GraphQL, record the schema, the available queries and mutations, and any fields that expose nested objects or related records.
Map trust boundaries as part of that inventory. Identify where traffic crosses from browser to API gateway, from gateway to application, from application to downstream services, and from internal service to third-party integration. This is also the point to note any exposed admin functions, debug endpoints, health checks, and test-only features that could become reachable in production if configuration drifts.
Where possible, keep the inventory close to the source of truth. OpenAPI specifications, GraphQL schemas, gateway configuration, and infrastructure-as-code should all be checked together. If those artefacts disagree, the test plan will usually miss something.
Test authentication controls
Authentication testing should answer a simple question: can an attacker impersonate a valid caller, or keep using credentials after they should have expired? For APIs, this usually means testing bearer tokens, API keys, OAuth flows, and machine-to-machine credentials.
Check token handling first. Confirm that tokens are validated for issuer, audience, signature, expiry, and not-before time. If you use JWTs, verify that the application rejects unsigned or incorrectly signed tokens, and that it does not accept unexpected algorithms. Test that expired tokens are rejected consistently, including after clock skew and refresh events.
Rotation and revocation are equally important. If a token or key is revoked, the API should stop accepting it within the expected window. For long-lived credentials, define what “expected” means in your environment and test it. A common failure mode is a revocation process that works in one service but not in a cached gateway or downstream microservice.
For session-based APIs, confirm that session identifiers are unpredictable, bound to the right context, and invalidated on logout or privilege change. For machine-to-machine authentication, check that service identities are scoped tightly and that credentials are not shared across environments. Service accounts used in development should not have the same reach as production identities.
If your API uses OAuth, test the scope model carefully. A token with read-only scope should not be able to create, update, or delete data. Also check that the application does not trust claims that are not enforced by the authorisation layer. Authentication proves who the caller is. It does not prove what they are allowed to do.
Test authorisation and object-level access control
Authorisation is where many API issues become serious. Broken object level authorisation, often called BOLA, occurs when a caller can access another user’s object simply by changing an identifier. Broken function level authorisation occurs when a user can reach an action that should be reserved for a different role.
Test object access by changing identifiers in requests and checking whether the response still returns data that belongs to another user, tenant, or account. Do this across all object types, not just the obvious ones. Orders, invoices, files, tickets, devices, and profile records are all common candidates. The test should cover direct object references, nested object references, and list endpoints that return related records.
Test function access by attempting privileged actions with lower-privilege roles. For example, a standard user should not be able to call administrative endpoints, change another user’s role, export bulk data, or modify security settings. Do not assume that the front end prevents this. The API must enforce the rule itself.
Tenant isolation deserves separate attention in multi-tenant SaaS. Verify that a token issued for one tenant cannot read or modify another tenant’s data, even if the caller knows the object identifier. Also check for cross-tenant leakage in search, reporting, background jobs, and webhook processing, because those paths are often less carefully protected than the main request flow.
Where role-based access control is used, confirm that the implementation is explicit and centrally enforced. Ad hoc checks scattered through controller code are easier to miss and harder to maintain. If you already have a secure code review process, link this testing to the same review criteria used for access control in application code.
Validate input handling and schema enforcement
API input validation should be strict, predictable, and aligned to the contract. Every request parameter, header, and body field should be validated for type, length, format, range, and allowed values. The goal is not only to prevent injection flaws, but also to stop malformed or unexpected data from changing application behaviour.
Test positive and negative cases. Positive tests confirm that valid requests are accepted. Negative tests confirm that invalid requests are rejected with a controlled error. Check what happens when required fields are missing, when numeric values are replaced with strings, when arrays are sent where scalars are expected, and when unexpected fields are added to the payload.
Mass assignment is a common issue in JSON APIs. If the application binds request bodies directly to model objects, an attacker may be able to set fields that were never intended to be user-controlled, such as role, status, price, or ownership attributes. Test whether the API ignores or rejects fields that should be server-controlled.
Content type handling also matters. Confirm that the API accepts only the content types it is designed to process, and that it does not silently interpret ambiguous input. For example, if the endpoint expects JSON, it should not accept form-encoded or XML payloads unless that is explicitly required and tested.
For APIs that use deserialisation, test for unsafe object creation, unexpected type coercion, and overly permissive polymorphic handling. These issues are often subtle and can be missed if the team relies only on happy-path functional tests. The article on input validation, encoding, and output sanitisation techniques is a useful companion if you want to go deeper into the mechanics.
Check output handling and data exposure
APIs frequently expose more data than the client actually needs. That creates unnecessary risk even when authentication and authorisation are correct. Excessive data exposure can reveal personal data, internal identifiers, security flags, pricing logic, or operational metadata that should not be visible to every caller.
Review response bodies field by field. Confirm that each endpoint returns only the data required for the use case. If a mobile app needs a display name and status, it should not receive internal notes, audit metadata, or full account records. For GraphQL, test whether the schema allows clients to request fields that should be hidden or restricted.
Pagination and filtering deserve the same scrutiny. A list endpoint may be safe for a single page but leak data when page size is increased, filters are removed, or sort parameters are manipulated. Test whether the API enforces sensible limits and whether it validates filter inputs against allowed values rather than passing them directly to a query layer.
Error messages should be useful for developers but not revealing for attackers. Check that stack traces, database errors, internal hostnames, and implementation details are not returned to clients. A controlled error response should tell the caller what went wrong without exposing internals that help with enumeration or exploitation.
Also check logging side effects. Sometimes the response is clean, but the application logs the full request or response body, including secrets or personal data. That is a separate exposure path and should be treated as part of the same test case.
Assess rate limiting and abuse resistance
Rate limiting is not only about availability. It also reduces the value of brute force, credential stuffing, enumeration, and scraping. A good API security test should confirm that abusive request patterns are slowed, blocked, or challenged before they can cause damage.
Test authentication endpoints, password reset flows, OTP verification, and token refresh endpoints first. These are common targets for automated abuse. Confirm that the API applies per-user, per-IP, and where appropriate per-device or per-client limits. If the service is public, test whether limits are enforced consistently across the gateway and application layers.
Then test enumeration resistance. If an endpoint reveals whether a user, order, or account exists, an attacker can use that signal to build a target list. The response should be as uniform as practical, with careful handling of timing, status codes, and error text. This is especially important for account recovery and registration flows.
Quota enforcement should be tested as a business control as well as a technical one. If one tenant can consume disproportionate resources, other tenants may experience degraded service. For APIs that support bulk export, search, or report generation, confirm that quotas and throttles are enforced before expensive work starts, not after.
For denial-of-service resilience, test how the API behaves under repeated large payloads, slow requests, and bursts of valid traffic. The aim is not to break the service, but to confirm that defensive controls, timeouts, and queue limits behave as designed. If you need a broader view of resilience testing, the article on testing systems for high load and denial-of-service conditions is relevant.
Review transport security and API gateway controls
Transport security is easy to assume and easy to misconfigure. Every API should use TLS, and the configuration should be reviewed as part of testing rather than left to default platform settings. Check that plaintext HTTP is redirected or rejected, that weak protocol versions are disabled, and that certificates are valid and trusted in the intended environment.
For service-to-service APIs, consider mutual TLS where the trust model justifies it. Mutual authentication can reduce the risk of rogue internal clients, but only if certificate issuance, rotation, and revocation are managed properly. Test that the service rejects clients without the correct certificate and that certificate expiry does not create an outage.
API gateways and reverse proxies should be part of the test scope. Gateway policies often implement authentication, header normalisation, request size limits, and path-based routing. If the gateway and application disagree on how to interpret a request, an attacker may be able to bypass controls by using alternate encodings, duplicated headers, or unusual path formats.
Check whether the gateway strips or rewrites headers that should not be client-controlled, such as internal forwarding headers or identity assertions. Also confirm that request normalisation happens before security decisions are made. A control that inspects one representation of a request while the backend processes another is a common source of bypass.
Test logging, monitoring, and detection coverage
Security testing should not stop at prevention. You also need to know whether the right events are being logged and whether the logs are useful for investigation and detection. If an API is attacked, the team should be able to reconstruct what happened without relying on guesswork.
At a minimum, log authentication successes and failures, authorisation failures, token issuance and revocation events, privilege changes, object access denials, rate-limit triggers, and unusual request patterns. Include correlation identifiers so that a single transaction can be traced across gateway, application, and downstream services.
Be careful not to log sensitive data unnecessarily. Request bodies, tokens, passwords, and personal data should be excluded or masked unless there is a clear operational reason to retain them. The logging design should support incident response without creating a second data exposure problem.
From a detection perspective, think about what abnormal API activity looks like in your environment. Examples include repeated access denied responses from the same token, sudden increases in object enumeration, requests from unusual geographies, or a service account calling endpoints it never normally uses. Those patterns can be surfaced in a SIEM and, where appropriate, fed into SOAR playbooks for automated containment.
Check secrets, keys, and third-party integrations
API security often depends on the security of secrets and integrations around the API itself. Keys, client secrets, signing material, and webhook tokens should be stored in a dedicated secrets manager, not in source code, build logs, or environment files committed to the repository.
Test how secrets are issued, rotated, and revoked. Confirm that a leaked key can be replaced without a manual redeploy of every dependent service. Check that development, test, and production secrets are separated and that access is limited by role and environment. If service accounts are used, verify that they have the minimum permissions needed for their function.
Third-party integrations deserve specific attention. Webhooks should be authenticated, replay-resistant, and validated against a known sender profile. OAuth integrations should use the narrowest practical scopes and should be reviewed whenever the integration changes. If the API consumes data from external services, treat that input as untrusted even if the partner is known and the channel is encrypted.
Dependency risk also matters. Libraries used in API frameworks, authentication middleware, JSON parsing, and gateway plugins can all introduce exposure if they are outdated or poorly maintained. If your team is already working on software supply chain assurance, tie the API checklist to dependency review and build provenance controls. The article on software supply chain assurance controls is a useful reference point here.
Automate API security checks in CI/CD
Manual testing is valuable, but it does not scale well across frequent releases. The strongest pattern is to automate as much of the checklist as possible in CI/CD and reserve manual effort for edge cases, complex authorisation logic, and exploratory testing.
Place static analysis early in the pipeline so that obvious coding issues are caught before merge. Add API contract tests to verify that the implementation still matches the OpenAPI or GraphQL schema. Include negative tests that send malformed requests, missing fields, unexpected roles, and boundary values. These tests are often more valuable than a large number of happy-path checks.
Dynamic testing should run against a deployed test environment that mirrors production controls as closely as possible. That includes the gateway, identity provider, rate limiting, and logging path. If the test environment is too different from production, the results will be misleading. For example, a test that passes without a gateway may fail in production because the gateway normalises requests differently.
Use contract tests to stop accidental breaking changes and security regressions. For example, if a field should no longer be returned, assert that it is absent. If a role should not reach an endpoint, assert that the request is rejected. If a token should expire after a fixed interval, assert that the API refuses it after that point. These are simple tests, but they prevent a lot of avoidable drift.
Prioritise findings and decide what good looks like
Not every issue has the same urgency. A useful checklist should help the team decide what must block release and what can be scheduled for remediation. Prioritisation should combine exploitability, exposure, and business impact.
As a rule, treat unauthorised access to another user’s data, privilege escalation, token bypass, and secret leakage as high priority. Issues that only affect edge-case behaviour or require unrealistic preconditions may still matter, but they should be triaged differently. The key is to avoid a flat backlog where everything is labelled critical and nothing gets fixed.
Define minimum acceptance criteria for release readiness. For example: all authentication and authorisation tests pass, no high-risk data exposure remains, rate limiting is in place for public endpoints, and logging captures the events needed for investigation. That gives engineering, product, and security teams a common standard to work to.
If you want to align the checklist with a broader secure development programme, map the findings to your existing risk treatment process and secure coding standards. That keeps the work practical and avoids creating a separate security process that nobody uses.
Common API security gaps teams miss
Some of the most persistent API issues are not in the main code path. Versioning mistakes are a good example. Old API versions may remain live long after the team believes they have been retired. If those versions are less protected, they can become the easiest route in.
Shadow APIs are another common gap. These include undocumented endpoints created for internal tooling, partner integrations, or temporary debugging. If they are not in the inventory, they are unlikely to be tested. The same applies to staging or test environments that are reachable from the internet and use weaker controls than production.
Documentation can also create risk if it is too generous. Public API docs should not expose internal-only routes, sample credentials, or implementation details that reveal how to bypass controls. Debug features, verbose error modes, and admin consoles should be disabled or tightly restricted outside controlled environments.
Finally, do not forget asynchronous paths. Webhooks, message queues, background jobs, and event consumers often process the same data as the main API but with less scrutiny. They should be tested with the same assumptions about trust, validation, and authorisation.
For teams building or buying software in the UK SME space, the practical value of this checklist is consistency. It gives developers a repeatable way to test the controls that matter most, and it gives security and engineering leaders a clearer basis for release decisions. If you want help turning this into a working control set for your environment, speak to a consultant.
Frequently asked questions
What should be included in an API security testing checklist?
A practical checklist should cover authentication, authorisation, object-level access control, input validation, schema enforcement, output handling, rate limiting, transport security, logging, secrets management, and integration trust. It should also include automated checks in CI/CD so the same controls are verified on every release.
How often should development teams test APIs for security?
API security checks should run continuously during development, on every meaningful change, and again before release. High-risk areas such as authentication, authorisation, and data exposure should be tested whenever related code, configuration, or gateway policy changes.


Comments are closed