Juicy Shop

← All lessons

Security Misconfiguration

ConfigurationA05:2021 – Security Misconfigurationintermediate10 min

Most breaches don't need a clever exploit — just a default password, a verbose error, or an exposed admin panel. Learn the common misconfigurations and how secure-by-default settings close them.

The default-and-forgot problem

Frameworks, databases, and cloud services ship with permissive defaults to make getting started easy: sample accounts, debug modes, open ports, world-readable buckets. Security misconfiguration is the gap between 'works on my machine' and 'hardened for production'. The fix is a repeatable hardening process applied to every environment, not a one-off checklist someone runs by hand.

Verbose errors and stack traces

A stack trace returned to the browser tells an attacker your framework, versions, file paths, and sometimes secrets or SQL. In production, log the full error server-side and return a generic message with a correlation id to the client. Disable debug endpoints, directory listings, and detailed error pages before you ship.

Security headers and CORS

Missing response headers are a classic misconfiguration. Set a strict Content-Security-Policy, X-Content-Type-Options: nosniff, and a sensible Referrer-Policy; enable HSTS. For CORS, never reflect arbitrary Origins or use Access-Control-Allow-Origin: * together with credentials — allow-list the exact origins you trust.

Least functionality

Reduce attack surface: remove unused features, sample apps, and default accounts; change every default credential; close ports you don't need; and don't expose internal admin tools to the public internet. The fewer doors exist, the fewer can be left unlocked.

Insecure vs secure

✗ insecure
const app = express();
app.use(errorhandler()); // full stack traces to client
app.use(cors({ origin: true, credentials: true }));
// reflects ANY origin and allows credentials

Stack traces leak internals to attackers, and reflecting any Origin with credentials lets any site make authenticated cross-origin calls.

✓ secure
const app = express();
app.use(helmet()); // sets CSP, HSTS, nosniff, etc.
app.use(cors({ origin: ALLOWED_ORIGINS, credentials: true }));
app.use((err, _req, res, _next) => {
  log.error(err);
  res.status(500).json({ id: correlationId() });
});

Helmet applies secure headers, CORS is restricted to an explicit allow-list, and clients get a generic error with a correlation id instead of a stack trace.

Key takeaways

  • Permissive defaults, not exotic exploits, cause many breaches.
  • Never return stack traces to clients in production.
  • Set security headers (CSP, HSTS, nosniff) and lock down CORS to an allow-list.
  • Remove unused features, sample apps, and default credentials.
  • Harden every environment with a repeatable, automated process.

Knowledge check

Further reading