SBAC: State-Based Access Control

Modern security systems are very good at answering the question:

“Is this identity allowed to perform this action?”

They are far less effective at answering:

“Is this action correct right now?”

Most real-world security failures occur in this gap. Actions are authenticated, authorized, schema-valid, and yet behaviorally wrong. Endpoints are invoked out of order, workflows are bypassed, state is replayed, and valid APIs are called at invalid times.

I am proposing in this paper that State-Based Access Control (SBAC) addresses this gap by enforcing interaction correctness using a server-authoritative model inspired by authoritative simulation systems.

The diagram above illustrates how SBAC layers alongside RBAC and ABAC.

RBAC answers who may act, ABAC answers under what conditions, and SBAC enforces when an action is valid based on authoritative system state.

Only actions reachable from the current state are permitted. All others are treated as behavioral anomalies.


Motivation and Intuition

1. The Gap Between Allowed and Correct

Traditional access control models focus on identity and permission. They assume that once a client is authenticated and authorized, it will behave correctly.

In practice, this assumption fails. Attackers do not need exploits when they can simply call valid endpoints in the wrong order or at the wrong time.

SBAC exists to make behavior itself a first-class security concern.


2. The Core Principle

SBAC is built on simple concepts:

  • Clients do not execute workflows
  • They submit inputs
  • The server decides what is possible

This principle has been battle-tested in multiplayer game engines for decades. SBAC applies the same thinking to web applications, APIs, and real-time distributed systems.


3. Why SBAC Complements RBAC and ABAC

SBAC is not a replacement for existing access control models.

  • RBAC determines who may act
  • ABAC determines under what conditions they may act
  • SBAC determines when and in what order actions are valid

All three layers are required for correct enforcement.


SBAC Technical Specification

4. Definition of State-Based Access Control

State-Based Access Control (SBAC) is an access control model in which the validity of an action is determined by the current authoritative state of the system and the set of transitions reachable from that state.

An action is permitted if and only if:

  1. The client is authenticated (out of scope)
  2. The client is authorized by RBAC or ABAC (out of scope)
  3. The action corresponds to a valid transition from the current state
  4. All transition guards evaluate to true

5. Formal Model of Interaction State

SBAC assumes that applications have security-relevant state, even when that state is implicit in application logic.

This state must be made explicit.

Let:

  • S be the set of all security-relevant server states
  • I be the set of all externally observable client inputs
  • T ⊆ S × I × S be the set of valid transitions

The authoritative interaction model is defined as:

G = (S, T)  

This graph is not a developer workflow diagram.

It is a security artifact.

If an action is not represented in T, it does not exist from a security perspective.

C# example: modeling states and transitions

public enum StateId  
{
    Browsing,
    CheckoutPending,
    Complete
}

public enum OperationId  
{
    StartCheckout,
    ConfirmCheckout
}

/// <summary>
/// Canonical external input after transport normalization.
/// </summary>
public sealed record InputEnvelope(  
    OperationId Operation,
    string ClientId,
    string SessionId,
    long Sequence,
    string Nonce,
    IReadOnlyDictionary<string, string> Meta,
    JsonElement? Payload);

public sealed record Transition(  
    StateId From,
    OperationId Operation,
    StateId To);

6. Transitions, Guards, and Reducers

Each transition in T is defined by:

  • a source state
  • an operation identifier
  • a guard predicate
  • a reducer function

The guard determines whether the transition is valid.

The reducer determines how the server state evolves.

Authorization logic belongs in guards.

State mutation belongs in reducers.

C# example: guard and reducer separation

public delegate ValueTask<bool> GuardAsync(  
    StateId state,
    ClassifiedClient client,
    InputEnvelope input,
    CancellationToken ct);

public delegate ValueTask<StateId> ReducerAsync(  
    StateId state,
    ClassifiedClient client,
    InputEnvelope input,
    CancellationToken ct);

public sealed record TransitionDef(  
    Transition Transition,
    GuardAsync Guard,
    ReducerAsync Reduce);

7. Input Envelopes and Normalization

SBAC does not validate raw requests.

All client interactions are normalized into a canonical input envelope before evaluation.

An input envelope typically contains:

  • operation identifier
  • client classification
  • monotonic sequence number
  • nonce or uniqueness token
  • request metadata
  • payload (if applicable)
  • transport identifier

