Empty Exception Block
Description
Empty Exception Block occurs when an invokable code block contains an exception handling block (catch, except, rescue, etc.) that does not contain any code - it is completely empty or contains only comments. When exceptions are caught but not handled, the program silently swallows errors and continues in a potentially invalid or insecure state. This prevents proper error detection, logging, and recovery, making debugging extremely difficult and potentially hiding security-relevant failures.
Risk
Empty exception blocks have direct security implications. Security exceptions (authentication failures, authorization errors, cryptographic failures) may be silently ignored. Attackers can trigger errors that should terminate operations but instead allow continued execution. Failed validation or sanitization exceptions may be swallowed, allowing malicious input to pass through. Audit and logging of security events is prevented. The application may continue operating with corrupted state after errors. Failed security controls go undetected. Resource cleanup may be skipped, leading to resource leaks that enable DoS attacks.
Solution
Never leave catch blocks empty. At minimum, log the exception with appropriate severity. Rethrow exceptions if the current context cannot handle them properly. Implement proper error recovery or graceful degradation. Use specific exception types rather than catching all exceptions. If an exception truly should be ignored, document why with a clear comment explaining the decision. Use static analysis tools to detect empty catch blocks. Consider using logging frameworks with appropriate log levels for different exception types. Implement centralized exception handling strategies.
Common Consequences
| Impact | Details |
|---|---|
| Other | Scope: Other Reduce Reliability - Exceptions are silently ignored, leaving the application in potentially invalid states. |
| Other | Scope: Other Reduce Maintainability - Silent failures make debugging and troubleshooting extremely difficult. |
| Integrity | Scope: Integrity Unexpected State - The application may continue with corrupted data or state after swallowed exceptions. |
Example Code
Vulnerable Code
// Vulnerable: Empty catch block
public class VulnerableAuthenticator {
public boolean authenticate(String username, String password) {
try {
User user = userRepository.findByUsername(username);
return passwordEncoder.matches(password, user.getPasswordHash());
} catch (Exception e) {
// Vulnerable: Exception silently swallowed!
// Authentication failures, database errors, all ignored
}
return false; // Might return false for wrong reasons
}
public void changePassword(String userId, String newPassword) {
try {
User user = userRepository.findById(userId);
user.setPasswordHash(passwordEncoder.encode(newPassword));
userRepository.save(user);
} catch (Exception e) {
// Vulnerable: Password change failure silently ignored
// User thinks password changed, but it didn't!
}
}
public byte[] decryptSensitiveData(byte[] encrypted, byte[] key) {
try {
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"));
return cipher.doFinal(encrypted);
} catch (Exception e) {
// Vulnerable: Cryptographic failure silently ignored!
// Attacker might exploit this to bypass decryption
}
return null; // Returns null instead of properly handling error
}
}
# Vulnerable: Empty except blocks in Python
class VulnerableFileProcessor:
def process_file(self, filepath):
try:
with open(filepath, 'r') as f:
data = f.read()
return self._parse_data(data)
except:
# Vulnerable: Bare except catches everything
# Including KeyboardInterrupt, SystemExit!
pass # Silently fails
def validate_input(self, user_input):
try:
# Security validation
sanitized = self._sanitize(user_input)
self._check_injection(sanitized)
return sanitized
except Exception:
# Vulnerable: Validation failure silently ignored!
pass
return user_input # Returns unsanitized input on error!
def connect_securely(self, host, port):
try:
context = ssl.create_default_context()
sock = context.wrap_socket(socket.socket(), server_hostname=host)
sock.connect((host, port))
return sock
except ssl.SSLError:
# Vulnerable: SSL errors silently ignored
pass
except Exception as e:
# Vulnerable: All other errors ignored too
pass
# Falls through to return None - caller might not check
return None
// Vulnerable: Empty catch in C#
public class VulnerablePaymentService
{
public bool ProcessPayment(PaymentRequest request)
{
try
{
ValidateCard(request.CardNumber);
var result = _gateway.Charge(request);
LogTransaction(result);
return result.Success;
}
catch (PaymentValidationException)
{
// Vulnerable: Validation failure silently ignored
}
catch (PaymentGatewayException)
{
// Vulnerable: Gateway errors silently ignored
}
catch (Exception)
{
// Vulnerable: All exceptions swallowed
}
return false;
}
public void UpdateUserPermissions(string userId, List<string> permissions)
{
try
{
var user = _userRepository.Get(userId);
user.Permissions = permissions;
_userRepository.Save(user);
}
catch (UnauthorizedAccessException)
{
// Vulnerable: Authorization failure silently ignored!
// Attacker might exploit timing to detect if user exists
}
catch
{
// Vulnerable: Catch-all with no body
}
}
}
// Vulnerable: Empty catch in JavaScript
class VulnerableUserService {
async authenticateUser(username, password) {
try {
const user = await this.db.findUser(username);
const valid = await bcrypt.compare(password, user.passwordHash);
return valid ? user : null;
} catch (e) {
// Vulnerable: All authentication errors silently ignored
// Database errors, bcrypt failures, all swallowed
}
return null;
}
parseJsonConfig(configString) {
try {
return JSON.parse(configString);
} catch {
// Vulnerable: Invalid JSON silently ignored
// Returns undefined, caller might not handle this
}
}
async fetchSecureData(url) {
try {
const response = await fetch(url, {
headers: { 'Authorization': `Bearer ${this.token}` }
});
return await response.json();
} catch (error) {
// Vulnerable: Network errors, auth failures all ignored
// No logging, no retry, no fallback
}
}
}
Fixed Code
// Fixed: Proper exception handling
public class FixedAuthenticator {
private static final Logger logger = LoggerFactory.getLogger(FixedAuthenticator.class);
public boolean authenticate(String username, String password) throws AuthenticationException {
try {
User user = userRepository.findByUsername(username);
if (user == null) {
logger.warn("Authentication failed: user not found - {}", username);
return false;
}
boolean authenticated = passwordEncoder.matches(password, user.getPasswordHash());
if (!authenticated) {
logger.warn("Authentication failed: invalid password for user {}", username);
} else {
logger.info("User {} authenticated successfully", username);
}
return authenticated;
} catch (DataAccessException e) {
// Fixed: Log and wrap in domain exception
logger.error("Database error during authentication for user {}", username, e);
throw new AuthenticationException("Authentication service unavailable", e);
}
}
public void changePassword(String userId, String newPassword) throws PasswordChangeException {
try {
User user = userRepository.findById(userId);
if (user == null) {
throw new PasswordChangeException("User not found: " + userId);
}
user.setPasswordHash(passwordEncoder.encode(newPassword));
userRepository.save(user);
logger.info("Password changed successfully for user {}", userId);
} catch (DataAccessException e) {
// Fixed: Log error and throw domain exception
logger.error("Failed to change password for user {}", userId, e);
throw new PasswordChangeException("Failed to update password", e);
}
}
public byte[] decryptSensitiveData(byte[] encrypted, byte[] key) throws DecryptionException {
try {
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
GCMParameterSpec spec = extractGcmParams(encrypted);
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"), spec);
return cipher.doFinal(extractCiphertext(encrypted));
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
// Fixed: Configuration error - should not happen in production
logger.error("Cipher configuration error", e);
throw new DecryptionException("Cryptographic configuration error", e);
} catch (InvalidKeyException e) {
// Fixed: Log security event
logger.error("Invalid decryption key provided");
throw new DecryptionException("Invalid decryption key", e);
} catch (BadPaddingException | AEADBadTagException e) {
// Fixed: Likely tampering or wrong key
logger.warn("Decryption failed - possible data tampering");
throw new DecryptionException("Decryption failed - data may be corrupted", e);
}
}
}
# Fixed: Proper exception handling in Python
import logging
from typing import Optional
logger = logging.getLogger(__name__)
class FixedFileProcessor:
def process_file(self, filepath: str) -> Optional[dict]:
"""Process file with proper error handling."""
try:
with open(filepath, 'r') as f:
data = f.read()
return self._parse_data(data)
except FileNotFoundError:
# Fixed: Specific handling for missing files
logger.warning(f"File not found: {filepath}")
raise
except PermissionError:
# Fixed: Security-relevant - log and raise
logger.error(f"Permission denied reading file: {filepath}")
raise
except json.JSONDecodeError as e:
# Fixed: Handle parse errors specifically
logger.error(f"Failed to parse file {filepath}: {e}")
raise ProcessingError(f"Invalid file format: {filepath}") from e
def validate_input(self, user_input: str) -> str:
"""Validate and sanitize user input."""
try:
sanitized = self._sanitize(user_input)
self._check_injection(sanitized)
return sanitized
except ValidationError as e:
# Fixed: Log security event and raise
logger.warning(f"Input validation failed: {e}")
raise # Don't return unsanitized input!
except Exception as e:
# Fixed: Catch-all logs and raises
logger.error(f"Unexpected error during validation: {e}")
raise ValidationError("Input validation failed") from e
def connect_securely(self, host: str, port: int) -> ssl.SSLSocket:
"""Establish secure connection with proper error handling."""
try:
context = ssl.create_default_context()
sock = context.wrap_socket(
socket.socket(),
server_hostname=host
)
sock.connect((host, port))
logger.info(f"Secure connection established to {host}:{port}")
return sock
except ssl.SSLCertVerificationError as e:
# Fixed: Certificate errors are security-critical
logger.error(f"SSL certificate verification failed for {host}: {e}")
raise ConnectionSecurityError(f"Certificate verification failed for {host}") from e
except ssl.SSLError as e:
# Fixed: Log SSL errors
logger.error(f"SSL error connecting to {host}:{port}: {e}")
raise ConnectionSecurityError(f"SSL error: {e}") from e
except (socket.timeout, ConnectionRefusedError) as e:
# Fixed: Network errors handled separately
logger.warning(f"Connection failed to {host}:{port}: {e}")
raise ConnectionError(f"Could not connect to {host}:{port}") from e
// Fixed: Proper exception handling in C#
public class FixedPaymentService
{
private readonly ILogger<FixedPaymentService> _logger;
public async Task<PaymentResult> ProcessPaymentAsync(PaymentRequest request)
{
try
{
ValidateCard(request.CardNumber);
var result = await _gateway.ChargeAsync(request);
await LogTransactionAsync(result);
return result;
}
catch (PaymentValidationException ex)
{
// Fixed: Log validation failures
_logger.LogWarning(ex, "Payment validation failed for request {RequestId}",
request.RequestId);
return PaymentResult.ValidationFailed(ex.Message);
}
catch (PaymentGatewayException ex)
{
// Fixed: Log gateway errors with correlation ID
_logger.LogError(ex, "Payment gateway error for request {RequestId}",
request.RequestId);
return PaymentResult.GatewayError(ex.Message);
}
catch (Exception ex)
{
// Fixed: Catch-all logs unexpected errors
_logger.LogCritical(ex, "Unexpected error processing payment {RequestId}",
request.RequestId);
throw; // Rethrow unexpected exceptions
}
}
public async Task UpdateUserPermissionsAsync(string userId, List<string> permissions)
{
try
{
var user = await _userRepository.GetAsync(userId);
if (user == null)
{
throw new UserNotFoundException(userId);
}
user.Permissions = permissions;
await _userRepository.SaveAsync(user);
_logger.LogInformation("Permissions updated for user {UserId}", userId);
}
catch (UnauthorizedAccessException ex)
{
// Fixed: Log security event and rethrow
_logger.LogWarning(ex, "Unauthorized attempt to update permissions for {UserId}",
userId);
throw; // Let caller handle authorization failures
}
catch (DbUpdateException ex)
{
// Fixed: Log database errors
_logger.LogError(ex, "Database error updating permissions for {UserId}", userId);
throw new PermissionUpdateException("Failed to update permissions", ex);
}
}
}
// Fixed: Proper exception handling in JavaScript
class FixedUserService {
constructor(db, logger) {
this.db = db;
this.logger = logger;
}
async authenticateUser(username, password) {
try {
const user = await this.db.findUser(username);
if (!user) {
this.logger.warn({ username }, 'Authentication failed: user not found');
return null;
}
const valid = await bcrypt.compare(password, user.passwordHash);
if (!valid) {
this.logger.warn({ username }, 'Authentication failed: invalid password');
return null;
}
this.logger.info({ username }, 'User authenticated successfully');
return user;
} catch (error) {
// Fixed: Log error and throw
this.logger.error({ error, username }, 'Authentication error');
throw new AuthenticationError('Authentication service unavailable', error);
}
}
parseJsonConfig(configString) {
try {
return JSON.parse(configString);
} catch (error) {
// Fixed: Log and throw with context
this.logger.error({ error }, 'Failed to parse JSON configuration');
throw new ConfigurationError('Invalid JSON configuration', error);
}
}
async fetchSecureData(url) {
try {
const response = await fetch(url, {
headers: { 'Authorization': `Bearer ${this.token}` }
});
if (!response.ok) {
// Fixed: Handle HTTP errors
if (response.status === 401) {
this.logger.warn({ url }, 'Authentication failed for secure fetch');
throw new AuthenticationError('Invalid or expired token');
}
throw new FetchError(`HTTP ${response.status}: ${response.statusText}`);
}
return await response.json();
} catch (error) {
if (error instanceof AuthenticationError || error instanceof FetchError) {
throw error;
}
// Fixed: Log network errors
this.logger.error({ error, url }, 'Network error fetching secure data');
throw new NetworkError('Failed to fetch data', error);
}
}
}
CVE Examples
Empty exception blocks have contributed to vulnerabilities where error conditions were not properly detected, though specific CVEs typically map to the resulting weakness (e.g., authentication bypass) rather than this CWE directly.
Related CWEs
- CWE-1071: Empty Code Block (parent)
- CWE-390: Detection of Error Condition Without Action (related)
- CWE-754: Improper Check for Unusual or Exceptional Conditions (related)
References
- MITRE Corporation. "CWE-1069: Empty Exception Block." https://cwe.mitre.org/data/definitions/1069.html
- Bloch, Joshua. "Effective Java, Third Edition." Item 77: Don't ignore exceptions.
- SonarSource. "Code Smell: Empty Catch Block."