Skip to content

Add explicit algorithm allowlist to JWT validation #1445

@michaellwest

Description

@michaellwest

M4: No Explicit Algorithm Allowlist in JWT Validation

Severity: MEDIUM
Category: Cryptographic Weakness / Algorithm Confusion
File: src/Spe/Core/Settings/Authorization/SharedSecretAuthenticationProvider.cs
Lines: 235–249 (ComputeHash method)


Risk Explanation

The ComputeHash method selects the HMAC algorithm based on the alg claim from the untrusted JWT header:

switch (algorithm)
{
    case "HS256": using (var hmac = new HMACSHA256(key)) { return hmac.ComputeHash(data); }
    case "HS384": using (var hmac = new HMACSHA384(key)) { return hmac.ComputeHash(data); }
    case "HS512": using (var hmac = new HMACSHA512(key)) { return hmac.ComputeHash(data); }
    default: return null;
}

The alg: "none" attack is currently blocked by accidentComputeHash returns null, and the subsequent Convert.ToBase64String(hash) throws a NullReferenceException, caught by the generic catch (Exception) block.

Why this is fragile:

  • If anyone refactors to handle null gracefully, the alg: "none" bypass becomes exploitable.
  • If new algorithms are added (e.g., RS256), an attacker could force algorithm confusion (classic CVE-2015-9235).
  • The defense is not visible or documented — a future developer will not know the NullReferenceException is load-bearing.

Implementation Plan

Add an explicit algorithm allowlist check before the switch statement, and a fail-closed null check after:

private static readonly HashSet<string> AllowedAlgorithms = new HashSet<string>(StringComparer.Ordinal)
{
    "HS256", "HS384", "HS512"
};

private byte[] ComputeHash(string algorithm, byte[] key, byte[] data)
{
    if (!AllowedAlgorithms.Contains(algorithm))
    {
        PowerShellLog.Warn($"[Auth] action=algorithmRejected algorithm={algorithm}");
        return null;
    }
    // ... existing cases ...
}

And after ComputeHash returns:

var hash = ComputeHash(tokenHeader.Alg, keyBytes, inputBytes);
if (hash == null)
{
    PowerShellLog.Warn("[Auth] action=authFailed reason=unsupportedAlgorithm");
    return false;
}
var computedSignature = Convert.ToBase64String(hash);

Files to modify

File Change
src/Spe/Core/Settings/Authorization/SharedSecretAuthenticationProvider.cs Add algorithm allowlist, null check after ComputeHash

Test Plan

  1. Unit test — alg: "none" token: Rejected.
  2. Unit test — unknown algorithms: RS256, ES256, PS256, empty, NONE, hs256 (case-sensitive) — all rejected.
  3. Unit test — allowed algorithms: HS256, HS384, HS512 — all accepted.
  4. Warning is logged when unsupported algorithm is attempted.
  5. Existing JWT authentication tests pass.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions