A love letter to every dev who's ever git add . at 2am and hoped for the best.
Let's play a game. Raise your hand if you've ever done one of these:
•Hardcoded an API key "just for testing" and forgot about it for six months
•Pushed a .env file because .gitignore was in the other branch
•Left DEBUG = True in production because "it's fine, nobody's looking"
•Used admin / admin123 in a staging environment that turned out to be public
•Copy-pasted a Stack Overflow answer that disabled CORS entirely, "temporarily"
Yeah. Me too. We've all been there. This post isn't about shaming anyone it's about the handful of security habits that actually matter, explained the way a dev would explain them to another dev, minus the compliance speak.
- Secrets Management Is Not Optional, It's Just Annoying Here's the uncomfortable truth: every secret you've ever committed to a public (or "private but actually not") repo is compromised the moment it's pushed. Git history doesn't forget. Deleting the file in the next commit doesn't help the secret is still sitting in the .git folder, waiting for someone to run git log -p.
The fix isn't complicated, it's just a habit change:
Add this before you need it, not after
echo ".env" >> .gitignore
echo "*.pem" >> .gitignore
echo "secrets.json" >> .gitignore
And if you do leak a secret rotate it immediately. Not "add to the backlog." Immediately. A leaked key is a live grenade, not a ticket.
- Your Dependencies Are Someone Else's Code Running in Your Prod npm install pulls in hundreds of packages you've never read a single line of. Most of them are fine. Some of them get compromised, typosquatted, or quietly updated with malicious code by an attacker who bought out a maintainer's account.
This isn't hypothetical paranoia it's happened to some very well-known packages. The defense isn't "never use dependencies," it's:
npm audit
npm audit fix
Run it. Actually read the output. Don't just --force your way past every warning because you're mid-sprint.
- That SQL Query You "Simplified" Is a Time Bomb # please, for the love of all that is holy, no query = f"SELECT * FROM users WHERE email = '{user_input}'"
If you've written this even once, even in a demo, even in code you swore would never touch production
congratulations, you've built a SQL injection vulnerability. It doesn't matter how unlikely it seems that anyone will exploit it. "Unlikely" is not a security control.
this one, always
query = "SELECT * FROM users WHERE email = %s"
cursor.execute(query, (user_input,))
Parameterized queries aren't slower, they aren't harder to write once you're used to them, and they close an entire category of vulnerability that has existed since before most of us were born.
CORS Isn't a Suggestion, It's a Wall
// the "I'll fix it later" special
app.use(cors({ origin: '' }));
We've all shipped this to make a frustrating error go away at 11pm. The problem is that "later" rarely comes, and origin: '' means literally any website on the internet can make authenticated requests to your API on behalf of your users. Lock it down to the origins that actually need access it takes five extra minutes and saves you from an entire category of cross-origin attacks.Logs Are Great, Except When They're Logging Passwords
console.log('User login attempt:', req.body);
Looks harmless. Except req.body often contains the password field, and now it's sitting in plaintext in your logging service, readable by anyone with log access, retained for however long your retention policy says (which is probably "forever, we never checked").
Log what you need to debug. Redact what you don't need to see."It's Just an Internal Tool" Is How Breaches Start
Internal tools get the least security attention and often the most access admin panels, debug endpoints, internal APIs with no auth because "only people on the VPN can reach it." Except VPNs get misconfigured, laptops get stolen, and internal tools become the softest target in the whole stack precisely because nobody treated them like a real attack surface.
If it touches production data, it deserves production-level auth. No exceptions for "it's just internal."
The Actual Point
None of this requires a security degree. It requires treating security the same way you treat any other bug class something you check for by default, not something you bolt on when someone yells at you after an incident. The best security habits are boring, unglamorous, and mostly just... not skipping steps because you're tired.
Ship fast. Just don't ship secrets, unparameterized queries, or wide-open CORS while you're doing it.
What's the security habit that's saved you the most pain?
Drop it in the comments collecting these for round two.
Top comments (0)