Normalization ensures uniform enforcement across transports, replay detection, and ordering validation.

C# example: normalize HTTP into an input envelope (minimal)

public static class InputNormalization  
{
    public static InputEnvelope FromHttp(HttpRequest req, string clientId, string sessionId)
    {
        // Example: map endpoint to an SBAC operation
        var op = req.Path.Value switch
        {
            "/checkout/start"   => OperationId.StartCheckout,
            "/checkout/confirm" => OperationId.ConfirmCheckout,
            _ => throw new InvalidOperationException("Unknown operation")
        };

        // Sequence/nonce can be sent as headers or body fields (implementation choice)
        var seq = long.Parse(req.Headers["X-Sbac-Seq"]);
        var nonce = req.Headers["X-Sbac-Nonce"].ToString();

        var meta = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
        {
            ["method"] = req.Method,
            ["path"] = req.Path.Value ?? "",
            ["ua"] = req.Headers.UserAgent.ToString()
        };

        return new InputEnvelope(op, clientId, sessionId, seq, nonce, meta, payload: null);
    }
}

8. The Ghost (Reachability Envelope)

At any moment, only a subset of transitions is valid.

Gs = { t ∈ T | from(t) = s ∧ guard(t, s) = true }  

Gs defines what actions are valid right now.

It is never fully exposed to the client.

Any input outside of Gs is behaviorally inconsistent and constitutes an anomaly.

The ghost represents a strict security boundary.

Transitions outside of Gs are not deferred, sanitized, or conditionally evaluated.

They are categorically invalid for the current state.

C# example: compute the ghost and enforce it

public sealed class SbacEngine  
{
    private readonly IReadOnlyList<TransitionDef> _defs;

    public SbacEngine(IEnumerable<TransitionDef> defs) => _defs = defs.ToList();

    public async ValueTask<IReadOnlyList<TransitionDef>> ComputeGhostAsync(
        StateId current,
        ClassifiedClient client,
        InputEnvelope inputContext,
        CancellationToken ct)
    {
        var candidates = _defs.Where(d => d.Transition.From == current).ToList();
        var allowed = new List<TransitionDef>(capacity: candidates.Count);

        foreach (var d in candidates)
        {
            if (await d.Guard(current, client, inputContext, ct))
                allowed.Add(d);
        }

        return allowed;
    }

    public async ValueTask<StateId> ApplyAsync(
        StateId current,
        ClassifiedClient client,
        InputEnvelope input,
        CancellationToken ct)
    {
        var ghost = await ComputeGhostAsync(current, client, input, ct);

        var match = ghost.FirstOrDefault(d => d.Transition.Operation == input.Operation);
        if (match is null)
            throw new SbacAnomalyException(SbacAnomaly.InvalidTransitionAttempt, "Operation not in ghost");

        return await match.Reduce(current, client, input, ct);
    }
}

9. Bounded Lookahead and Predictive Disclosure

SBAC may optionally define bounded reachability:

Reachable(s, k)  

This represents the set of states reachable from s within k transitions.

Bounded reachability enables predictive asset loading, UI prefetching, capability pre-issuance, and latency hiding.

Predictive disclosure must never expand the ghost.

C# example: bounded lookahead for prefetch hints (conceptual)

public static class Reachability  
{
    public static ISet<StateId> ReachableWithin(
        StateId start,
        int k,
        IEnumerable<TransitionDef> defs)
    {
        var byFrom = defs.GroupBy(d => d.Transition.From)
                         .ToDictionary(g => g.Key, g => g.Select(x => x.Transition.To).ToArray());

        var reachable = new HashSet<StateId> { start };
        var frontier = new HashSet<StateId> { start };

        for (int depth = 0; depth < k; depth++)
        {
            var next = new HashSet<StateId>();
            foreach (var s in frontier)
            {
                if (!byFrom.TryGetValue(s, out var tos)) continue;
                foreach (var to in tos)
                    if (reachable.Add(to)) next.Add(to);
            }
            frontier = next;
            if (frontier.Count == 0) break;
        }

        return reachable;
    }
}

10. Client Model

SBAC replaces the ambiguous notion of “user” with client.

A client is any external entity that interacts with the system and may originate inputs or receive disclosures.

Client classification is assigned by the server, not claimed by the client.

C# example: classify a client (simplified)

