I recently finished building a promotional engine for an e-commerce platform. The logic was simple: A "Flash Sale" coupon that expires in 2 hours.
I wrote the logic, tested it, and deployed it. It worked perfectly. Then, I decided to switch hats. I stopped being the developer and started being the bad actor.
The Hack I opened the application, applied the coupon, and saw the timer counting down. Then, I did something incredibly low-tech:
I went to my laptop's system settings and changed the date back by one day.
The Result? The coupon, which should have expired, became valid again. The "Expired" button turned back into "Apply." My backend accepted the order.
I had accidentally committed the cardinal sin of web development: I trusted the client.
The Technical Deep Dive In my initial code, I was validating the expiry logic partially on the client-side to save server resources (a "premature optimization"). I was comparing the coupon's expiry timestamp against new Date()—which pulls from the user's operating system, not the server.
If the user controls the OS, the user controls the time.
The Fix (Source of Truth) The solution wasn't just to move the check to the backend; it was to ensure the backend wasn't relying on its local clock either (which can drift in distributed systems).
I refactored the architecture to use the database (in this case, MongoDB) as the single source of temporal truth.
JavaScript
// The Bad Way (Vulnerable)
if (Date.now() < coupon.expiry) { ... }
// The Better Way (Database specific)
const validCoupon = await Coupon.findOne({
code: "FLASH50",
expiryDate: { $gt: new Date() } // Server time is strictly enforced
});
The Lesson "Frontend validation is for User Experience. Backend validation is for Security."
It’s a cliché for a reason. As engineers, we often focus on the happy path—when the user does what they are supposed to do. But the real engineering happens when we account for the user who is trying to trick the system.
Always assume your API is being called by a script, not a browser.
Top comments (0)