L2: Optional nbf/iat Claims Bypass Token Lifetime Ceiling
Severity: LOW
Category: Authentication Weakness
File: src/Spe/Core/Settings/Authorization/SharedSecretAuthenticationProvider.cs
Lines: 282–284
Risk Explanation
The nbf (not-before) and iat (issued-at) claims are only validated when their value is > 0. Since long defaults to 0 when the claim is absent, an attacker can omit both claims to bypass the maximum token lifetime check (which compares exp - iat).
Tokens without iat effectively have no lifetime ceiling, even when MaxTokenLifetimeSeconds is configured. A token with exp set to the year 2099 and no iat would pass all checks.
Practical impact: Low, because the exp check still enforces an absolute expiration. However, MaxTokenLifetimeSeconds becomes ineffective.
Backward Compatibility Warning
The SPE remoting module does NOT include iat by default. In SPE.psm1 line 39:
New-Jwt -Algorithm 'HS256' -Issuer 'SPE Remoting' -Audience ... -Name $Username -SecretKey $SharedSecret -ValidforSeconds 30
Neither -IncludeIssuedAt nor -IssuedAt is passed. Enforcing iat on the server would break all existing SPE remoting clients using the default New-Jwt call.
Implementation Plan
Phase 1: Update the client module (non-breaking)
-
Change New-Jwt.ps1 to include iat by default:
if ($IssuedAt -ne 0) {
$payload['iat'] = $IssuedAt
} else {
$payload['iat'] = [datetimeoffset]::UtcNow.ToUnixTimeSeconds()
}
-
Update SPE.psm1 line 39 to explicitly pass -IncludeIssuedAt.
Phase 2: Enforce on the server (after clients have updated)
-
Require iat only when MaxTokenLifetimeSeconds is configured:
if (MaxTokenLifetimeSeconds > 0 && iat == 0)
{
PowerShellLog.Warn("[Auth] action=authFailed reason=missingIatClaim");
return false;
}
When MaxTokenLifetimeSeconds is 0 (default), tokens without iat are still accepted.
-
Do NOT unconditionally require iat — this would break third-party clients.
Files to modify
| File |
Change |
Phase |
Modules/SPE/New-Jwt.ps1 |
Always include iat by default |
Phase 1 |
Modules/SPE/SPE.psm1 |
Add -IncludeIssuedAt to New-Jwt call |
Phase 1 |
src/Spe/Core/Settings/Authorization/SharedSecretAuthenticationProvider.cs |
Require iat when MaxTokenLifetimeSeconds > 0 |
Phase 2 |
Test Plan
- Token without iat, MaxTokenLifetimeSeconds > 0: Before fix: passes. After fix: rejected.
- Token with valid iat still passes.
- Token without iat, MaxTokenLifetimeSeconds = 0 (disabled): Still passes (backward compat).
- SPE remoting module generates tokens with iat after Phase 1.
- Backward compat test — old client against new server with MaxTokenLifetimeSeconds=0: Works.
L2: Optional nbf/iat Claims Bypass Token Lifetime Ceiling
Severity: LOW
Category: Authentication Weakness
File:
src/Spe/Core/Settings/Authorization/SharedSecretAuthenticationProvider.csLines: 282–284
Risk Explanation
The
nbf(not-before) andiat(issued-at) claims are only validated when their value is> 0. Sincelongdefaults to0when the claim is absent, an attacker can omit both claims to bypass the maximum token lifetime check (which comparesexp - iat).Tokens without
iateffectively have no lifetime ceiling, even whenMaxTokenLifetimeSecondsis configured. A token withexpset to the year 2099 and noiatwould pass all checks.Practical impact: Low, because the
expcheck still enforces an absolute expiration. However,MaxTokenLifetimeSecondsbecomes ineffective.Backward Compatibility Warning
The SPE remoting module does NOT include
iatby default. InSPE.psm1line 39:Neither
-IncludeIssuedAtnor-IssuedAtis passed. Enforcingiaton the server would break all existing SPE remoting clients using the defaultNew-Jwtcall.Implementation Plan
Phase 1: Update the client module (non-breaking)
Change
New-Jwt.ps1to includeiatby default:Update
SPE.psm1line 39 to explicitly pass-IncludeIssuedAt.Phase 2: Enforce on the server (after clients have updated)
Require
iatonly whenMaxTokenLifetimeSecondsis configured:When
MaxTokenLifetimeSecondsis 0 (default), tokens withoutiatare still accepted.Do NOT unconditionally require
iat— this would break third-party clients.Files to modify
Modules/SPE/New-Jwt.ps1iatby defaultModules/SPE/SPE.psm1-IncludeIssuedAttoNew-Jwtcallsrc/Spe/Core/Settings/Authorization/SharedSecretAuthenticationProvider.csiatwhenMaxTokenLifetimeSeconds > 0Test Plan