Use of Redundant Code
Description
Use of Redundant Code occurs when software contains multiple functions, methods, procedures, macros, or code blocks that implement identical or nearly identical logic. This code duplication creates maintenance challenges because changes or fixes must be applied to multiple locations, increasing the risk that some instances will be missed. While primarily a code quality issue, redundant code can have indirect security implications when security patches or fixes are inconsistently applied across duplicated code segments.
Risk
The primary risk is reduced maintainability that can lead to security vulnerabilities. When a security flaw is discovered in duplicated code, developers may fix one instance while overlooking others. This inconsistent patching leaves some attack vectors open. Additionally, redundant code increases the attack surface by providing multiple potential points of exploitation. Code duplication also makes security audits more difficult and time-consuming, increasing the likelihood that vulnerabilities will be missed. The complexity introduced by duplication can also mask security issues during code review.
Solution
Extract common functionality into single, reusable functions or methods. Apply the DRY (Don't Repeat Yourself) principle during development. Use static analysis tools to detect code duplication. Refactor existing duplicated code into shared utilities. Implement code review processes that flag duplication. Create shared libraries for commonly needed functionality. Use design patterns appropriately to avoid unnecessary code repetition. Ensure any security-critical code exists in exactly one location to simplify maintenance and auditing.
Common Consequences
| Impact | Details |
|---|---|
| Other | Scope: Other Reduce Maintainability - Duplicated code makes the product harder to maintain, increasing the risk of inconsistent security patches. |
| Integrity | Scope: Integrity Quality Degradation - Inconsistent updates to duplicated code segments can lead to reliability issues and potential security gaps. |
Example Code
Vulnerable Code
// Vulnerable: Duplicated validation logic across multiple methods
public class VulnerableUserService {
public boolean createUser(String username, String password, String email) {
// Duplicated validation logic - Instance 1
if (username == null || username.length() < 3 || username.length() > 50) {
return false;
}
if (!username.matches("^[a-zA-Z0-9_]+$")) {
return false;
}
if (password == null || password.length() < 8) {
return false;
}
if (email == null || !email.contains("@")) {
return false;
}
// Create user...
return true;
}
public boolean updateUser(String username, String password, String email) {
// Duplicated validation logic - Instance 2
// If security fix is needed, might be forgotten here
if (username == null || username.length() < 3 || username.length() > 50) {
return false;
}
if (!username.matches("^[a-zA-Z0-9_]+$")) {
return false;
}
if (password == null || password.length() < 8) {
return false;
}
if (email == null || !email.contains("@")) {
return false;
}
// Update user...
return true;
}
public boolean validateUserInput(String username, String password, String email) {
// Duplicated validation logic - Instance 3
// Another copy that might be missed during updates
if (username == null || username.length() < 3 || username.length() > 50) {
return false;
}
if (!username.matches("^[a-zA-Z0-9_]+$")) {
return false;
}
if (password == null || password.length() < 8) {
return false;
}
if (email == null || !email.contains("@")) {
return false;
}
return true;
}
}
# Vulnerable: Duplicated database query construction
class VulnerableDataAccess:
def get_user_by_id(self, user_id, connection):
# Duplicated query pattern - Instance 1
cursor = connection.cursor()
query = "SELECT * FROM users WHERE id = '" + str(user_id) + "'"
cursor.execute(query)
return cursor.fetchone()
def get_user_by_email(self, email, connection):
# Duplicated query pattern - Instance 2
# Same SQL injection vulnerability
cursor = connection.cursor()
query = "SELECT * FROM users WHERE email = '" + email + "'"
cursor.execute(query)
return cursor.fetchone()
def get_user_by_username(self, username, connection):
# Duplicated query pattern - Instance 3
# If parameterization is added to one, others remain vulnerable
cursor = connection.cursor()
query = "SELECT * FROM users WHERE username = '" + username + "'"
cursor.execute(query)
return cursor.fetchone()
// Vulnerable: Duplicated error handling with security implications
class VulnerableApiClient {
async getUser(userId) {
try {
const response = await fetch(`/api/users/${userId}`);
if (!response.ok) {
// Duplicated error handling - Instance 1
console.log("Error fetching user:", response.status);
console.log("Request details:", { userId, endpoint: '/api/users' });
throw new Error(`HTTP ${response.status}`);
}
return response.json();
} catch (error) {
console.error("Full error:", error.stack); // Leaks stack trace
throw error;
}
}
async getOrders(userId) {
try {
const response = await fetch(`/api/orders?user=${userId}`);
if (!response.ok) {
// Duplicated error handling - Instance 2
// Same information leakage pattern
console.log("Error fetching orders:", response.status);
console.log("Request details:", { userId, endpoint: '/api/orders' });
throw new Error(`HTTP ${response.status}`);
}
return response.json();
} catch (error) {
console.error("Full error:", error.stack); // Leaks stack trace
throw error;
}
}
}
Fixed Code
// Fixed: Centralized validation logic
public class FixedUserService {
private final UserValidator validator = new UserValidator();
public boolean createUser(String username, String password, String email) {
// Fixed: Use single validation method
if (!validator.validateUserInput(username, password, email)) {
return false;
}
// Create user...
return true;
}
public boolean updateUser(String username, String password, String email) {
// Fixed: Same validation method used everywhere
if (!validator.validateUserInput(username, password, email)) {
return false;
}
// Update user...
return true;
}
}
// Fixed: Single source of truth for validation
class UserValidator {
private static final int MIN_USERNAME_LENGTH = 3;
private static final int MAX_USERNAME_LENGTH = 50;
private static final int MIN_PASSWORD_LENGTH = 8;
private static final Pattern USERNAME_PATTERN = Pattern.compile("^[a-zA-Z0-9_]+$");
private static final Pattern EMAIL_PATTERN = Pattern.compile("^[^@]+@[^@]+\\.[^@]+$");
public boolean validateUserInput(String username, String password, String email) {
return validateUsername(username)
&& validatePassword(password)
&& validateEmail(email);
}
public boolean validateUsername(String username) {
if (username == null) return false;
if (username.length() < MIN_USERNAME_LENGTH) return false;
if (username.length() > MAX_USERNAME_LENGTH) return false;
return USERNAME_PATTERN.matcher(username).matches();
}
public boolean validatePassword(String password) {
if (password == null) return false;
if (password.length() < MIN_PASSWORD_LENGTH) return false;
// Additional password rules can be added in ONE place
return true;
}
public boolean validateEmail(String email) {
if (email == null) return false;
return EMAIL_PATTERN.matcher(email).matches();
}
}
# Fixed: Centralized, parameterized query execution
class FixedDataAccess:
def _execute_query(self, connection, query, params):
"""Single method for all database queries with proper parameterization"""
cursor = connection.cursor()
cursor.execute(query, params) # Fixed: Parameterized query
return cursor
def get_user_by_id(self, user_id, connection):
# Fixed: Uses centralized query method
query = "SELECT * FROM users WHERE id = %s"
cursor = self._execute_query(connection, query, (user_id,))
return cursor.fetchone()
def get_user_by_email(self, email, connection):
# Fixed: Same secure pattern
query = "SELECT * FROM users WHERE email = %s"
cursor = self._execute_query(connection, query, (email,))
return cursor.fetchone()
def get_user_by_username(self, username, connection):
# Fixed: Consistent security across all methods
query = "SELECT * FROM users WHERE username = %s"
cursor = self._execute_query(connection, query, (username,))
return cursor.fetchone()
# Alternative: Use a query builder pattern
class SecureQueryBuilder:
def __init__(self, table):
self.table = table
self.conditions = []
self.params = []
def where(self, field, value):
self.conditions.append(f"{field} = %s")
self.params.append(value)
return self
def execute(self, connection):
query = f"SELECT * FROM {self.table}"
if self.conditions:
query += " WHERE " + " AND ".join(self.conditions)
cursor = connection.cursor()
cursor.execute(query, tuple(self.params))
return cursor
// Fixed: Centralized error handling
class FixedApiClient {
async _handleResponse(response, context) {
if (!response.ok) {
// Fixed: Single error handling implementation
// Easy to update security behavior in one place
const error = new ApiError(response.status, context);
// Sanitized logging - no sensitive data
console.error(`API Error: ${response.status} for ${context.operation}`);
throw error;
}
return response.json();
}
async _fetchWithErrorHandling(url, context) {
try {
const response = await fetch(url);
return this._handleResponse(response, context);
} catch (error) {
if (error instanceof ApiError) {
throw error;
}
// Fixed: Centralized error sanitization
console.error(`Network error for ${context.operation}`);
throw new ApiError(0, { ...context, networkError: true });
}
}
async getUser(userId) {
// Fixed: Uses centralized error handling
return this._fetchWithErrorHandling(
`/api/users/${encodeURIComponent(userId)}`,
{ operation: 'getUser', resourceType: 'user' }
);
}
async getOrders(userId) {
// Fixed: Same secure pattern
return this._fetchWithErrorHandling(
`/api/orders?user=${encodeURIComponent(userId)}`,
{ operation: 'getOrders', resourceType: 'orders' }
);
}
}
class ApiError extends Error {
constructor(status, context) {
super(`API Error: ${status}`);
this.status = status;
this.context = context;
}
}
<?php
// Fixed: Centralized input sanitization
class FixedInputHandler {
private static $instance = null;
private $sanitizers = [];
private function __construct() {
// Define sanitizers once
$this->sanitizers = [
'string' => fn($v) => htmlspecialchars(trim($v), ENT_QUOTES, 'UTF-8'),
'email' => fn($v) => filter_var($v, FILTER_SANITIZE_EMAIL),
'int' => fn($v) => filter_var($v, FILTER_SANITIZE_NUMBER_INT),
'url' => fn($v) => filter_var($v, FILTER_SANITIZE_URL),
];
}
public static function getInstance() {
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
public function sanitize($value, $type) {
if (!isset($this->sanitizers[$type])) {
throw new InvalidArgumentException("Unknown sanitizer: $type");
}
return $this->sanitizers[$type]($value);
}
}
// Usage - all code uses the same sanitization
class UserController {
private $inputHandler;
public function __construct() {
$this->inputHandler = FixedInputHandler::getInstance();
}
public function createUser($data) {
$username = $this->inputHandler->sanitize($data['username'], 'string');
$email = $this->inputHandler->sanitize($data['email'], 'email');
// Consistent sanitization across entire application
}
public function updateUser($data) {
$username = $this->inputHandler->sanitize($data['username'], 'string');
$email = $this->inputHandler->sanitize($data['email'], 'email');
// Same behavior, security fixes apply everywhere
}
}
?>
CVE Examples
This CWE is primarily a code quality issue and is marked as PROHIBITED for direct CVE mapping. However, inconsistent security patches in duplicated code have contributed to various vulnerabilities where fixes were incompletely applied.
Related CWEs
- CWE-710: Improper Adherence to Coding Standards (parent)
- CWE-1006: Bad Coding Practices (category member)
- CWE-398: Indicator of Poor Code Quality (related)
References
- MITRE Corporation. "CWE-1041: Use of Redundant Code." https://cwe.mitre.org/data/definitions/1041.html
- Martin, Robert C. "Clean Code: A Handbook of Agile Software Craftsmanship."
- Hunt, Andrew and Thomas, David. "The Pragmatic Programmer" - DRY Principle.