A small command-line tool that reads Java code and flags webhook handlers that act on a message before checking it's actually real.
A webhook is just a message one company's server sends to yours — like Stripe pinging your app to say "that payment went through, ship the order."
The catch: that URL is public, so anyone on the internet can send your app that message. The only thing proving it's really from Stripe is a signature — think of it like a wax seal on a letter. So the rule is simple: check the seal before you do anything.
This tool catches the case where the code does the important thing first and checks the seal after:
capture(payment); // marks the order paid...
if (!verifySignature(payload, signature)) { // ...then checks the seal, too late
throw new SecurityException("bad signature");
}
A faker can send a "payment worked!" message with a garbage seal:
curl -X POST https://shop.example.com/webhook/payment \
-H "Stripe-Signature: totally-fake" \
-d '{"type":"payment_succeeded","amount":100}'
The app charges ahead and marks the order paid before it ever looks at the seal. The check is right there in the code — it just runs one line too late to help.
gradlew.bat build
java -jar build\libs\webhookcheck.jar .\examples
⚠ NoVerificationController.java:18 orderHook — no signature verification found
⚠ ResultIgnoredController.java:17 handleWebhook — signature checked but result is ignored
⚠ TooLateController.java:18 handleWebhook — payload processed before signature check
✓ 6 handlers checked, 3 issues
(If the ⚠ shows as a box on Windows, run chcp 65001 first.)
A handler is safe only when the seal check runs — and stops everything on failure — before any important action. Three ways that breaks:
- No check at all — the message is trusted blindly.
- Check too late — the check is there, but something important already ran.
- Check ignored — the seal is checked, but the code doesn't stop on a bad one.
I threw tricky code at my own tool to see where it breaks — better to know the gaps than pretend they aren't there:
- Check throws its own error instead of using an
if→ false alarm. - Check done by hand (comparing the codes directly) → missed, because nothing is literally named "verify."
- Checking handed off to a helper function → missed; the tool reads one function at a time.
- A skipped check where the action uses a word I didn't list → stays quiet.
The first three are false alarms; the last is a real miss. Fixing all four is the plan for v2.
- Walk the folder and read every
.javafile into a tree the tool can inspect (using JavaParser — this is what lets it reason about the order of the code, which plain text search can't). - Find the webhook handlers.
- For each one, check that a seal check runs and stops on failure before any important action.
- Print what's wrong.
gradlew.bat test
The tests point the tool at a set of example handlers — three broken, three safe — and check it flags exactly the broken ones and stays quiet on the safe ones.
Java 17 or newer. No need to install Gradle — the included gradlew.bat handles it.