public enum ClientClass  
{
    Human,
    Api,
    Seo,
    Unknown
}

public sealed record ClassifiedClient(  
    string ClientId,
    ClientClass Class,
    string? SubjectId,     // user id or service principal id
    string? TokenId);      // JTI or equivalent

11. Client Classes

SBAC recognizes four common client classes:

  • Interactive Human Client
  • Programmatic API Client
  • Observational Client (SEO)
  • Unknown Client

Each class receives a different projection of the system and interaction surface.


12. Authoritative Disclosure (SEO)

Observational clients do not traverse workflows.

They receive disclosure projections, which are read-only, server-authored views of the system.

Disclosure endpoints must never originate state transitions.


13. Capability Tokens and State Coupling

SBAC discourages implicit permission for stateful operations.

Instead, the server issues capability tokens that bind an operation to a specific state or resource and are time-limited.

Capabilities are proofs of reachability, not authentication.

C# example: capability token shape (conceptual)

public sealed record Capability(  
    string CapabilityId,
    string ClientId,
    OperationId Operation,
    StateId BoundState,
    DateTimeOffset ExpiresAt,
    string Signature); // HMAC or asymmetric signature

// Verify that the capability was issued by the server and is still valid
public static bool VerifyCapability(Capability cap, StateId currentState, DateTimeOffset nowUtc)  
{
    if (cap.ExpiresAt <= nowUtc) return false;
    if (cap.BoundState != currentState) return false;
    // Signature validation omitted here (implementation-specific)
    return true;
}

14. Transport-Agnostic Enforcement

All client inputs must pass through the same authoritative validation pipeline, regardless of transport.

Behavior must be enforced identically across HTTP, WebSockets, SignalR, gRPC, and message queues.


15. Temporal Integrity

SBAC assumes adversaries can replay requests.

The server must therefore detect duplicated, reordered, or delayed inputs using sequence numbers, nonces, or server-issued state versions.

C# example: basic sequence/nonce gate (per session)

public sealed class ReplayGate  
{
    private long _lastSeq;
    private readonly HashSet<string> _nonces = new(StringComparer.Ordinal);

    public bool Accept(long seq, string nonce)
    {
        if (seq <= _lastSeq) return false;
        if (!_nonces.Add(nonce)) return false;

        _lastSeq = seq;

        // Production: expire nonces over time to bound memory.
        return true;
    }
}

16. Anomaly Classification

SBAC defines a standard anomaly taxonomy:

  • Invalid transition attempt
  • Temporal violation
  • Guard failure
  • Enumeration or probing
  • Integrity divergence

Anomalies are first-class security signals.

Anomaly classification is coupled with response policy.

SBAC does not mandate a specific response, but it requires that anomalies be observable and actionable.

Common responses include token revocation, forced re-authentication, progressive trust degradation, and temporary account lockout.

C# example: anomaly types and exception

public enum SbacAnomaly  
{
    InvalidTransitionAttempt,
    TemporalViolation,
    GuardFailure,
    EnumerationOrProbing,
    IntegrityDivergence
}

public sealed class SbacAnomalyException : Exception  
{
    public SbacAnomaly Type { get; }

    public SbacAnomalyException(SbacAnomaly type, string message) : base(message)
        => Type = type;
}

Example: Blocking a Real-World Workflow Bypass

17. Scenario Overview

Consider a common e-commerce checkout flow:

  1. Browse catalog
  2. Select item
  3. Start checkout
  4. Confirm payment

The system uses modern authentication (OAuth or JWT-based access tokens), RBAC for role enforcement, and ABAC for contextual checks such as region, device, or account state.

An attacker does not bypass authentication.

Instead, the attacker successfully exploits a client-side vulnerability (for example, reflected XSS in a product review field) and steals a legitimate user’s access token.

The attacker now possesses a valid, unexpired token issued by the system and begins using it programmatically.


18. Attack Without SBAC

Using the stolen access token, the attacker:

  • presents a valid bearer token issued to a real user
  • satisfies RBAC checks
  • satisfies ABAC checks

Instead of following the intended state progression enforced by the client UI, the attacker directly invokes:

POST /checkout/confirm  

No item has been selected.

No checkout session has been initialized.

No prior server-side state transition has occurred.

From a traditional access-control perspective:

  • authentication passes
  • authorization passes
  • the endpoint exists and is valid

Unless additional ad-hoc checks exist, the request is processed.

