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

ImpactDetails
OtherScope: Other

Reduce Maintainability - Literal constants make code harder to understand and update.
OtherScope: Other

Increase Analytical Complexity - Magic numbers obscure code intent.
IntegrityScope: 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.


  • 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

  1. MITRE Corporation. "CWE-1106: Insufficient Use of Symbolic Constants." https://cwe.mitre.org/data/definitions/1106.html
  2. Martin, Robert C. "Clean Code" - Meaningful Names.
  3. CERT C Coding Standard. "DCL06-C: Use meaningful symbolic constants to represent literal values."