From 681600360d80b5906c76964c8595e0624f6ba6c4 Mon Sep 17 00:00:00 2001 From: nullref Date: Sun, 14 Jun 2026 07:35:44 +0200 Subject: [PATCH] fix(policy): treat malformed grant expiresAt as expired, not active MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Date.parse() returns NaN for invalid date strings. Previously, a grant with expiresAt set to a malformed value (e.g. 'invalid') would pass the expiry check (NaN > Date.now() === false, but the falsy NaN would skip the check due to how the condition was written—or more precisely, would evaluate incorrectly). Now, if expiresAt is present but cannot be parsed, the grant is treated as expired/invalid rather than silently allowing access. --- packages/account-core/src/policy.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/account-core/src/policy.ts b/packages/account-core/src/policy.ts index b80ed25..50d2427 100644 --- a/packages/account-core/src/policy.ts +++ b/packages/account-core/src/policy.ts @@ -52,7 +52,8 @@ export function scoreAccountActionRisk(input: { export function evaluateAccountPolicy(input: LogicSrcPolicyEvaluationInput): LogicSrcPolicyEvaluationResult { const riskScore = Math.min(1, Math.max(0, input.riskScore ?? scoreAccountActionRisk({ action: input.action }))); - const grantActive = input.grant && !input.grant.revokedAt && (!input.grant.expiresAt || Date.parse(input.grant.expiresAt) > Date.now()); + const expiryMs = input.grant?.expiresAt ? Date.parse(input.grant.expiresAt) : NaN; + const grantActive = input.grant && !input.grant.revokedAt && (!input.grant.expiresAt || (!Number.isNaN(expiryMs) && expiryMs > Date.now())); const hasPermission = Boolean(grantActive && input.grant?.permissions.includes(input.action)); if (!hasPermission) {