This is not an authentication failure.

This is not an authorization failure.

It is a behavioral failure.


19. Same Attack With SBAC

In an SBAC-enabled system, the authoritative interaction graph includes states such as:

  • Browsing
  • CheckoutPending
  • Complete

The transition ConfirmCheckout is defined as valid only from CheckoutPending.

At the time the stolen token is used, the server’s authoritative state for that session is:

Browsing  

The computed ghost is:

Gs = { StartCheckout }  

When the attacker submits ConfirmCheckout, the server evaluates the request against Gs.

The transition is not reachable.

The request is rejected and classified as a behavioral anomaly.

As part of anomaly handling:

  • the access token is immediately invalidated
  • the active session is terminated
  • the legitimate user is required to re-authenticate

This response assumes credential compromise and prioritizes containment over attribution.

This corresponds to the blocked transition path shown in the SBAC diagram, where an out-of-sequence action is rejected before any state mutation occurs.

C# example: anomaly response (revoke token, force re-auth, lockout)

public interface ITokenRevocation  
{
    ValueTask RevokeAsync(string tokenId, CancellationToken ct);
}

public interface IAccountLockout  
{
    ValueTask RegisterAnomalyAsync(string subjectId, SbacAnomaly anomaly, CancellationToken ct);
    ValueTask<bool> ShouldLockoutAsync(string subjectId, CancellationToken ct);
    ValueTask LockoutAsync(string subjectId, TimeSpan duration, CancellationToken ct);
}

public sealed class SbacResponsePolicy  
{
    private readonly ITokenRevocation _revocation;
    private readonly IAccountLockout _lockout;

    public SbacResponsePolicy(ITokenRevocation revocation, IAccountLockout lockout)
    {
        _revocation = revocation;
        _lockout = lockout;
    }

    public async ValueTask HandleAnomalyAsync(ClassifiedClient client, SbacAnomaly anomaly, CancellationToken ct)
    {
        // Always revoke the token used in the anomalous request (credential misuse assumption).
        if (!string.IsNullOrWhiteSpace(client.TokenId))
            await _revocation.RevokeAsync(client.TokenId!, ct);

        // Track anomalies for escalation decisions.
        if (!string.IsNullOrWhiteSpace(client.SubjectId))
        {
            var subject = client.SubjectId!;
            await _lockout.RegisterAnomalyAsync(subject, anomaly, ct);

            if (await _lockout.ShouldLockoutAsync(subject, ct))
                await _lockout.LockoutAsync(subject, duration: TimeSpan.FromMinutes(15), ct);
        }

        // “Force re-auth” is typically implemented by refusing future requests
        // until a fresh token is minted (e.g., 401 + prompt login).
    }
}

20. Why This Matters

This attack is realistic and common:

  • tokens are stolen via XSS, malicious extensions, compromised devices, or leaked logs
  • the attacker does not need to escalate privileges
  • the attacker uses the system exactly as designed, just out of sequence

The request was:

  • authenticated
  • authorized
  • syntactically valid

It was rejected solely because it was not correct in the current state.

SBAC treats this as more than a failed request.

A behavioral anomaly indicates likely credential misuse. As a result:

  • the token is revoked
  • the user is prompted to re-authenticate
  • the event is logged and correlated

Repeated anomalies originating from the same identity, device, or network context may trigger:

  • progressive trust degradation
  • temporary account lockout
  • secondary verification requirements

SBAC does not try to prevent token theft.

It assumes credentials will eventually be compromised.

SBAC ensures that compromised credentials cannot be used to violate system behavior silently.

In SBAC, invalid behavior is not only blocked, it is used as a signal to actively protect the user.


21. Relationship to RBAC and ABAC

RBAC and ABAC still apply.

They determine who may act and under what conditions.

SBAC determines when actions are possible.


22. Limitations

SBAC does not prevent server compromise.

It enforces correctness of client interaction, not the purity of execution.


23. Conclusion

State-Based Access Control formalizes a class of security checks that most systems already attempt informally.

By making interaction state explicit, server-authoritative, and enforceable, SBAC closes the gap between “allowed” and “correct.”

By assuming credential compromise and enforcing correctness at the interaction layer, SBAC shifts security from prevention alone to continuous behavioral enforcement.

Clients do not navigate reality.

They propose inputs.

The server decides what is reality.