Skip to content

Fix NumberFormatException in Webhook.Signature.getTimestamp#1

Open
devin-ai-integration[bot] wants to merge 1 commit intomasterfrom
fix/webhook-timestamp-number-format-exception
Open

Fix NumberFormatException in Webhook.Signature.getTimestamp#1
devin-ai-integration[bot] wants to merge 1 commit intomasterfrom
fix/webhook-timestamp-number-format-exception

Conversation

@devin-ai-integration
Copy link
Copy Markdown

@devin-ai-integration devin-ai-integration bot commented Apr 12, 2026

Why?

Webhook.Signature.getTimestamp() calls Long.parseLong() on the raw timestamp value extracted from the Stripe-Signature header without any error handling. If a malformed header contains a non-numeric, empty, or overflowing timestamp (e.g. t=abc,v1=sig...), the SDK throws an unhandled NumberFormatException instead of the expected SignatureVerificationException.

After this change, malformed timestamps are handled gracefully using the same code path as a missing timestamp — returning -1, which the caller (verifyHeader) already checks and converts into a descriptive SignatureVerificationException.

Related: stripe/stripe-java#2149

What?

  • Wrapped Long.parseLong() in getTimestamp() with a NumberFormatException catch that returns -1 (the existing sentinel for "no timestamp found")
  • Added three test cases in WebhookTest:
    • testNonNumericTimestampt=not_a_number
    • testEmptyTimestampValuet=
    • testOverflowTimestampValuet=99999999999999999999 (exceeds Long.MAX_VALUE)

Reviewer Checklist

  • Verify that returning -1 from the catch is consistent — getTimestamp already returns -1 at the end when no t= key is found, and verifyHeader checks timestamp <= 0 before throwing SignatureVerificationException
  • getTimestamp is private, so verifyHeader is the only caller — no other code paths are affected

See Also

  • stripe/stripe-java#2149 — community PR addressing the same issue
  • Webhook.java:130-135 — the verifyHeader guard that converts -1 into a SignatureVerificationException

Link to Devin session: https://app.devin.ai/sessions/c1b674151bf44bf5beb6dff50488e9d3
Requested by: @kllyjsn


Open with Devin

Webhook.Signature.getTimestamp() calls Long.parseLong() on the raw
timestamp value from the signature header without any error handling.
If a malformed webhook header arrives with a non-numeric timestamp
(e.g. t=abc,v1=sig...), the SDK throws an unhandled
NumberFormatException instead of a proper SignatureVerificationException.

This change wraps the Long.parseLong() call in a try-catch that returns
-1 on NumberFormatException, which the caller (verifyHeader) already
handles by throwing a SignatureVerificationException with a descriptive
message.

Added tests for:
- Non-numeric timestamp values
- Empty timestamp values
- Overflow timestamp values (exceeding Long.MAX_VALUE)

Fixes stripe#2149

Co-Authored-By: Jason Kelley <kllyjsn@gmail.com>
@devin-ai-integration
Copy link
Copy Markdown
Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant