Secure defaults
Secure defaults means the configuration you ship is the safe one: debug output off, generic errors, no shared default passwords, security headers on every response, and risky features off until someone enables them. CISA calls this secure by default: resilient against prevalent exploitation techniques out of the box.
Many leaks come from a setting nobody changed, not from code. Express sends stack traces unless NODE_ENV=production, Django's startproject writes DEBUG = True, and Ignition before 2.5.2, Laravel's debug error page, let unauthenticated attackers run code on sites with debug mode on (CVE-2021-3129). Code review often misses environment files and proxy settings; a check of the deployed system sees them.
- Who
- Developers and platform engineers who own the deployment configuration, with AppSec setting the baseline
- When
- Before each release, against the production configuration and the real path through CDN, proxy and application
- How often
- Every deployment, automated; the baseline reviewed when a framework, proxy or feature changes
- You end up with
- A written baseline kept as configuration as code, and a release check that proves headers, error pages and exposed paths
Do this
Write the production baseline down
List each setting that affects security and its production value, per framework and server: Django
DEBUG = False,NODE_ENV=production,ASPNETCORE_ENVIRONMENT=Production, Spring Boot Actuator exposing onlyhealth, nginxautoindex off. Keep it in the repository as configuration as code, so every change is reviewed. NIST SSDF PW.9 asks for this: a secure baseline, implemented as the default and documented for administrators.Turn off debug output and verbose errors
Set each framework's production switch explicitly, even where the default is safe, and add a final error handler that logs the detail with a reference ID and returns only that ID. Check the error pages of the proxy and CDN too. ASVS 5.0 requirement V13.4.2 asks that debug modes be disabled in production, and Django's settings reference says never to deploy with
DEBUGon.Ship only what the service needs
Deploy a clean build directory, never a working tree: no
.git,.env, backups or public source maps. Delete sample apps and default accounts, keep monitoring and API documentation endpoints such as Actuator,pprofand Swagger UI internal, and turn off directory listings and HTTP TRACE. Enforce the same rules at the web server, so a mistake in the build is caught at the edge.Send security headers on every response
Send
Strict-Transport-Security, a nonce- or hash-basedContent-Security-Policywithframe-ancestors,X-Content-Type-Options: nosniff,Referrer-Policy: strict-origin-when-cross-originand aPermissions-Policythat disables unused features; removeX-Powered-Byand version numbers inServer. Roll CSP out in report-only mode first, and set the headers at a layer that also covers 404s, redirects and static files.Make risky options opt-in
For software that customers install or configure, ship no shared default password: have the administrator set one during setup, or issue a one-time setup token. Keep dangerous features off, with a warning that names the risk when someone turns one on. CISA recommends folding hardening-guide steps into the default configuration, and publishing loosening guides that explain the risk of each change instead.
Check every deployment from outside
After each deployment, send requests through the real CDN and proxy: a URL that throws,
/.git/HEAD,/.env, the.mapfile of your main bundle and known admin paths. Inspect the response headers withcurl -sIor Security headers analyzer. Run framework checks such as Django'smanage.py check --deployagainst the production settings in CI, and fail the release on any finding.
Done when
A pre-release check of the deployed system confirms the headers, error pages and exposed paths, and a failure blocks the release.
Mark it in the gap checkCommon mistakes
- Trusting a framework default instead of setting the value. A container image or
.envfile that sets a development environment,APP_DEBUG=trueor noNODE_ENVturns detailed errors back on without any code change. - Checking the application but not the edge. Proxies, CDNs and default error handlers can drop security headers on 404s and redirects, or serve files from the build directory that the application never would.
- Opening Spring Boot Actuator with
include=*so a health check works. It also exposesenv,configpropsandthreaddump; keephealthpublic and put the rest on an internal port behind authentication. - Publishing a hardening guide instead of changing the default. Customers who never read it run the unsafe configuration, and CISA warns that hardening guides can also show attackers which insecure features to look for.
- Removing version banners and calling the work done. Banners only slow reconnaissance; turning off debug output and patching are the controls.
The production switch in common frameworks
Set each one explicitly in the production configuration, even where the default is safe, and make the deployment fail when it is wrong. Checked against each framework's documentation in October 2026.
| Framework | Production setting | Safe if unset? |
|---|---|---|
| Django | DEBUG = False, with ALLOWED_HOSTS set | Yes, but startproject writes DEBUG = True |
| Flask | No --debug or debug=True; serve with a production WSGI server | Yes, but the Werkzeug debugger runs arbitrary code if it is ever on |
| Express | NODE_ENV=production and your own final error handler | No: otherwise the built-in handler sends the stack trace |
| ASP.NET Core | ASPNETCORE_ENVIRONMENT=Production | Yes: with no environment set, Production is the default |
| Spring Boot | Actuator exposure health only; show-values left at never | Yes: only health is exposed over HTTP |
| Laravel | APP_DEBUG=false | Yes in config/app.php, but .env files often set it to true |
| Rails | config.consider_all_requests_local = false | Yes: false by default in production |
| PHP | display_errors = Off, log_errors = On, expose_php = Off | No: display_errors is On without a php.ini, and php.ini-production leaves expose_php = On |
Tools and guides
- Tool: security headers analyzer
- Tool: CSP evaluator
- Ship without debug modes, verbose errors or exposed files
Turn off debug output, publish an allowlisted build and probe each deployment for exposed files and endpoints.
- Configure HTTP security headers from a tested baseline
Send the response headers that make browsers enforce HTTPS, run only your own scripts, refuse hostile framing and keep cookies on one host, then prove they appear on every kind of response.
- Handle failures without leaking internals or weakening controls
Give callers a useful, bounded response while preserving protected diagnostic evidence and safe application state.
- Apply CISA Secure by Design: principles, pledge goals and evidence
What CISA's Secure by Design guidance and pledge ask of software manufacturers as of October 2026, and how to turn each of the three principles, the seven pledge goals and the Product Security Bad Practices into engineering actions, metrics and evidence.
Standards
- NIST SSDF 1.1
- PW.9 Configure Software to Have Secure Settings by Default
- OWASP SAMM 2
- Environment ManagementSecure Deployment
Sources
- CISA and partners: Shifting the Balance of Cybersecurity Risk (Secure by Design and Secure by Default). Revised 25 October 2023.
- OWASP Top 10:2025 A02 Security Misconfiguration. OWASP Top 10:2025.
- OWASP ASVS 5.0.0: V13 Configuration (V13.4 Unintended Information Leakage). Version 5.0.0.
- OWASP HTTP Security Response Headers Cheat Sheet
- OWASP Secure Headers Project
- NIST SP 800-218: Secure Software Development Framework (SSDF) Version 1.1, practice PW.9. February 2022.
- OWASP SAMM: Environment Management
- CVE-2021-3129: Ignition remote code execution in Laravel debug mode (CVE record)
- Django settings reference: DEBUG. Django 6.1.
- Django deployment checklist (check --deploy). Django 6.1.
- Werkzeug documentation: Debugging applications
- Express guide: Error handling
- Microsoft Learn: ASP.NET Core runtime environments. ASP.NET Core 10.0.
- Spring Boot reference: Actuator endpoints
- Laravel 13 documentation: Configuration, debug mode. Laravel 13.x.
- Rails guides: Configuring Rails applications (consider_all_requests_local)
- php-src: php.ini-production