Use of Invariant Value in Dynamically Changing Context
Description
Use of Invariant Value in Dynamically Changing Context is a vulnerability that occurs when a product uses a constant value, name, or reference in contexts where that value can or should vary across different environments, instances, or time periods. This includes hardcoded passwords that remain the same across all installations, fixed cryptographic keys embedded in binaries, constant file paths or addresses that may differ between systems, and other static values used where dynamic, per-instance values are security-appropriate. The invariant nature means that compromising the value in one context compromises all contexts using that same constant value.
Risk
Invariant values create widespread vulnerabilities because a single discovery compromises all affected systems. Hardcoded passwords revealed through reverse engineering provide universal access to all installations of the software. Cryptographic keys embedded in binaries enable attackers to decrypt communications or forge signatures for all users. Fixed file paths or memory addresses may not exist or may have different contents on different systems, causing crashes or enabling exploitation. The risk is amplified by the difficulty of remediation - invariant values compiled into binaries cannot be changed without updating the software itself. Default values that should be configured per-deployment but remain unchanged create similar exposure. Historical incidents have demonstrated massive impact when hardcoded credentials are discovered in widely-deployed software.
Solution
Eliminate invariant values in security-sensitive contexts. Generate cryptographic keys at runtime or during installation for each instance. Require administrators to set passwords during deployment rather than providing defaults. Use configuration files, environment variables, or secure key management systems for values that vary between installations. When defaults are necessary, make them obviously insecure (forcing configuration) or generate them randomly per-instance. For code addresses or paths, use dynamic resolution appropriate to the runtime environment. Conduct code reviews to identify hardcoded values and replace them with properly configured or generated alternatives. Implement automated scanning for hardcoded credentials in source code.
Common Consequences
| Impact | Details |
|---|---|
| Access Control | Scope: Access Control Hardcoded credentials provide universal backdoor access to all installations. Attackers discovering the credential can access every system using that software. |
| Confidentiality | Scope: Confidentiality Fixed cryptographic keys enable decryption of data across all instances. Attackers can intercept and decrypt communications for any user. |
| Availability | Scope: Availability Fixed memory addresses or paths may cause crashes on systems with different memory layouts or file system structures. |
Example Code
Vulnerable Code (C/Java)
The following examples demonstrate use of invariant values:
// Vulnerable: Invariant values in C
#include <stdio.h>
#include <string.h>
// Vulnerable: Hardcoded diagnostic password
#define DIAGNOSTIC_PASSWORD "DiagAdmin2024"
int vulnerable_check_diagnostic_access(const char *password) {
// Vulnerable: Same password for all installations
if (strcmp(password, DIAGNOSTIC_PASSWORD) == 0) {
return 1; // Access granted
}
return 0;
}
// Vulnerable: Fixed encryption key
static const unsigned char ENCRYPTION_KEY[] = {
0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c
};
void vulnerable_encrypt(unsigned char *data, size_t len) {
// Vulnerable: Key is the same in every binary
for (size_t i = 0; i < len; i++) {
data[i] ^= ENCRYPTION_KEY[i % sizeof(ENCRYPTION_KEY)];
}
}
// Vulnerable: Fixed memory address
typedef void (*FunctionPointer)(void);
void vulnerable_fixed_address() {
// Vulnerable: Address may not be valid on all systems
FunctionPointer func = (FunctionPointer)0x00401000;
func(); // May crash or execute arbitrary code
}
// Vulnerable: Fixed file path
#define CONFIG_PATH "/opt/myapp/config.conf"
FILE* vulnerable_open_config() {
// Vulnerable: Path may not exist on all systems
return fopen(CONFIG_PATH, "r");
}
// Vulnerable: Fixed API key
const char *API_KEY = "sk_live_51H2x3y4z5a6b7c8d9e0f1g2h3";
void vulnerable_api_call() {
// Vulnerable: Same API key everywhere
make_api_request(API_KEY);
}
// Vulnerable: Invariant values in Java
public class VulnerableInvariant {
// Vulnerable: Hardcoded password
private static final String ADMIN_PASSWORD = "admin123";
public boolean vulnerableCheckAdmin(String password) {
// Vulnerable: Same password for all deployments
return password.equals(ADMIN_PASSWORD);
}
// Vulnerable: Fixed encryption key
private static final byte[] ENCRYPTION_KEY = {
(byte)0x00, (byte)0x01, (byte)0x02, (byte)0x03,
(byte)0x04, (byte)0x05, (byte)0x06, (byte)0x07,
(byte)0x08, (byte)0x09, (byte)0x0a, (byte)0x0b,
(byte)0x0c, (byte)0x0d, (byte)0x0e, (byte)0x0f
};
public byte[] vulnerableEncrypt(byte[] data) throws Exception {
// Vulnerable: Key is constant across all instances
SecretKeySpec keySpec = new SecretKeySpec(ENCRYPTION_KEY, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
return cipher.doFinal(data);
}
// Vulnerable: Fixed database credentials
private static final String DB_URL = "jdbc:mysql://localhost/app";
private static final String DB_USER = "appuser";
private static final String DB_PASS = "AppP@ss2024";
public Connection vulnerableGetConnection() throws SQLException {
// Vulnerable: Credentials same everywhere
return DriverManager.getConnection(DB_URL, DB_USER, DB_PASS);
}
// Vulnerable: Fixed secret key for JWT
private static final String JWT_SECRET = "mySecretKey12345";
public String vulnerableCreateToken(String user) {
// Vulnerable: All tokens signed with same key
return createJwt(user, JWT_SECRET);
}
// Vulnerable: Fixed file location
private static final String LOG_PATH = "/var/log/myapp/app.log";
public void vulnerableLog(String message) throws IOException {
// Vulnerable: Path may not exist
Files.write(Paths.get(LOG_PATH), message.getBytes(),
StandardOpenOption.APPEND);
}
}
# Vulnerable: Invariant values in Python
import os
# Vulnerable: Hardcoded credentials
ADMIN_USERNAME = "admin"
ADMIN_PASSWORD = "SuperSecret123"
def vulnerable_authenticate(username, password):
# Vulnerable: Same credentials for all installations
return username == ADMIN_USERNAME and password == ADMIN_PASSWORD
# Vulnerable: Fixed encryption key
ENCRYPTION_KEY = b'0123456789abcdef'
def vulnerable_encrypt(data):
from Crypto.Cipher import AES
# Vulnerable: Key is constant everywhere
cipher = AES.new(ENCRYPTION_KEY, AES.MODE_ECB)
return cipher.encrypt(data)
# Vulnerable: Fixed API endpoint
API_ENDPOINT = "https://api.example.com/v1"
API_KEY = "fixed_api_key_12345"
def vulnerable_api_call():
# Vulnerable: Same key for all users
import requests
return requests.get(API_ENDPOINT, headers={"Authorization": API_KEY})
# Vulnerable: Fixed file paths
CONFIG_FILE = "/etc/myapp/config.json"
DATA_DIR = "/var/lib/myapp/data"
def vulnerable_load_config():
# Vulnerable: Paths may not exist on all systems
with open(CONFIG_FILE, 'r') as f:
return json.load(f)
# Vulnerable: Fixed salt for password hashing
PASSWORD_SALT = b'constant_salt_value'
def vulnerable_hash_password(password):
import hashlib
# Vulnerable: Same salt for all passwords
return hashlib.pbkdf2_hmac('sha256', password.encode(),
PASSWORD_SALT, 100000)
Fixed Code (C/Java)
// Fixed: Dynamic values in C
#include <stdio.h>
#include <stdlib.h>
#include <openssl/rand.h>
// Fixed: Password from configuration
char* secure_get_diagnostic_password() {
// Fixed: Read from environment or config file
char *password = getenv("DIAGNOSTIC_PASSWORD");
if (password == NULL) {
fprintf(stderr, "DIAGNOSTIC_PASSWORD not configured\n");
exit(1);
}
return password;
}
// Fixed: Generate key at runtime
int secure_generate_key(unsigned char *key, size_t len) {
// Fixed: Unique key per installation
return RAND_bytes(key, len) == 1 ? 0 : -1;
}
// Fixed: Read key from secure storage
int secure_load_key(const char *key_file, unsigned char *key, size_t len) {
// Fixed: Key stored externally, per-installation
FILE *f = fopen(key_file, "rb");
if (!f) return -1;
size_t read = fread(key, 1, len, f);
fclose(f);
return read == len ? 0 : -1;
}
// Fixed: Dynamic function resolution
typedef void (*FunctionPointer)(void);
FunctionPointer secure_get_function(const char *name) {
// Fixed: Dynamic lookup appropriate to platform
void *handle = dlopen(NULL, RTLD_LAZY);
return (FunctionPointer)dlsym(handle, name);
}
// Fixed: Configurable paths
char* secure_get_config_path() {
// Fixed: Allow override via environment
char *path = getenv("MYAPP_CONFIG_PATH");
if (path) return path;
// Default based on platform
#ifdef _WIN32
return "C:\\ProgramData\\MyApp\\config.conf";
#else
return "/etc/myapp/config.conf";
#endif
}
// Fixed: API key from secure storage
char* secure_get_api_key() {
// Fixed: From environment or secrets manager
return getenv("API_KEY");
}
// Fixed: Dynamic values in Java
import java.security.SecureRandom;
import java.nio.file.*;
import javax.crypto.*;
import javax.crypto.spec.*;
public class SecureInvariant {
// Fixed: Password from configuration
public boolean secureCheckAdmin(String password) {
// Fixed: Read expected password from config
String adminPassword = System.getenv("ADMIN_PASSWORD");
if (adminPassword == null) {
throw new SecurityException("ADMIN_PASSWORD not configured");
}
// Fixed: Constant-time comparison
return MessageDigest.isEqual(
password.getBytes(), adminPassword.getBytes());
}
// Fixed: Key from secure storage or generated per-installation
public byte[] secureGetEncryptionKey() throws Exception {
// Fixed: Load from key store or generate
String keyPath = System.getenv("ENCRYPTION_KEY_FILE");
if (keyPath != null) {
return Files.readAllBytes(Paths.get(keyPath));
}
// Or generate and store
byte[] key = new byte[32];
SecureRandom.getInstanceStrong().nextBytes(key);
return key;
}
// Fixed: Database credentials from environment
public Connection secureGetConnection() throws SQLException {
String dbUrl = System.getenv("DB_URL");
String dbUser = System.getenv("DB_USER");
String dbPass = System.getenv("DB_PASSWORD");
if (dbUrl == null || dbUser == null || dbPass == null) {
throw new SQLException("Database configuration incomplete");
}
return DriverManager.getConnection(dbUrl, dbUser, dbPass);
}
// Fixed: JWT secret from secure configuration
public String secureCreateToken(String user) throws Exception {
String jwtSecret = System.getenv("JWT_SECRET");
if (jwtSecret == null) {
throw new SecurityException("JWT_SECRET not configured");
}
// Ensure minimum length
if (jwtSecret.length() < 32) {
throw new SecurityException("JWT_SECRET too short");
}
return createJwt(user, jwtSecret);
}
// Fixed: Configurable file paths
public void secureLog(String message) throws IOException {
String logPath = System.getProperty("app.log.path",
System.getenv("MYAPP_LOG_PATH"));
if (logPath == null) {
logPath = System.getProperty("java.io.tmpdir") + "/myapp.log";
}
Files.write(Paths.get(logPath), message.getBytes(),
StandardOpenOption.CREATE, StandardOpenOption.APPEND);
}
}
# Fixed: Dynamic values in Python
import os
import secrets
# Fixed: Credentials from environment
def secure_authenticate(username, password):
# Fixed: Read from environment
admin_user = os.environ.get('ADMIN_USERNAME')
admin_pass = os.environ.get('ADMIN_PASSWORD')
if not admin_user or not admin_pass:
raise ValueError("Admin credentials not configured")
# Fixed: Constant-time comparison
import hmac
user_match = hmac.compare_digest(username, admin_user)
pass_match = hmac.compare_digest(password, admin_pass)
return user_match and pass_match
# Fixed: Key from file or generated per-installation
def secure_get_encryption_key():
key_file = os.environ.get('ENCRYPTION_KEY_FILE')
if key_file and os.path.exists(key_file):
with open(key_file, 'rb') as f:
return f.read()
# Generate if not exists
key = secrets.token_bytes(32)
return key
# Fixed: API configuration from environment
def secure_api_call():
import requests
api_endpoint = os.environ.get('API_ENDPOINT')
api_key = os.environ.get('API_KEY')
if not api_endpoint or not api_key:
raise ValueError("API configuration not set")
return requests.get(api_endpoint, headers={"Authorization": api_key})
# Fixed: Configurable paths
def secure_get_config_path():
# Fixed: Allow override
config_path = os.environ.get('MYAPP_CONFIG_PATH')
if config_path:
return config_path
# Platform-appropriate default
import platform
if platform.system() == 'Windows':
return os.path.join(os.environ.get('PROGRAMDATA', 'C:\\ProgramData'),
'MyApp', 'config.json')
else:
return '/etc/myapp/config.json'
# Fixed: Unique salt per password
def secure_hash_password(password):
import hashlib
# Fixed: Generate unique salt per password
salt = secrets.token_bytes(16)
hash_value = hashlib.pbkdf2_hmac('sha256', password.encode(),
salt, 100000)
return salt + hash_value # Store both together
The fix uses environment variables, configuration files, or runtime generation for values that should vary between installations.
Exploited in the Wild
Hardcoded Passwords (Various)
Numerous products have been compromised through hardcoded diagnostic or administrative passwords discovered through reverse engineering.
Browser Component Fixed Paths (CVE-2002-0980)
A browser component wrote error messages to predictable locations, allowing attackers to process content in less-restrictive security contexts.
Tools to Test/Exploit
-
TruffleHog — Scans for hardcoded secrets in code.
-
git-secrets — Prevents committing secrets to repositories.
-
Strings — Extracts strings from binaries to find hardcoded values.
CVE Examples
- CVE-2002-0980 — Browser writing to predictable locations.
References
-
MITRE Corporation. "CWE-344: Use of Invariant Value in Dynamically Changing Context." Common Weakness Enumeration. https://cwe.mitre.org/data/definitions/344.html
-
OWASP Foundation. "Cryptographic Storage Cheat Sheet." https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html
-
CWE-798. "Use of Hard-coded Credentials." https://cwe.mitre.org/data/definitions/798.html