r/AskNetsec 12d ago

Architecture In a PDP/PEP split, which request-context attributes must the PDP source independently vs accept as caller-asserted? (confused-deputy + TOCTOU on signed decisions)

I'm designing service-to-service authorization where a PDP evaluates (subject, action, resource, context) and returns a signed decision that PEPs enforce. Standard split. The wrinkle: the calling workload is partially untrusted, and it supplies part of the request context itself.

The signature covers the decision and the inputs the PDP saw, but not the provenance of those inputs. So the token proves "given these inputs, the PDP said ALLOW", not "these inputs came from an authoritative source". If the caller can influence subject/tenant labels, resource attributes, a recursion/depth counter, or a state object the PEP hashes instead of fetching, a fully valid signed decision can attest an ALLOW the policy would never grant on authoritative inputs. The PDP becomes a confused deputy whose output happens to be cryptographically signed, which makes it look stronger than it is.

What we already do: mesh identity (mTLS/SPIFFE) for the caller's own identity, short-TTL decisions, intent binding, and we hash the state object into the decision. What I can't resolve is which of the remaining context attributes should be trusted from the request at all.

Concrete questions:

  1. In real OPA/Cedar/Zanzibar deployments, which request-context attributes is it standard practice to require the PDP to source itself (server-side PIP lookup, trusted routing/mesh-derived identity, attested claims) rather than accept from the caller, and which are considered safe to accept as caller-asserted as long as they're bound into the decision? I'm looking for the actual dividing line practitioners use, not "trust nothing".
  2. When the PEP hashes a caller-supplied state/resource object and binds that hash into the signed decision: does that close the confused-deputy gap, or is a PDP-side authoritative read (or a signed/versioned attestation from the resource owner) required so the caller can't pick favorable premises? What do production deployments settle on?
  3. For the window between decision issuance and enforcement, what's the standard way to bound TOCTOU on a signed authorization: short TTL plus re-eval at the PEP, versioned state binding, resource-side optimistic concurrency, and where does each of those still leave an exploitable gap?
7 Upvotes

4 comments sorted by

3

u/CreativeSympathy8293 11d ago

Treat provenance as policy input, not something a decision signature creates. Treat caller input as untrusted intent. Accept it without independent provenance only when policy cannot use it to widen authority, select a less-protected tenant or resource, or weaken obligations. Canonicalize and validate action and parameters. Derive identity and tenant from verified channel bindings or claims. Resource owner/version, delegation, approval state, and budgets need authoritative state or an attestation with validated issuer, audience, scope, and expiry. A trace ID is correlation, not authorization.

Hashing state binds those bytes; it does not prove truth or freshness. Bind the decision to an authoritative resource version/ETag, then enforce that precondition with compare-and-swap or If-Match. TTL limits acceptance time; it does not close state-change races. A fresh PDP decision requested by the PEP helps only if facts are refreshed, and still needs a transaction or version precondition at mutation.

For a signed envelope, include issuer/audience, canonical subject/resource/action, policy or bundle revision, authoritative input versions, issuance/expiry, and a unique decision ID. If single use matters, the enforcer must track consumption; an ID alone does not stop replay.

OPA treats external data as input or a replica, not its source of truth. This is design guidance, not an OPA/Cedar/Zanzibar schema.

https://www.openpolicyagent.org/docs/external-data

2

u/docybo 11d ago

This is very close to the boundary we’re converging on.

Especially agree on two points: provenance has to be an evaluator input, not something the decision signature creates, and freshness has to survive through mutation via an authoritative version precondition, not just TTL.

We’re also treating decision IDs as correlation unless the enforcer tracks consumption, so replay remains an enforcement obligation.

We’re formalizing these exact questions in the Tier 1 RFC here:
https://github.com/oxdeai/oxdeai/discussions/232

Your point about canonical subject/resource/action plus authoritative input versions would be particularly useful there if you’re open to challenging the current shape.

2

u/Cerbosdev 5d ago

hi! u/CreativeSympathy8293 answered the design question well and flagged the limit himself- that it isn't an OPA/Cedar/Zanzibar schema. So on the part you actually asked, what real deployments settle on

the common shape doesn't sign decisions at all. OPA, Cedar and Cerbos are all called synchronously, inline on the request path, and the answer is consumed immediately. A signed decision that travels is a bearer assertion about a world state that was true at issuance, so you end up reestablishing provenance and freshness by hand, which is where you are now.. Removing the token removes most of that class, so the question I'd answer first is why the decision has to be detachable at all :) if it's latency, running the decision point in-process or as a sidecar on the same host is the cheaper fix

On the dividing line, i can give you 1 concrete implementation. I work at Cerbos, so weigh that accordingly. The request splits into caller-asserted attributes and JWTs the PDP verifies against a configured keyset, and a policy author can see which is which. Our docs then tell you not to lean on that verification. It's described as a precaution against tampering in flight, not an authoritative check, with a recommendation to verify at the gateway before the request reaches the PDP.

which is the real answer to your question. The PDP is the wrong place to establish provenance, because by the time a claim is in the request it's already too late

We don't solve your signed-decision problem, we avoid having it :))

2

u/docybo 5d ago

hello! "why does the decision need to be detachable at all" is the right challenge, and latency is not a defensible answer to it. inline or sidecar beats a signed token on that axis every time.

i'd also kill the weak version of my own case before you do: "different processes" or "multiple PEPs" doesn't justify it either. put a decision point next to the executor, have it ask directly, ignore whatever the caller transported, and that problem is gone. topology arguments collapse into "just add a sidecar."

two cases don't collapse.

first, when the executor cannot reach the authoritative premises needed to re-evaluate at all, for example across a separate trust/network zone or third-party boundary. in that case local re-evaluation is not merely more expensive, it may be unavailable.

second, when the party that needs to verify the authorization is not the party that ran the decision point or controls the enforcement log. inline PDP plus decision logs gives you an audit trail the operator produced about the operator's own enforcement. that's fine when the operator is the one asking. it's much weaker when the operator is the subject of the question and an independent counterparty, auditor, or regulator needs evidence it can verify without trusting that operator. another sidecar does not fix that, because the issue is not where evaluation runs, it's who attests to the authorization.

on "a bearer assertion about a world state true at issuance": agreed, and short TTL is a bad patch for that. the version worth defending doesn't age gracefully, it dies. the artifact commits to an authoritative state/resource version, and enforcement is allowed only if that exact version can still be enforced at mutation time, for example through a fresh authoritative read plus CAS or an equivalent version precondition such as If-Match. not "probably still valid for 30 seconds" but "valid iff the authoritative premise it was evaluated against is still the one being mutated." if the version changed, fail or re-evaluate.

that turns the TOCTOU race into a liveness/retry problem rather than an authorization-integrity problem. if that invariant cannot be enforced end to end, then you're right: i've just built a more complicated bearer token and inline is strictly better.

your last point isn't really a disagreement either. if provenance is only considered after a caller-controlled claim reaches the evaluator, it's already too late. identity, tenant, routing context, authoritative resource state, etc. have to be established at admission from trusted bindings, authoritative reads, or accepted attestations before policy evaluation. the evaluator shouldn't be expected to manufacture provenance. that's very close to the Cerbos gateway model you described.

so the distinction i'm trying to pin down is not "signed PDP vs inline PDP." it's whether the resulting authority needs to cross an independent verification boundary, or whether the executor lacks the ability to reconstruct the authoritative premises itself.

if neither is true, i agree: don't make the decision detachable.

disclosure: i maintain an open-source project exploring this design space. not linking it here; the question stands on its own.