From 4b38a9d8c8723ceed1139f3b6f4e43cf38d4531c Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Thu, 11 Jun 2026 05:53:11 -0400 Subject: [PATCH] harden(security): freeze RoleCarryingUserIdentity.Roles to a defensive copy Code-review follow-up to T17: copy the roles into a fresh array at construction so a caller mutating the source list cannot retroactively alter a session's granted roles, and so the T18 ack gate's per-invocation .Contains(...) runs over a known-small frozen array. --- .../Security/RoleCarryingUserIdentity.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/Security/RoleCarryingUserIdentity.cs b/src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/Security/RoleCarryingUserIdentity.cs index c46b69f5..29d85fd1 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/Security/RoleCarryingUserIdentity.cs +++ b/src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/Security/RoleCarryingUserIdentity.cs @@ -23,7 +23,11 @@ public sealed class RoleCarryingUserIdentity : UserIdentity public RoleCarryingUserIdentity(UserIdentityToken token, IReadOnlyList roles) : base(token) { - Roles = roles ?? throw new ArgumentNullException(nameof(roles)); + ArgumentNullException.ThrowIfNull(roles); + // Freeze to a defensive copy so a caller mutating the source list can never retroactively + // alter this session's granted roles, and so the gate's per-ack `.Contains(...)` runs over a + // known-small frozen array. + Roles = [.. roles]; } /// The roles the authenticator granted this session, used by downstream permission gates.