I do security stuff at Fortica Cyberguard. Here are five things I keep finding in almost every codebase I look at. Not fancy exploits - just basic mistakes that keep happening.
1. Trusting client-side validation
Client-side validation is for UX, not security. Anyone can open DevTools and bypass it.
Found a file upload that checked extensions in JavaScript. Renamed a shell script to .jpg and uploaded it. Server accepted it, saved it in the web root. That's remote code execution in 30 seconds.
Fix:
Always validate on the server. Check file headers, not extensions. Validate everything - data types, ranges, formats.
javascript// This does nothing for security
if (!email.includes('@')) {
showError('Invalid email');
}
// This actually matters (server-side)
const validator = require('validator');
if (!validator.isEmail(email)) {
return res.status(400).json({ error: 'Invalid email' });
}
2. Secrets in environment variables
Environment variables aren't a security solution. They're just config.
Common issues:
.env files in git (found AWS admin keys this way multiple times)
Secrets in Docker build args (stays in image history - run docker history and see)
Environment dumps in startup logs
Secrets printed in error logs
Better:
Use actual secrets managers (AWS Secrets Manager, Vault, etc.)
For local dev, .env is fine but add to .gitignore
Rotate secrets regularly
dockerfile
# Bad - stays in image history
ARG DATABASE_PASSWORD=super_secret_123
# Better - injected at runtime
ENV DATABASE_PASSWORD=${DATABASE_PASSWORD}
3. Rolling your own auth
Just don't.
There's session management, password resets, rate limiting, token refresh, account enumeration prevention... it gets complex fast.
What happened: Built JWT auth for a side project. Forgot to validate the algorithm field. Someone sent a token with algorithm: none and it validated. Oops.
What to use:
Passport.js, NextAuth, Django auth, Devise - whatever's standard for your stack
Or just use Auth0, Supabase, Firebase
If you must build it, use bcrypt/argon2 and follow OWASP guidelines
Time saved not debugging auth edge cases > cost of these tools.
4. Ignoring dependency vulnerabilities
npm audit shows 47 vulnerabilities. "I'll fix that later."
Spoiler: Nobody fixes it later.
I run dependency scanners on repos during pentests. Companies have public package.json files showing vulnerable packages. Then it's just finding which one is used and exploiting it.
Real examples:
Equifax breach - unpatched Struts vulnerability
Log4Shell - affected thousands who were "too busy" to update
Found auth bypasses in old JWT library versions multiple times
Fix it:
Set up Dependabot or Renovate
Run security checks in CI/CD
Actually update things
bashnpm audit
pip-audit
# Then actually fix them
npm audit fix
5. Logging sensitive data
Found a production API logging full request bodies. Passwords, credit card numbers, everything. Logs were in Splunk, retained for 2 years, accessible to 30 people.
"Oh yeah, forgot to remove debug logs after launch." That was 3 years ago.
Watch out for:
Full request/response objects in logs
Exception handlers dumping everything
Debug logs in production
Authorization headers (Bearer tokens everywhere)
Long retention periods
Better:
javascript// Bad
logger.info('User login:', { user: userObject });
// Better
logger.info('User login:', {
userId: user.id,
timestamp: new Date()
});
Use proper log levels. Debug logs with sensitive data? Fine locally. Production? No.
Quick takeaway
These aren't sophisticated attacks. They're basic stuff that gets skipped when rushing to ship.
About 80% of critical issues I find in pentests are from this list. Not zero-days or nation-state hackers - just missing the basics.
Quick checklist:
- Server-side validation on everything
- Secrets in a proper manager
- Use existing auth libraries
- Update dependencies
- Don't log sensitive data
That's it. Doing these consistently prevents most breaches I've seen.
What else do you see often? Always curious about common patterns.
Top comments (0)