Skip to content

[BUG] verifyJwt accepts tampered signature — returns publicKey instead of null #761

@adityabhatkar23

Description

@adityabhatkar23

Description

A clear and concise description of what the bug is.

verifyJwt accepts tampered JWTs and returns the publicKey payload instead of returning null when signature verification fails. This causes the unit test tests/auth-jwt.test.ts > JWT helpers > returns null for a tampered signature to fail in CI.

Steps to Reproduce

  1. Ensure JWT_SECRET is set (e.g., via vi.stubEnv in tests).
  2. Run the backend test suite or the specific test file: pnpm test -- tests/auth-jwt.test.ts or run CI.
  3. Observe the failing test: tampered signature still validates and verifyJwt returns { publicKey }.

Expected Behavior

verifyJwt should validate the JWT signature and return null for any verification failure (tampered header/body/signature, expired token, malformed token). For valid tokens, it should return { publicKey } extracted from the token "sub" claim.

Actual Behavior

The current implementation decodes the token without verifying its signature (likely using jwt.decode or manual parsing), so tampered tokens can be accepted and the publicKey returned.

Screenshots

N/A

Environment

  • FlowFi Version: commit 0fd6620 (from CI job)
  • Browser: N/A
  • Operating System: CI Linux runner
  • Node.js Version: (CI-provided)
  • Wallet: N/A

Component

  • Frontend
  • Backend
  • Smart Contracts
  • Documentation
  • Other (please specify)

Logs/Error Messages

FAIL tests/auth-jwt.test.ts > JWT helpers > returns null for a tampered signature
→ expected { publicKey: 'GTESTPUBLICKEY123' } to be null

Excerpt from CI logs:
{"level":"warn","message":"[Auth] JWT_SECRET is less than 32 bytes long; consider using a stronger secret","timestamp":"2026-06-10T05:13:35.646Z"}

Test run summary: 39 passed, 1 failed (tests/auth-jwt.test.ts), total 213 tests. See CI job: https://github.com/LabsCrypt/flowfi/actions/runs/80486592390

Additional Context

Related issue referenced during triage: #760

This is security-sensitive: accepting tampered JWTs is a vulnerability. The test suite already includes checks for tampered header, body, signature, expiry, and malformed tokens.

Possible Solution

Use a JWT library's verify function (for example, jsonwebtoken.verify) with the configured JWT_SECRET so the library validates the signature and standard claims (exp, iat). Do not use jwt.decode for validation-only behavior.

Suggested code change (example):

// backend/src/middleware/auth.ts (or .js)
import jwt from 'jsonwebtoken';

export function verifyJwt(token: string): { publicKey: string } | null {
  try {
    const JWT_SECRET = process.env.JWT_SECRET;
    const decoded = jwt.verify(token, JWT_SECRET) as { sub: string; iat?: number; exp?: number };
    return { publicKey: decoded.sub };
  } catch (error) {
    return null;
  }
}

Acceptance criteria:

  • CI passes with auth-jwt.test.ts (tampered signature test returns null).
  • verifyJwt returns null for tampered/expired/malformed tokens and returns { publicKey } for valid tokens.

Notes:

  • Ensure JWT_SECRET is present in CI and test environments. If the project uses a custom JWT signing/verification scheme, adapt verification to validate the actual algorithm used.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions