Security failures often appear at boundaries: one flow sets a value that another flow trusts, one role changes an assurance requirement, or an integration failure triggers a workaround that bypasses authorization. Unit tests are necessary, but they cannot fully express those relationships.

Four stages showing a change to one flow, a second flow that still assumes the old behaviour, a combination that permits something new, and eventual discovery by someone testing combinations.
Correct in isolation. Unsafe in sequence.

Model the product as connected state machines

List sensitive flows—signup, authentication, credential enrolment, recovery, role selection, provisioning and access approval—and identify shared states and records. Draw the dependencies between them. This exposes places where a change in one area may influence a supposedly separate path.

WebFrolic’s security paper highlights fragmented identity flows and chained attacks. It describes server-side extended state and transaction-based flows as ways to preserve history and validate transitions. Tests should exercise those properties across the whole request, not only one handler at a time.

Add adversarial combinations to the test plan

Think like an attacker who can use ordinary features in an unusual order. Can a user enrol a new authenticator and then satisfy a strong role requirement? Can recovery leave old API keys working? Can a tenant administrator change an identifier to reach another tenant? Can a partial provisioning failure leave access behind?

State the expected policy outcome and verify the audit trail too. A denial without an intelligible record is hard to investigate; a success without evidence is hard to validate. Security assertions belong in the functional result and operation history.

Test failure and retry paths

Integrations time out, clients retry, requests are duplicated and workers process events out of order. Sensitive operations must be safe under those conditions. Check idempotency, rollback or compensation, partial completion and what happens when a dependency is unavailable.

Fallbacks deserve extra attention. Emergency support, alternative authenticators and integration recovery may be necessary, but can create hidden routes around the main policy. Test every fallback as a first-class flow with explicit preconditions and audit events.

Make the test suite evolve with policy

When a feature changes shared state, role assignment, authenticator configuration or recovery, expand regression coverage to adjacent flows. Maintain a set of invariants—for example, “a new factor cannot authorise its own enrolment”—and test them wherever relevant.

A complete test matrix can grow quickly, so prioritise privilege boundaries, cross-tenant operations, credential changes, recovery and high-impact configuration. Security testing should be a release discipline rather than a one-time assessment.

What to ask your own team

Map interactions among flows, roles, credentials and integrations?

Maintain explicit security invariants and test relevant paths?

Exercise retries, partial failures, fallbacks and out-of-order operations?

Review final decisions and correlated audit evidence?

← Back to all articlesRead the security white paper →