Staging and development environments are created quickly, secured casually, and forgotten permanently. They frequently contain the same data as production with none of its controls, and they are trivially discoverable.

How they are found

Predictable naming — staging, dev, test, uat, beta as subdomains. Certificate transparency logs, which record every certificate issued. Search engine indexing where nobody added a directive. Links in public code repositories or documentation. None of this requires effort; it is enumerated automatically.

What makes them dangerous

  • Real customer data copied in for realistic testing, now in an environment nobody monitors.
  • Debug modes exposing stack traces, configuration, and sometimes credentials.
  • Default or shared credentials that were never changed.
  • Outdated code with vulnerabilities fixed in production but not here.
  • Connections to production services, making the weak environment a route into the strong one.

Use data that is not real

The single highest-value change is not copying production data. Generated or masked datasets remove the consequence of exposure entirely. Where realistic data is genuinely required for a specific test, mask the identifying fields, restrict who can access it, and delete it when the test concludes.

Basic controls for every non-production environment

  • Authentication in front of the whole environment — HTTP basic auth is sufficient and takes minutes.
  • A robots directive and noindex headers, though these are not a security control on their own.
  • Network restriction to your addresses or VPN where practical.
  • No credentials for production services, ever.
  • An owner and a decommission date.

Decommission deliberately

When a project ends, remove the environment and its DNS record. Leaving it running produces an unpatched, unmonitored system on your domain indefinitely — and, once the underlying service is cancelled, a dangling DNS record available for subdomain takeover.