Use of Hard-coded, Security-relevant Constants
Description
Use of Hard-coded, Security-relevant Constants is a vulnerability where a product uses hard-coded constants instead of configurable values for security-critical parameters. This includes hard-coded cryptographic keys, salts, initialization vectors, algorithm identifiers, iteration counts, key sizes, timeout values, and other security-relevant parameters. When these values are embedded directly in code, they become difficult to change, may be exposed through reverse engineering, and create consistency issues across deployments where different security configurations might be needed.
Risk
Hard-coded security constants create significant vulnerabilities. Cryptographic keys embedded in code can be extracted through reverse engineering, decompilation, or source code leaks, compromising all systems using that key. Hard-coded salts eliminate the uniqueness benefit that salts provide, making rainbow table attacks feasible. Fixed iteration counts may become insufficient as computing power increases but cannot be updated without code changes. Hard-coded timeouts may be inappropriately long or short for different deployment environments. When security constants are discovered, changing them requires code updates, testing, and deployment rather than simple configuration changes, leading to delayed responses to security incidents.
Solution
Externalize all security-relevant constants to configuration files, environment variables, or secure parameter stores. Use key management systems for cryptographic keys. Generate unique salts per operation rather than using fixed values. Make iteration counts and key sizes configurable with secure defaults. Store security timeouts in configuration that can be adjusted per environment. When constants must be in code, use named constants with clear documentation rather than magic numbers. Implement configuration validation to ensure security parameters meet minimum requirements. Use different security configurations for development, testing, and production environments.
Common Consequences
| Impact | Details |
|---|---|
| Confidentiality | Scope: Confidentiality Read Application Data - Hard-coded cryptographic keys or other secrets can be extracted from code, enabling attackers to decrypt sensitive data or bypass authentication. |
| Access Control | Scope: Access Control Bypass Protection Mechanism - Hard-coded security parameters like timeouts or retry limits may be insufficient, allowing brute force attacks or session fixation. |
| Other | Scope: Other Reduce Maintainability - Hard-coded constants make it difficult to update security parameters in response to new threats or changing requirements without code changes. |
Example Code
Vulnerable Code
// Vulnerable: Hard-coded security-relevant constants
public class VulnerableCrypto {
// Vulnerable: Hard-coded encryption key
private static final byte[] SECRET_KEY =
"MySecretKey12345".getBytes(StandardCharsets.UTF_8);
// Vulnerable: Hard-coded IV (should be random per encryption)
private static final byte[] INIT_VECTOR =
{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F};
// Vulnerable: Hard-coded salt (defeats purpose of salting)
private static final String PASSWORD_SALT = "FixedSalt123";
// Vulnerable: Hard-coded iteration count (may become insecure)
private static final int PBKDF2_ITERATIONS = 1000; // Too low!
// Vulnerable: Hard-coded key size
private static final int KEY_SIZE = 128; // Should be 256
public byte[] encrypt(String plaintext) throws Exception {
SecretKeySpec keySpec = new SecretKeySpec(SECRET_KEY, "AES");
IvParameterSpec ivSpec = new IvParameterSpec(INIT_VECTOR);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
return cipher.doFinal(plaintext.getBytes());
}
public String hashPassword(String password) {
// Vulnerable: Same salt for all passwords
String salted = PASSWORD_SALT + password;
return DigestUtils.sha256Hex(salted);
}
}
// Vulnerable: Hard-coded security timeouts
public class VulnerableSession {
// Vulnerable: Hard-coded timeout values
private static final int SESSION_TIMEOUT = 3600; // 1 hour
private static final int TOKEN_EXPIRY = 86400; // 24 hours
private static final int MAX_LOGIN_ATTEMPTS = 3;
private static final int LOCKOUT_DURATION = 300; // 5 minutes
// These may be too long or too short for different environments
}
# Vulnerable: Hard-coded security constants in Python
import hashlib
from Crypto.Cipher import AES
class VulnerableSecurity:
# Vulnerable: Hard-coded API key
API_SECRET_KEY = "sk_live_hardcoded_key_12345"
# Vulnerable: Hard-coded encryption key
ENCRYPTION_KEY = b"0123456789ABCDEF" # 16 bytes for AES-128
# Vulnerable: Hard-coded JWT secret
JWT_SECRET = "super_secret_jwt_key"
# Vulnerable: Hard-coded HMAC key
HMAC_KEY = b"hmac_secret_key_value"
# Vulnerable: Hard-coded password pepper
PASSWORD_PEPPER = "application_pepper_2023"
def encrypt_data(self, data):
# Vulnerable: Using hard-coded key and no IV
cipher = AES.new(self.ENCRYPTION_KEY, AES.MODE_ECB) # ECB is also bad
return cipher.encrypt(self._pad(data))
def hash_password(self, password):
# Vulnerable: Hard-coded pepper, no unique salt
peppered = password + self.PASSWORD_PEPPER
return hashlib.sha256(peppered.encode()).hexdigest()
def generate_token(self, user_id):
# Vulnerable: Hard-coded JWT secret
import jwt
return jwt.encode(
{"user_id": user_id},
self.JWT_SECRET,
algorithm="HS256"
)
# Vulnerable: Hard-coded security limits
MAX_FILE_SIZE = 10485760 # 10MB - might need adjustment
MAX_REQUEST_SIZE = 1048576 # 1MB - fixed limit
RATE_LIMIT = 100 # requests per minute
BCRYPT_ROUNDS = 10 # Should be configurable and higher
// Vulnerable: Hard-coded constants in Node.js
const crypto = require('crypto');
// Vulnerable: Hard-coded encryption key
const ENCRYPTION_KEY = 'abcdefghijklmnop'; // 16 bytes
// Vulnerable: Hard-coded HMAC secret
const HMAC_SECRET = 'hmac_secret_123';
// Vulnerable: Hard-coded JWT secret
const JWT_SECRET = 'my_jwt_secret_key';
// Vulnerable: Hard-coded session settings
const SESSION_CONFIG = {
secret: 'session_secret_value', // Hard-coded
maxAge: 3600000, // Fixed 1 hour
secure: false, // Should depend on environment
sameSite: 'lax' // Fixed policy
};
// Vulnerable: Hard-coded crypto parameters
const CRYPTO_CONFIG = {
algorithm: 'aes-128-cbc', // Should be configurable
iterations: 10000, // Fixed PBKDF2 iterations
keyLength: 16, // Fixed key length
saltLength: 16 // Fixed salt length
};
function encryptData(data) {
// Vulnerable: Using hard-coded key
const cipher = crypto.createCipheriv(
'aes-128-cbc',
ENCRYPTION_KEY,
Buffer.alloc(16) // Zero IV - even worse!
);
return cipher.update(data, 'utf8', 'hex') + cipher.final('hex');
}
function signData(data) {
// Vulnerable: Hard-coded HMAC key
return crypto.createHmac('sha256', HMAC_SECRET)
.update(data)
.digest('hex');
}
<?php
// Vulnerable: Hard-coded security constants in PHP
class VulnerableCrypto {
// Vulnerable: Hard-coded encryption key
private const ENCRYPTION_KEY = 'MySuperSecretKey';
// Vulnerable: Hard-coded IV
private const IV = '1234567890123456';
// Vulnerable: Hard-coded HMAC key
private const HMAC_KEY = 'hmac_key_fixed';
// Vulnerable: Hard-coded bcrypt cost (too low)
private const BCRYPT_COST = 4; // Should be at least 12
// Vulnerable: Hard-coded password requirements
private const MIN_PASSWORD_LENGTH = 6; // Too short
private const REQUIRE_SPECIAL_CHAR = false; // Should be true
public function encrypt($data) {
// Vulnerable: Using hard-coded key and IV
return openssl_encrypt(
$data,
'AES-128-CBC',
self::ENCRYPTION_KEY,
0,
self::IV
);
}
public function hashPassword($password) {
// Vulnerable: Fixed low cost factor
return password_hash($password, PASSWORD_BCRYPT, [
'cost' => self::BCRYPT_COST
]);
}
public function signData($data) {
// Vulnerable: Hard-coded HMAC key
return hash_hmac('sha256', $data, self::HMAC_KEY);
}
}
// Vulnerable: Hard-coded security timeouts
define('SESSION_TIMEOUT', 3600);
define('CSRF_TOKEN_EXPIRY', 1800);
define('PASSWORD_RESET_EXPIRY', 86400);
define('MAX_LOGIN_ATTEMPTS', 5);
?>
Fixed Code
// Fixed: Configurable security constants
public class SecureCrypto {
private final SecureRandom secureRandom;
private final SecurityConfig config;
private final KeyManagementService keyService;
public SecureCrypto(SecurityConfig config, KeyManagementService keyService) {
this.config = config;
this.keyService = keyService;
this.secureRandom = new SecureRandom();
}
public EncryptedData encrypt(String plaintext) throws Exception {
// Fixed: Get key from key management service
byte[] key = keyService.getEncryptionKey();
// Fixed: Generate random IV for each encryption
byte[] iv = new byte[config.getIvSize()];
secureRandom.nextBytes(iv);
SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
IvParameterSpec ivSpec = new IvParameterSpec(iv);
// Fixed: Algorithm configurable
Cipher cipher = Cipher.getInstance(config.getCipherAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
byte[] ciphertext = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));
// Return IV with ciphertext (IV doesn't need to be secret)
return new EncryptedData(iv, ciphertext);
}
public String hashPassword(String password) {
// Fixed: Generate unique salt per password
byte[] salt = new byte[config.getSaltSize()];
secureRandom.nextBytes(salt);
// Fixed: Configurable iteration count from config
int iterations = config.getPbkdf2Iterations();
int keyLength = config.getDerivedKeyLength();
PBEKeySpec spec = new PBEKeySpec(
password.toCharArray(),
salt,
iterations,
keyLength
);
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
byte[] hash = factory.generateSecret(spec).getEncoded();
// Return salt and hash together
return Base64.getEncoder().encodeToString(salt) + ":" +
Base64.getEncoder().encodeToString(hash);
}
}
// Fixed: Security configuration class
public class SecurityConfig {
private final int ivSize;
private final int saltSize;
private final int pbkdf2Iterations;
private final int derivedKeyLength;
private final String cipherAlgorithm;
public SecurityConfig() {
// Load from environment or config file
this.ivSize = getIntProperty("CRYPTO_IV_SIZE", 16);
this.saltSize = getIntProperty("CRYPTO_SALT_SIZE", 32);
this.pbkdf2Iterations = getIntProperty("PBKDF2_ITERATIONS", 310000);
this.derivedKeyLength = getIntProperty("DERIVED_KEY_LENGTH", 256);
this.cipherAlgorithm = getProperty("CIPHER_ALGORITHM", "AES/GCM/NoPadding");
// Validate minimum security requirements
validateConfig();
}
private void validateConfig() {
if (pbkdf2Iterations < 100000) {
throw new SecurityException("PBKDF2 iterations too low");
}
if (derivedKeyLength < 256) {
throw new SecurityException("Key length too short");
}
}
// Getters...
}
# Fixed: Configurable security parameters in Python
import os
import secrets
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.backends import default_backend
class SecureSecurity:
def __init__(self, config=None):
self.config = config or SecurityConfig()
self.key_service = KeyManagementService()
def encrypt_data(self, data: bytes) -> dict:
# Fixed: Get key from key management service
key = self.key_service.get_encryption_key()
# Fixed: Generate random IV for each encryption
iv = secrets.token_bytes(self.config.iv_size)
# Fixed: Use authenticated encryption (GCM)
cipher = Cipher(
algorithms.AES(key),
modes.GCM(iv),
backend=default_backend()
)
encryptor = cipher.encryptor()
ciphertext = encryptor.update(data) + encryptor.finalize()
return {
'iv': iv,
'ciphertext': ciphertext,
'tag': encryptor.tag
}
def hash_password(self, password: str) -> str:
# Fixed: Generate unique salt per password
salt = secrets.token_bytes(self.config.salt_size)
# Fixed: Configurable iterations
kdf = PBKDF2HMAC(
algorithm=hashes.SHA256(),
length=self.config.derived_key_length,
salt=salt,
iterations=self.config.pbkdf2_iterations,
backend=default_backend()
)
key = kdf.derive(password.encode())
import base64
return base64.b64encode(salt).decode() + ':' + base64.b64encode(key).decode()
def generate_token(self, user_id: str) -> str:
import jwt
# Fixed: Get secret from key service
secret = self.key_service.get_jwt_secret()
return jwt.encode(
{"user_id": user_id},
secret,
algorithm=self.config.jwt_algorithm
)
class SecurityConfig:
"""Security configuration loaded from environment."""
def __init__(self):
# Fixed: All parameters from environment with secure defaults
self.iv_size = int(os.environ.get('CRYPTO_IV_SIZE', '12')) # 96 bits for GCM
self.salt_size = int(os.environ.get('CRYPTO_SALT_SIZE', '32'))
self.pbkdf2_iterations = int(os.environ.get('PBKDF2_ITERATIONS', '310000'))
self.derived_key_length = int(os.environ.get('DERIVED_KEY_LENGTH', '32'))
self.jwt_algorithm = os.environ.get('JWT_ALGORITHM', 'HS256')
# Fixed: Validate minimum requirements
self._validate()
def _validate(self):
if self.pbkdf2_iterations < 100000:
raise ValueError("PBKDF2 iterations must be at least 100000")
if self.salt_size < 16:
raise ValueError("Salt size must be at least 16 bytes")
// Fixed: Configurable security constants in Node.js
const crypto = require('crypto');
class SecurityConfig {
constructor() {
// Fixed: Load from environment
this.ivSize = parseInt(process.env.CRYPTO_IV_SIZE || '12');
this.saltSize = parseInt(process.env.CRYPTO_SALT_SIZE || '32');
this.pbkdf2Iterations = parseInt(process.env.PBKDF2_ITERATIONS || '310000');
this.keyLength = parseInt(process.env.KEY_LENGTH || '32');
this.algorithm = process.env.CIPHER_ALGORITHM || 'aes-256-gcm';
// Fixed: Validate configuration
this.validate();
}
validate() {
if (this.pbkdf2Iterations < 100000) {
throw new Error('PBKDF2 iterations too low');
}
if (this.keyLength < 32) {
throw new Error('Key length too short');
}
}
}
class SecureCrypto {
constructor(config, keyService) {
this.config = config || new SecurityConfig();
this.keyService = keyService;
}
async encrypt(data) {
// Fixed: Get key from key service
const key = await this.keyService.getEncryptionKey();
// Fixed: Generate random IV for each encryption
const iv = crypto.randomBytes(this.config.ivSize);
// Fixed: Use authenticated encryption
const cipher = crypto.createCipheriv(this.config.algorithm, key, iv);
let ciphertext = cipher.update(data, 'utf8');
ciphertext = Buffer.concat([ciphertext, cipher.final()]);
const authTag = cipher.getAuthTag();
return {
iv: iv.toString('base64'),
ciphertext: ciphertext.toString('base64'),
authTag: authTag.toString('base64')
};
}
hashPassword(password) {
// Fixed: Generate unique salt
const salt = crypto.randomBytes(this.config.saltSize);
// Fixed: Use configurable iterations
const hash = crypto.pbkdf2Sync(
password,
salt,
this.config.pbkdf2Iterations,
this.config.keyLength,
'sha256'
);
return salt.toString('base64') + ':' + hash.toString('base64');
}
}
// Fixed: Session config from environment
const sessionConfig = {
secret: process.env.SESSION_SECRET, // Required, no default
maxAge: parseInt(process.env.SESSION_MAX_AGE || '3600000'),
secure: process.env.NODE_ENV === 'production',
sameSite: process.env.SESSION_SAME_SITE || 'strict'
};
if (!sessionConfig.secret) {
throw new Error('SESSION_SECRET environment variable required');
}
module.exports = { SecurityConfig, SecureCrypto, sessionConfig };
<?php
// Fixed: Configurable security parameters in PHP
class SecurityConfig {
private int $ivSize;
private int $saltSize;
private int $pbkdf2Iterations;
private int $bcryptCost;
private string $cipherAlgorithm;
public function __construct() {
// Fixed: Load from environment with secure defaults
$this->ivSize = (int)getenv('CRYPTO_IV_SIZE') ?: 16;
$this->saltSize = (int)getenv('CRYPTO_SALT_SIZE') ?: 32;
$this->pbkdf2Iterations = (int)getenv('PBKDF2_ITERATIONS') ?: 310000;
$this->bcryptCost = (int)getenv('BCRYPT_COST') ?: 12;
$this->cipherAlgorithm = getenv('CIPHER_ALGORITHM') ?: 'aes-256-gcm';
$this->validate();
}
private function validate(): void {
if ($this->pbkdf2Iterations < 100000) {
throw new SecurityException('PBKDF2 iterations too low');
}
if ($this->bcryptCost < 10) {
throw new SecurityException('Bcrypt cost too low');
}
}
// Getters...
public function getIvSize(): int { return $this->ivSize; }
public function getSaltSize(): int { return $this->saltSize; }
public function getPbkdf2Iterations(): int { return $this->pbkdf2Iterations; }
public function getBcryptCost(): int { return $this->bcryptCost; }
public function getCipherAlgorithm(): string { return $this->cipherAlgorithm; }
}
class SecureCrypto {
private SecurityConfig $config;
private KeyManagementService $keyService;
public function __construct(SecurityConfig $config, KeyManagementService $keyService) {
$this->config = $config;
$this->keyService = $keyService;
}
public function encrypt(string $data): array {
// Fixed: Get key from key service
$key = $this->keyService->getEncryptionKey();
// Fixed: Generate random IV
$iv = random_bytes($this->config->getIvSize());
// Fixed: Use authenticated encryption
$ciphertext = openssl_encrypt(
$data,
$this->config->getCipherAlgorithm(),
$key,
OPENSSL_RAW_DATA,
$iv,
$tag
);
return [
'iv' => base64_encode($iv),
'ciphertext' => base64_encode($ciphertext),
'tag' => base64_encode($tag)
];
}
public function hashPassword(string $password): string {
// Fixed: Use configurable bcrypt cost
return password_hash($password, PASSWORD_BCRYPT, [
'cost' => $this->config->getBcryptCost()
]);
}
}
// Fixed: Security timeouts from environment
class SecurityTimeouts {
public static function getSessionTimeout(): int {
return (int)getenv('SESSION_TIMEOUT') ?: 3600;
}
public static function getCsrfTokenExpiry(): int {
return (int)getenv('CSRF_TOKEN_EXPIRY') ?: 1800;
}
public static function getPasswordResetExpiry(): int {
return (int)getenv('PASSWORD_RESET_EXPIRY') ?: 3600; // 1 hour, not 24
}
public static function getMaxLoginAttempts(): int {
return (int)getenv('MAX_LOGIN_ATTEMPTS') ?: 5;
}
}
?>
CVE Examples
- CVE-2022-26138: Atlassian Confluence Questions used hard-coded password for the disabledsystemuser account.
- CVE-2021-29078: NetModule Router Software contained hard-coded cryptographic keys.
- CVE-2020-4574: IBM Security Key Lifecycle Manager used hard-coded credentials.
References
- MITRE Corporation. "CWE-547: Use of Hard-coded, Security-relevant Constants." https://cwe.mitre.org/data/definitions/547.html
- OWASP. "Cryptographic Storage Cheat Sheet."
- NIST. "Key Management Guidelines."