ASVS 5.0 V13.2.1 requires that backend components which do not use your normal user session mechanism (APIs, middleware, data layers) authenticate to each other using individual service accounts, short lived tokens or certificates. Unchanging credentials such as passwords, long lived API keys and shared privileged accounts do not meet it. This is Level 2.
Why it matters
A static key shared by many services has no owner, no expiry and no audit trail. When it leaks (a log line, a repo, an old laptop) the attacker gets everything it unlocks, indefinitely, and you cannot tell which service misused it. Per service identities with short lifetimes shrink both the window and the blast radius.
How to implement it
Choose workload identity from your platform and use it:
- Cloud IAM roles bound to the workload (instance roles, Kubernetes service account to cloud role mapping) so the SDK fetches temporary credentials automatically.
- OAuth 2.0 client credentials with short access token lifetimes, one client per service.
- Mutual TLS with per service certificates (see V12.3.5).
- Database access through a vault that issues per service credentials with a short TTL.
Kubernetes example with a dedicated service account, no secret mounted:
apiVersion: v1
kind: ServiceAccount
metadata:
name: orders-api
namespace: prod
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: orders-api
namespace: prod
spec:
selector:
matchLabels:
app: orders-api
template:
metadata:
labels:
app: orders-api
spec:
serviceAccountName: orders-api
automountServiceAccountToken: true
containers:
- name: app
image: registry.example/orders-api:1.8.2
Pair it with a cloud role or token audience that only this account may assume.
How to test it
- List credentials each service uses and check that none is a password or key without an expiry.
- Inspect issued tokens: lifetime should be minutes to an hour.
- Use one service's credentials to call another service it should not reach. The call must fail.
- Scan repositories and images for committed credentials.
Click through it at your own pace, or open it full screen.
Common mistakes
- One database admin account used by every service.
- A "service token" with no expiry stored in an environment variable.
- Short lived tokens, but one shared client id so you still cannot tell callers apart.
- Treating a network allowlist as authentication.
Try it yourself
Build a table of every credential your backend uses to call something else: database users, queue credentials, cloud keys, third party API keys. Add columns for owner, lifetime, whether it is shared and how it is rotated. Highlight rows with no expiry or more than one consumer.
Pick the riskiest row and replace it first. For a cloud hosted service, that usually means attaching a role to the workload and deleting the key. For a database, it means moving to a vault issued credential or IAM based authentication. After the switch, delete the old credential and confirm nothing breaks, which proves nothing else was using it.
Repeat until the highlighted rows are gone or have a dated exception with an owner.
Quick check
Is a rotated API key per service acceptable?
It is better than a shared key, but the requirement points to service accounts, short lived tokens or certificates. A key is acceptable only if it is individual and truly short lived.