Insufficient Use of Symbolic Constants
Description
Insufficient Use of Symbolic Constants occurs when source code uses literal constants (magic numbers or strings) that may need to change or evolve over time, instead of defining and using symbolic constants with meaningful names. This makes code harder to understand, maintain, and modify consistently. When the same literal value appears in multiple places, changing it requires finding and updating all occurrences, which is error-prone and can lead to inconsistencies.
Risk
Using literal constants instead of symbolic ones has indirect security implications. Buffer size literals scattered throughout code make buffer overflow vulnerabilities more likely when sizes change. Security-related constants (max attempts, timeouts, key sizes) may be inconsistently updated. Code review is harder when magic numbers obscure the intent. Maintainers may change one occurrence but miss others, creating security gaps. Testing is complicated by unclear constant values. Configuration errors are more likely with hardcoded values.
Solution
Define symbolic constants for all values that have semantic meaning or may need to change. Use language-appropriate constant mechanisms (const, #define, enum, final, static readonly). Group related constants in dedicated files or classes. Name constants to clearly convey their purpose. Use constants consistently throughout the codebase. Apply static analysis to detect magic numbers. Include units in constant names where applicable (e.g., TIMEOUT_SECONDS). Document the rationale for constant values.
Common Consequences
| Impact | Details |
|---|---|
| Other | Scope: Other Reduce Maintainability - Literal constants make code harder to understand and update. |
| Other | Scope: Other Increase Analytical Complexity - Magic numbers obscure code intent. |
| Integrity | Scope: Integrity Inconsistent State - Updating one literal but missing others causes inconsistencies. |
Example Code
Vulnerable Code
// Vulnerable: Literal constants (magic numbers)
#include <stdio.h>
#include <string.h>
void vulnerable_process_input() {
// Vulnerable: Magic number 1024 appears multiple times
char buffer[1024];
char temp[1024];
// If we need to change buffer size, must find ALL occurrences
fgets(buffer, 1024, stdin); // Magic number duplicated
// Vulnerable: What does 5 mean?
if (login_attempts > 5) {
lock_account();
}
// Vulnerable: What is 30?
sleep(30); // Timeout? Seconds? Minutes?
// Vulnerable: Security-sensitive magic numbers
if (password_length < 8) { // Why 8? Where else is this checked?
reject_password();
}
// Vulnerable: Cryptographic constants without explanation
unsigned char key[32]; // AES-256 key size, but unclear
unsigned char iv[16]; // Block size, but unclear
// Vulnerable: Network constants
connect_to_server("192.168.1.100", 8080); // Hardcoded IP and port
// Vulnerable: Error codes as magic numbers
if (result == -1) { // What error?
handle_error();
} else if (result == -2) { // Different error?
handle_other_error();
}
}
// Vulnerable: Same values duplicated across functions
void vulnerable_validate_user(char* username) {
if (strlen(username) < 3 || strlen(username) > 50) {
reject_username();
}
}
void vulnerable_validate_email(char* email) {
// Same limits duplicated - easy to get out of sync
if (strlen(email) < 3 || strlen(email) > 50) {
reject_email();
}
}
// Vulnerable: Java with magic numbers
public class VulnerableUserService {
public void validatePassword(String password) {
// Vulnerable: Magic numbers for password rules
if (password.length() < 8) { // Why 8?
throw new ValidationException("Password too short");
}
if (password.length() > 128) { // Why 128?
throw new ValidationException("Password too long");
}
}
public void processLogin(String username, String password) {
// Vulnerable: Magic number for retry limit
for (int i = 0; i < 3; i++) {
if (attemptLogin(username, password)) {
return;
}
// Vulnerable: Magic number for delay (milliseconds? seconds?)
Thread.sleep(1000);
}
lockAccount(username);
}
public byte[] encryptData(byte[] data) {
// Vulnerable: Cryptographic magic numbers
byte[] key = new byte[32]; // AES key size
byte[] iv = new byte[16]; // IV size
// Vulnerable: Algorithm name as string literal
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
return cipher.doFinal(data);
}
public void cacheData(String key, Object value) {
// Vulnerable: What does 3600 mean?
cache.put(key, value, 3600); // TTL in seconds? milliseconds?
}
public void sendRequest() {
// Vulnerable: Timeout magic number
connection.setConnectTimeout(5000); // 5 seconds, but not clear
connection.setReadTimeout(30000); // 30 seconds, but not clear
}
}
# Vulnerable: Python with magic numbers
class VulnerableDataProcessor:
def process_file(self, filepath):
# Vulnerable: Magic number for chunk size
with open(filepath, 'rb') as f:
while True:
chunk = f.read(4096) # Why 4096?
if not chunk:
break
self.process_chunk(chunk)
def validate_input(self, data):
# Vulnerable: Magic numbers for validation
if len(data) > 10000: # Why 10000?
raise ValueError("Input too large")
if data.count('\n') > 1000: # Why 1000?
raise ValueError("Too many lines")
def calculate_rate(self, requests, period):
# Vulnerable: Magic number for rate limit
if requests / period > 100: # 100 requests per what?
raise RateLimitException()
def connect_database(self):
# Vulnerable: Hardcoded connection parameters
return connect(
host='localhost',
port=5432,
database='myapp',
pool_size=10, # Why 10?
timeout=30 # Seconds? Milliseconds?
)
Fixed Code
// Fixed: Proper use of symbolic constants
#include <stdio.h>
#include <string.h>
// Security-related constants
enum SecurityConstants {
MAX_LOGIN_ATTEMPTS = 5,
ACCOUNT_LOCKOUT_SECONDS = 30,
MIN_PASSWORD_LENGTH = 8,
MAX_PASSWORD_LENGTH = 128
};
// Buffer size constants
enum BufferSizes {
INPUT_BUFFER_SIZE = 1024,
MAX_USERNAME_LENGTH = 50,
MIN_USERNAME_LENGTH = 3,
MAX_EMAIL_LENGTH = 254 // RFC 5321
};
// Cryptographic constants
enum CryptoConstants {
AES_256_KEY_SIZE = 32,
AES_BLOCK_SIZE = 16,
PBKDF2_ITERATIONS = 100000
};
// Network constants
static const char* const DEFAULT_SERVER_HOST = "192.168.1.100";
static const int DEFAULT_SERVER_PORT = 8080;
// Error codes with meaningful names
typedef enum {
ERROR_SUCCESS = 0,
ERROR_CONNECTION_FAILED = -1,
ERROR_AUTHENTICATION_FAILED = -2,
ERROR_TIMEOUT = -3
} ErrorCode;
void fixed_process_input() {
// Fixed: Using symbolic constants
char buffer[INPUT_BUFFER_SIZE];
char temp[INPUT_BUFFER_SIZE];
fgets(buffer, INPUT_BUFFER_SIZE, stdin);
// Fixed: Clear intent
if (login_attempts > MAX_LOGIN_ATTEMPTS) {
lock_account();
}
// Fixed: Timeout clearly named
sleep(ACCOUNT_LOCKOUT_SECONDS);
// Fixed: Password requirements clear
if (password_length < MIN_PASSWORD_LENGTH) {
reject_password();
}
// Fixed: Crypto sizes named
unsigned char key[AES_256_KEY_SIZE];
unsigned char iv[AES_BLOCK_SIZE];
// Fixed: Named error codes
ErrorCode result = connect_to_server(DEFAULT_SERVER_HOST, DEFAULT_SERVER_PORT);
if (result == ERROR_CONNECTION_FAILED) {
handle_connection_error();
} else if (result == ERROR_AUTHENTICATION_FAILED) {
handle_auth_error();
}
}
// Fixed: Shared constants used consistently
void fixed_validate_user(char* username) {
if (strlen(username) < MIN_USERNAME_LENGTH ||
strlen(username) > MAX_USERNAME_LENGTH) {
reject_username();
}
}
void fixed_validate_email(char* email) {
// Same constant ensures consistency
if (strlen(email) < MIN_USERNAME_LENGTH ||
strlen(email) > MAX_EMAIL_LENGTH) {
reject_email();
}
}
// Fixed: Java with proper constants
public class FixedUserService {
// Security constants
private static final int MIN_PASSWORD_LENGTH = 8;
private static final int MAX_PASSWORD_LENGTH = 128;
private static final int MAX_LOGIN_ATTEMPTS = 3;
private static final int RETRY_DELAY_MILLIS = 1000;
// Cryptographic constants
private static final int AES_KEY_SIZE_BYTES = 32; // 256 bits
private static final int AES_IV_SIZE_BYTES = 16; // 128 bits
private static final String CIPHER_TRANSFORMATION = "AES/CBC/PKCS5Padding";
// Cache constants
private static final int DEFAULT_CACHE_TTL_SECONDS = 3600; // 1 hour
// Connection constants
private static final int CONNECT_TIMEOUT_MILLIS = 5000; // 5 seconds
private static final int READ_TIMEOUT_MILLIS = 30000; // 30 seconds
public void validatePassword(String password) {
// Fixed: Constants make intent clear
if (password.length() < MIN_PASSWORD_LENGTH) {
throw new ValidationException(
"Password must be at least " + MIN_PASSWORD_LENGTH + " characters");
}
if (password.length() > MAX_PASSWORD_LENGTH) {
throw new ValidationException(
"Password cannot exceed " + MAX_PASSWORD_LENGTH + " characters");
}
}
public void processLogin(String username, String password) {
// Fixed: Named constants
for (int attempt = 0; attempt < MAX_LOGIN_ATTEMPTS; attempt++) {
if (attemptLogin(username, password)) {
return;
}
Thread.sleep(RETRY_DELAY_MILLIS);
}
lockAccount(username);
}
public byte[] encryptData(byte[] data) {
// Fixed: Named crypto constants
byte[] key = new byte[AES_KEY_SIZE_BYTES];
byte[] iv = new byte[AES_IV_SIZE_BYTES];
Cipher cipher = Cipher.getInstance(CIPHER_TRANSFORMATION);
return cipher.doFinal(data);
}
public void cacheData(String key, Object value) {
// Fixed: Named TTL constant
cache.put(key, value, DEFAULT_CACHE_TTL_SECONDS);
}
public void sendRequest() {
// Fixed: Named timeout constants
connection.setConnectTimeout(CONNECT_TIMEOUT_MILLIS);
connection.setReadTimeout(READ_TIMEOUT_MILLIS);
}
}
// Fixed: Constants in dedicated class for sharing
public final class SecurityConstants {
public static final int MIN_PASSWORD_LENGTH = 8;
public static final int MAX_PASSWORD_LENGTH = 128;
public static final int MAX_LOGIN_ATTEMPTS = 3;
public static final int PASSWORD_EXPIRY_DAYS = 90;
// Prevent instantiation
private SecurityConstants() {}
}
# Fixed: Python with proper constants
from typing import Final
from enum import IntEnum
from dataclasses import dataclass
# Security constants
MIN_PASSWORD_LENGTH: Final[int] = 8
MAX_PASSWORD_LENGTH: Final[int] = 128
MAX_LOGIN_ATTEMPTS: Final[int] = 3
# File processing constants
class FileConstants:
CHUNK_SIZE: Final[int] = 4096 # 4 KB chunks for optimal I/O
MAX_INPUT_SIZE: Final[int] = 10_000 # Maximum input bytes
MAX_LINE_COUNT: Final[int] = 1000 # Maximum lines per file
# Rate limiting constants
class RateLimitConstants:
MAX_REQUESTS_PER_SECOND: Final[int] = 100
RATE_LIMIT_WINDOW_SECONDS: Final[int] = 1
# Database constants
@dataclass(frozen=True)
class DatabaseConfig:
HOST: str = 'localhost'
PORT: int = 5432
DATABASE: str = 'myapp'
POOL_SIZE: int = 10
TIMEOUT_SECONDS: int = 30
# Error codes as enum
class ErrorCode(IntEnum):
SUCCESS = 0
CONNECTION_FAILED = -1
AUTHENTICATION_FAILED = -2
TIMEOUT = -3
class FixedDataProcessor:
def process_file(self, filepath: str) -> None:
"""Process file in chunks."""
with open(filepath, 'rb') as f:
while True:
# Fixed: Named constant with documentation
chunk = f.read(FileConstants.CHUNK_SIZE)
if not chunk:
break
self.process_chunk(chunk)
def validate_input(self, data: str) -> None:
"""Validate input data."""
# Fixed: Named constants make limits clear
if len(data) > FileConstants.MAX_INPUT_SIZE:
raise ValueError(
f"Input exceeds maximum size of {FileConstants.MAX_INPUT_SIZE}")
if data.count('\n') > FileConstants.MAX_LINE_COUNT:
raise ValueError(
f"Input exceeds maximum of {FileConstants.MAX_LINE_COUNT} lines")
def calculate_rate(self, requests: int, period_seconds: float) -> None:
"""Check rate limit."""
# Fixed: Named constants with units in name
rate = requests / period_seconds
if rate > RateLimitConstants.MAX_REQUESTS_PER_SECOND:
raise RateLimitException(
f"Rate {rate}/s exceeds limit of "
f"{RateLimitConstants.MAX_REQUESTS_PER_SECOND}/s")
def connect_database(self):
"""Connect to database with configured settings."""
# Fixed: Configuration object with named values
config = DatabaseConfig()
return connect(
host=config.HOST,
port=config.PORT,
database=config.DATABASE,
pool_size=config.POOL_SIZE,
timeout=config.TIMEOUT_SECONDS
)
CVE Examples
This CWE is marked as PROHIBITED for direct CVE mapping as it represents a code quality concern rather than a direct security vulnerability.
Related CWEs
- CWE-1078: Inappropriate Source Code Style or Formatting (parent)
- CWE-1006: Bad Coding Practices (category member)
- CWE-1107: Insufficient Isolation of Symbolic Constant Definitions (related)
References
- MITRE Corporation. "CWE-1106: Insufficient Use of Symbolic Constants." https://cwe.mitre.org/data/definitions/1106.html
- Martin, Robert C. "Clean Code" - Meaningful Names.
- CERT C Coding Standard. "DCL06-C: Use meaningful symbolic constants to represent literal values."