Incorrect Control Flow Scoping
Description
Incorrect Control Flow Scoping is a weakness where software does not properly return control flow to the appropriate location after completing a task or detecting an unusual condition. This occurs when code execution continues inappropriately after critical operations or exceptions, rather than returning to the correct control flow destination. Common manifestations include continuing execution after sending redirects, failing to terminate after exception handling, or improperly using System.exit() in environments where it kills more than intended.
Risk
Incorrect control flow scoping creates serious security vulnerabilities. Execution after redirect (EAR) vulnerabilities allow attackers to access content that should be protected by authentication or authorization redirects. Uncaught exceptions can crash applications or leave them in inconsistent states. Using System.exit() in J2EE environments terminates the entire container instead of just the current request. Returning from finally blocks can suppress exceptions and hide error conditions. These issues can lead to authentication bypass, information disclosure, denial of service, and unpredictable application behavior.
Solution
Always terminate execution appropriately after redirects by calling exit() or return. Handle all exceptions at appropriate levels—don't let them propagate unexpectedly. Never use System.exit() in container-managed environments; throw appropriate exceptions instead. Avoid returning from finally blocks. Use static analysis tools to detect control flow anomalies. Structure code so that protected operations only execute in explicit success paths. Implement comprehensive exception handling that covers all code paths.
Common Consequences
| Impact | Details |
|---|---|
| Other | Scope: Other Alter Execution Logic - Code executes when it should have been bypassed or terminated. |
| Access Control | Scope: Access Control Bypass Protection Mechanism - Authentication and authorization controls may be bypassed. |
| Availability | Scope: Availability DoS: Crash, Exit, or Restart - Improper termination can crash applications or entire containers. |
Example Code
Vulnerable Code
<?php
// Vulnerable: Execution continues after redirect
function checkAuthorization() {
if (!isLoggedIn()) {
http_redirect("/login.php");
// Vulnerable: No exit - execution continues
}
}
checkAuthorization();
// Sensitive code executes even for unauthorized users
$secrets = getSecrets();
echo $secrets; // Exposed after redirect header
?>
// Vulnerable: Uncaught exception in servlet
import javax.servlet.http.*;
public class VulnerableServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response) {
// Vulnerable: DNS lookup can throw uncaught exception
String hostname = request.getParameter("host");
InetAddress addr = InetAddress.getByName(hostname);
// UnknownHostException not caught - crashes servlet
// Rest of processing never completes
processRequest(addr);
}
}
// Vulnerable: System.exit() in J2EE container
@Stateless
public class VulnerableEJB {
public void processData(String data) {
try {
validateData(data);
} catch (ValidationException e) {
// Vulnerable: Terminates entire JVM, not just this request!
System.exit(1);
}
processValidData(data);
}
}
// Vulnerable: Return in finally block
public class VulnerableFinally {
public int vulnerableMethod() {
try {
riskyOperation();
return 1;
} catch (Exception e) {
return -1; // Error indicator
} finally {
// Vulnerable: Return in finally suppresses the try/catch returns!
return 0; // This ALWAYS returns, hiding errors
}
}
public void vulnerableFinallyException() {
try {
throw new SecurityException("Access denied");
} finally {
// Vulnerable: Return in finally swallows the exception
return; // SecurityException is lost!
}
}
}
# Vulnerable: Exception not properly handled
def vulnerable_process(user_input):
try:
result = parse_data(user_input)
except ValueError:
# Vulnerable: Catches exception but continues with undefined result
pass
# result may be undefined here
return process_result(result) # NameError or uses stale value
# Vulnerable: Broad exception catching
def vulnerable_auth():
try:
user = authenticate(username, password)
if user is None:
raise AuthenticationError("Invalid credentials")
return user
except Exception:
# Vulnerable: Catches ALL exceptions including AuthenticationError
# and continues as if nothing happened
pass
# Continues without authentication!
return default_user() # Dangerous fallback
// Vulnerable: Unchecked exception propagation
public class VulnerableController {
public ActionResult Process(string data) {
// Vulnerable: NullReferenceException can crash the request
var result = data.ToUpper(); // Crashes if data is null
// Never executes if data is null
return View(result);
}
}
Fixed Code
<?php
// Fixed: Exit immediately after redirect
function checkAuthorization() {
if (!isLoggedIn()) {
http_redirect("/login.php");
exit(); // Fixed: Terminate execution
}
}
checkAuthorization();
// Only executes if authorized
$secrets = getSecrets();
echo $secrets;
// Alternative: Structure code properly
if (isLoggedIn()) {
$secrets = getSecrets();
echo $secrets;
} else {
http_redirect("/login.php");
exit();
}
?>
// Fixed: Proper exception handling
import javax.servlet.http.*;
public class SecureServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
String hostname = request.getParameter("host");
try {
// Fixed: Handle potential exception
InetAddress addr = InetAddress.getByName(hostname);
processRequest(addr);
} catch (UnknownHostException e) {
// Fixed: Proper error response instead of crash
response.sendError(HttpServletResponse.SC_BAD_REQUEST,
"Invalid hostname");
return;
}
}
}
// Fixed: Don't use System.exit() in containers
@Stateless
public class SecureEJB {
public void processData(String data) throws ValidationException {
try {
validateData(data);
} catch (ValidationException e) {
// Fixed: Throw exception instead of System.exit()
// Let container handle the error properly
throw e;
}
processValidData(data);
}
}
// Fixed: Never return from finally
public class SecureFinally {
public int secureMethod() {
int result = 0;
try {
riskyOperation();
result = 1;
} catch (Exception e) {
result = -1;
} finally {
// Fixed: Cleanup only, no return
cleanup();
}
return result; // Return after finally block
}
public void secureMethodWithResource() {
// Fixed: Use try-with-resources instead
try (Resource res = new Resource()) {
res.process();
} // Automatic cleanup, no finally needed
}
}
# Fixed: Proper exception handling
def secure_process(user_input):
try:
result = parse_data(user_input)
except ValueError as e:
# Fixed: Handle the exception properly
logging.error(f"Parse error: {e}")
return None # Or raise a custom exception
return process_result(result)
# Fixed: Specific exception handling
def secure_auth():
try:
user = authenticate(username, password)
if user is None:
raise AuthenticationError("Invalid credentials")
return user
except AuthenticationError:
# Fixed: Re-raise authentication errors
raise
except ConnectionError as e:
# Fixed: Handle specific infrastructure errors
logging.error(f"Connection failed: {e}")
raise AuthenticationError("Service unavailable")
# Fixed: Use context managers
def secure_file_process(filename):
try:
with open(filename, 'r') as f:
data = f.read()
return process(data)
except FileNotFoundError:
return None
except PermissionError:
raise SecurityError("Access denied")
// Fixed: Null check and exception handling
public class SecureController {
public ActionResult Process(string data) {
// Fixed: Check for null
if (string.IsNullOrEmpty(data)) {
return BadRequest("Data is required");
}
try {
var result = data.ToUpper();
return View(result);
} catch (Exception ex) {
_logger.LogError(ex, "Processing failed");
return StatusCode(500, "Internal error");
}
}
}
CVE Examples
- CVE-2014-1266: Apple SSL "goto fail" bug—incorrect goto statement caused certificate validation to be bypassed.
- CVE-2023-21087: Uncaught exception in smartphone OS caused persistent boot loop (DoS).
- CVE-2007-2713: Execution after redirect allowed unauthorized administrator access.
References
- MITRE Corporation. "CWE-705: Incorrect Control Flow Scoping." https://cwe.mitre.org/data/definitions/705.html
- CWE-691: Insufficient Control Flow Management.
- CWE-698: Execution After Redirect.