CWE-1188 applies when a product initializes or sets a resource with a default that the installer, administrator or maintainer is meant to change, but the default is not secure. The assumption is that someone will harden it later. Many people never do.
This hits vendors and application teams alike. It also hits anyone who deploys software, because inherited defaults become your exposure.
How it happens
A default value is the most deployed configuration in the world. If it exposes a service, leaves a variable unset or enables a convenience feature, every installation that skips the hardening step carries the risk.
MITRE's demonstrative example is PHP. A login handler never initializes an authorized variable. With the old register_globals setting enabled, PHP sets that variable from whatever the POST request contains, so an attacker adds authorized=true and gains access without credentials.
// Vulnerable pattern: $authorized is never initialized
// $user and $pass automatically set from POST request
if (login_user($user, $pass)) {
$authorized = true;
}
if ($authorized) {
generatePage();
}
// Fixed: read input explicitly and initialize to the safe value
$user = $_POST['user'];
$pass = $_POST['pass'];
$authorized = false;
if (login_user($user, $pass)) {
$authorized = true;
}
MITRE adds that register_globals should never be enabled and is disabled by default in current PHP versions.
The record lists two other observed cases. CVE-2022-36349 is an insecure default variable initialization in BIOS firmware for a hardware board, which allows denial of service. CVE-2022-42467 is a generic database browser interface whose default mode exposes a web server to the network, allowing queries to the database.
The second one shows the common shape. A tool built for local use listens on all interfaces out of the box.
# Insecure default: reachable from the whole network
app.run(host="0.0.0.0", port=8080)
# Safer default: local only, with opt in for wider exposure
host = os.environ.get("BIND_HOST", "127.0.0.1")
app.run(host=host, port=8080)
What an attacker gains
MITRE says the impact varies widely depending on what the product controls. The examples span authentication bypass, denial of service and direct access to a database. The weakness itself is only a starting state. What matters is what that state protects.
How to find it
MITRE lists automated static analysis (SAST), which can find some instances by modeling data and control flow. Add these checks:
- Grep for uninitialized variables used in security decisions.
- Review default configuration files and flags, and ask what an unmodified install allows.
- Start the product from a clean install and scan its listening ports.
- Treat any setting documented as "change this before production" as a defect to fix in the default.
How to fix it
The record has no formal mitigations, but the description points the way. Do not ship a default that depends on someone changing it later.
- Initialize security relevant variables to the denying value.
- Bind services to local interfaces unless a user explicitly widens that.
- Generate unique credentials at install time instead of shipping shared ones.
- Make the secure choice the one that requires no action.
- Test a clean install in your pipeline, not only a configured one.
Quick check
Why are insecure defaults dangerous even when documented?
Because the default is what most installations actually run. A hardening step that depends on every installer reading the documentation will be skipped often.
What was wrong with the PHP login example?
The authorized variable was never initialized, so with register_globals enabled an attacker could set it through the request. Initializing it to false and reading input explicitly removes the problem.