Skip to content

[P2][Robustness] JWT Verifier should handle non-string alg headers without runtime errors #313

Description

@baixiangcpp

Summary

JWT Verifier assumes the decoded JWT header alg value is a string. A malformed token with a non-string alg value can cause runtime errors because classifyJwtVerificationAlgorithm() calls .toLowerCase() on the supplied value.

This is a robustness issue for a tool that processes untrusted pasted tokens.

Why this matters

Users paste arbitrary JWT-like strings, including malformed tokens from logs, bug reports, test fixtures, or attacks. A verifier should classify malformed/unsupported algorithms as actionable output, not throw a runtime error or bypass shared action feedback.

This also compounds the fire-and-forget action issue: the page currently starts verify() with void verify(), so an async runtime error can avoid the shared ToolActionBar failure path.

Current behavior

Relevant code:

  • src/features/tools/jwt-verifier/page.tsx
    • const alg = h?.alg as string || "unknown"
    • setVerifyResult(await verifyJwtSignature(token, secret, alg))
  • src/features/tools/jwt-verifier/logic.ts
    • classifyJwtVerificationAlgorithm(algorithm: string) calls algorithm.toLowerCase().

If the decoded header is:

{ "alg": 123 }

or:

{ "alg": { "name": "HS256" } }

then the runtime value passed as algorithm is not a string.

Expected behavior

Malformed/non-string alg should produce a stable unsupported/malformed status, for example:

{status: "unsupported",algorithm: "non-string alg"}

or a distinct status:

{status: "malformed",message: "JWT header alg must be a string."}

The UI should display an actionable warning rather than throwing.

Suggested implementation plan

  1. Normalize the decoded alg value before passing it to verification:
constrawAlg=h?.algconstalg=typeofrawAlg==="string" ? rawAlg : "unknown"
  1. Make classifyJwtVerificationAlgorithm() defensive against unknown input, or keep its type narrow and enforce normalization at the callsite.
  2. Consider adding a malformed result status for non-string alg.
  3. Return the async verify Promise through ToolActionBar as part of the related action-state issue.
  4. Add tests:
    • classifyJwtVerificationAlgorithm or verifyJwtSignature does not throw for non-string runtime values if exposed defensively;
    • page-level verification of a token with { "alg": 123 } shows unsupported/malformed guidance;
    • unsupported asymmetric algorithms still show unsupported guidance;
    • alg: none still shows unsigned warning.

Acceptance criteria

  • JWT Verifier does not throw when alg is missing, non-string, or malformed.
  • Non-string alg produces actionable unsupported/malformed UI guidance.
  • Existing HS256/HS384/HS512 valid/invalid behavior still works.
  • Existing alg: none behavior still shows the unsigned warning.
  • npm test -- --run tests/unit/jwt-verifier-claims.test.ts tests/component/jwt-verifier-page.test.tsx passes.
  • npm run check:types and npm run lint pass.

Related code pointers

  • src/features/tools/jwt-verifier/page.tsx
  • src/features/tools/jwt-verifier/logic.ts
  • tests/unit/jwt-verifier-claims.test.ts
  • tests/component/jwt-verifier-page.test.tsx
  • related action-state issue for fire-and-forget verify handlers

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions