Summary
ManagerImpl.onPostureDataUpdate (router/state/manager.go) re-evaluates access on a posture-data change for only the connId-keyed mux-sink dial conns. It does not re-check:
- SDK-hosted xgress dial circuits (
edgeClientConn.xgCircuits), or
- hosted bind terminators (the hosted-services registry).
As a result, when a device falls out of posture compliance (MFA timeout, OS / domain / process posture failure, etc.), its active xgress dial circuits and its hosted terminators are not torn down. Posture-based access revocation is incomplete.
Impact (security)
An identity that no longer satisfies a service's dial/bind posture checks continues to:
- reach the service over active SDK-hosted xgress dial circuits, and
- host the service via its terminators,
until an unrelated event (a policy change, or the connection dropping) cleans up. Policy-driven revocation (NotifyServiceChange -> handleDialAccessLost / handleBindAccessLost) is unaffected; only posture-driven revocation has the gap.
Affected
Verified at tag v2.0.0. Present wherever router-side RouterDataModel posture revalidation and SDK-hosted xgress coexist. At v2.0.0, onPostureDataUpdate iterates only GetConnIdToSinks() (mux sinks) and reads connState.ServiceSessionToken.ServiceId; xgCircuits / xgEdgeForwarder already exist but are never visited, and the hosted-terminator registry is never consulted on a posture change.
Fix
Extend onPostureDataUpdate to re-evaluate:
- dial access over the full circuit set (mux sinks and
xgCircuits) via the existing IterateCircuits / edgeCircuit abstraction, closing non-compliant circuits with CloseForDialAccessLoss; and
- bind access over the connection's hosted terminators, closing non-compliant ones through the bind-access-loss path (
ensureSdkCloseSent + terminator.close).
This unifies posture-driven revocation with the existing policy-driven revocation paths. The connect-v2 branch already contains this fix (a unified onPostureDataUpdate plus ConnProvider.IterateDialCircuits / IterateBindTerminators); this issue tracks the targeted 2.0.x backport, excluding the connect-v2-only sessionless / OIDC changes (which do not apply to 2.0.x).
Summary
ManagerImpl.onPostureDataUpdate(router/state/manager.go) re-evaluates access on a posture-data change for only the connId-keyed mux-sink dial conns. It does not re-check:edgeClientConn.xgCircuits), orAs a result, when a device falls out of posture compliance (MFA timeout, OS / domain / process posture failure, etc.), its active xgress dial circuits and its hosted terminators are not torn down. Posture-based access revocation is incomplete.
Impact (security)
An identity that no longer satisfies a service's dial/bind posture checks continues to:
until an unrelated event (a policy change, or the connection dropping) cleans up. Policy-driven revocation (
NotifyServiceChange->handleDialAccessLost/handleBindAccessLost) is unaffected; only posture-driven revocation has the gap.Affected
Verified at tag
v2.0.0. Present wherever router-side RouterDataModel posture revalidation and SDK-hosted xgress coexist. Atv2.0.0,onPostureDataUpdateiterates onlyGetConnIdToSinks()(mux sinks) and readsconnState.ServiceSessionToken.ServiceId;xgCircuits/xgEdgeForwarderalready exist but are never visited, and the hosted-terminator registry is never consulted on a posture change.Fix
Extend
onPostureDataUpdateto re-evaluate:xgCircuits) via the existingIterateCircuits/edgeCircuitabstraction, closing non-compliant circuits withCloseForDialAccessLoss; andensureSdkCloseSent+terminator.close).This unifies posture-driven revocation with the existing policy-driven revocation paths. The
connect-v2branch already contains this fix (a unifiedonPostureDataUpdateplusConnProvider.IterateDialCircuits/IterateBindTerminators); this issue tracks the targeted 2.0.x backport, excluding the connect-v2-only sessionless / OIDC changes (which do not apply to 2.0.x).