Use the framework as intended, it protects you. Break from patterns - raw queries, manual HTML - you lose protections.
XSS protection
| Framework | Default | Gap |
|---|---|---|
| React/Next.js | JSX auto-escapes | dangerouslySetInnerHTML; href/src don't validate schemes |
| Vue/Nuxt | {{ }} auto-escapes | v-html renders raw |
| Angular | Sanitises DOM bindings | bypassSecurityTrustHtml() |
| Django | Templates auto-escape | ` |
| Rails ERB | <%= %> auto-escapes | raw() and html_safe |
| Thymeleaf | th:text escapes | th:utext unescaped |
SQL injection
| Framework | Default | Gap |
|---|---|---|
| Django ORM | Parameterised | raw(), extra() |
| ActiveRecord | Parameterised | find_by_sql, where("name = '#{name}'") |
| SQLAlchemy | Parameterised | text() with formatting |
| Sequelize | Parameterised | sequelize.query() misused |
| Prisma | Parameterised (tagged-template $queryRaw) | $queryRawUnsafe, or $queryRaw built by string concatenation |
CSRF
| Framework | Default | Gap |
|---|---|---|
| Django | Middleware on | @csrf_exempt |
| Rails | protect_from_forgery on | API often skips |
| Next.js/Express | No built-in | Add yourself |
Auth
| Framework | Default |
|---|---|
| Django | Built-in auth, sessions, CSRF |
| Rails | Devise common (not built-in) |
| Next.js | No built-in (NextAuth.js common) |
| Express | No built-in (Passport.js common) |
Node/Express = you assemble from components = more misconfiguration risk.
Security headers
Most frameworks don't set HSTS, CSP, X-Frame-Options by default. Add via middleware (Django SecurityMiddleware, Helmet.js for Express).
File uploads
No framework provides safe upload handling by default. Validate content, sanitise filenames, store outside web root.
Debug mode
Never run debug in prod. Change default secrets. Restrict admin endpoints.
The takeaway
Know what your framework does by default. Know the escape hatches. Know what you add yourself. Most dangerous assumption: the framework handles everything.
