Always-Incorrect Control Flow Implementation
Description
Always-Incorrect Control Flow Implementation occurs when code contains logic that will always produce incorrect behavior regardless of input or program state. This includes impossible conditions, unreachable code paths, conditions that can never be true/false, and logic errors that make security checks ineffective. Unlike conditional bugs that only trigger under certain circumstances, these flaws are fundamentally broken in all cases.
Risk
Security checks that never execute. Authentication bypass when conditions are inverted. Authorization always granted or denied incorrectly. Critical code paths never reached. Error handling that never triggers. Validation that always passes or fails regardless of input.
Solution
Use static analysis to detect dead code and impossible conditions. Review control flow for logical correctness. Test both positive and negative paths. Use code coverage to find unreachable code. Implement proper boolean logic in security checks. Review comparisons for type mismatches.
Common Consequences
| Impact | Details |
|---|---|
| Authorization | Scope: Complete Bypass Security checks always fail or succeed. |
| Integrity | Scope: Logic Errors Code never behaves as intended. |
| Availability | Scope: Functionality Broken Expected features never work. |
Example Code + Solution Code
Vulnerable Code
// VULNERABLE: Always-incorrect control flow in C
#include <stdio.h>
#include <string.h>
// VULNERABLE: Condition is always true
int check_auth_vulnerable1(char* password) {
// VULNERABLE: Assignment instead of comparison
if (password = "secret") { // Always true (non-null pointer)
return 1; // Always authenticated!
}
return 0; // Never reached
}
// VULNERABLE: Condition is always false
int check_auth_vulnerable2(char* password) {
// VULNERABLE: Comparing pointers, not strings
if (password == "secret") { // Almost always false
return 1; // Never reached unless same literal
}
return 0; // Always returned
}
// VULNERABLE: Unsigned comparison always true
int validate_index_vulnerable(unsigned int index) {
// VULNERABLE: Unsigned is always >= 0
if (index >= 0) { // Always true
return 1; // Always valid!
}
return 0; // Never reached
}
// VULNERABLE: Logic error with return
int process_vulnerable(int value) {
if (value > 0) {
return 1;
}
// VULNERABLE: Early return makes this unreachable
return 0;
// This security check never executes
if (!validate_value(value)) {
log_error("Invalid value");
return -1;
}
}
// VULNERABLE: Semicolon after if
void security_check_vulnerable(int user_level) {
if (user_level < ADMIN_LEVEL); // VULNERABLE: Semicolon!
{
// This block always executes
grant_admin_access();
}
}
// VULNERABLE: Bitwise vs logical operator
int check_permissions_vulnerable(int perm1, int perm2) {
// VULNERABLE: & instead of &&
if (perm1 & perm2) { // Bitwise AND, not logical
// May not work as expected
return 1;
}
return 0;
}
# VULNERABLE: Python always-incorrect control flow
class VulnerableAuth:
# VULNERABLE: Always True condition
def check_password_vulnerable1(self, password):
# VULNERABLE: 'is' compares identity, not equality
# String literals may or may not be interned
if password is "secret": # Usually False
return True
return False # Almost always returned
# VULNERABLE: Wrong return placement
def validate_vulnerable(self, data):
return True # VULNERABLE: Always returns True first
# This validation never runs
if not self.is_valid(data):
raise ValueError("Invalid data")
# VULNERABLE: Empty condition block
def process_vulnerable(self, value):
if value < 0:
pass # VULNERABLE: Does nothing
# Negative values not handled!
self.process_value(value) # Processes negative values
# VULNERABLE: Mutable default argument
def add_permission_vulnerable(self, perm, perms=[]):
# VULNERABLE: perms shared between all calls
perms.append(perm)
return perms # Accumulates across calls!
# VULNERABLE: Boolean short-circuit mistake
def check_access_vulnerable(self, user, resource):
# VULNERABLE: Second condition never evaluated if first is True
if True or self.has_permission(user, resource):
return True
return False
# VULNERABLE: Exception handling that catches everything
def process_request_vulnerable(request):
try:
result = dangerous_operation(request)
except: # VULNERABLE: Catches all exceptions
pass # VULNERABLE: Silently ignores errors
return result # May be undefined!
// VULNERABLE: Java always-incorrect control flow
public class VulnerableControlFlow {
// VULNERABLE: String comparison with ==
public boolean checkPassword(String password) {
// VULNERABLE: == compares references, not content
if (password == "secret") { // Usually false
return true; // Rarely reached
}
return false;
}
// VULNERABLE: Always-false due to null check order
public boolean validateUser(User user) {
// VULNERABLE: user.getRole() called before null check
if (user.getRole().equals("admin") && user != null) {
return true; // NPE if user is null
}
return false;
}
// VULNERABLE: Unreachable code
public int calculate(int value) {
if (value > 0) {
return value * 2;
} else {
return value * -1;
}
// VULNERABLE: Never reached
if (isSpecialValue(value)) {
return handleSpecial(value);
}
}
// VULNERABLE: Boolean literal comparison
public boolean isActive(boolean flag) {
// VULNERABLE: Redundant and error-prone
if (flag == true) { // Works but could be == false by mistake
return true;
}
return false;
}
// VULNERABLE: instanceof with wrong type
public void process(Object obj) {
// VULNERABLE: Always false if obj can never be String here
if (obj instanceof Integer && obj instanceof String) { // Impossible
// Never executed
handleSpecial(obj);
}
}
// VULNERABLE: Inverted condition
public void securityCheck(User user, Resource resource) {
// VULNERABLE: ! negates entire expression when only want first part
if (!user.isAuthenticated() && user.hasPermission(resource)) {
// Intended: authenticated AND has permission
// Actual: NOT authenticated AND has permission
grantAccess(resource); // Wrong users get access
}
}
}
// VULNERABLE: JavaScript always-incorrect control flow
class VulnerableAuth {
// VULNERABLE: Type coercion issues
checkAuth(input) {
// VULNERABLE: '==' performs type coercion
if (input == true) { // "1" == true is true
return true; // Unintended truthy values pass
}
// Also vulnerable: '' == false, 0 == false, etc.
return false;
}
// VULNERABLE: Assignment in condition
checkAdmin(role) {
// VULNERABLE: Single = is assignment
if (role = 'admin') { // Always truthy (non-empty string)
return true; // Everyone is admin!
}
return false;
}
// VULNERABLE: Array/Object truthiness
checkPermissions(perms) {
// VULNERABLE: Empty array is truthy
if (perms) { // [] is truthy!
return true; // Empty permissions still passes
}
return false;
}
// VULNERABLE: typeof comparison error
validateInput(value) {
// VULNERABLE: typeof returns string, comparing to undefined fails
if (typeof value === undefined) { // Always false
return false; // Never reached
}
// Should be: typeof value === 'undefined'
return true; // Everything passes
}
// VULNERABLE: NaN comparison
validateNumber(num) {
// VULNERABLE: NaN !== NaN
if (num !== NaN) { // Always true (even for NaN!)
return true; // NaN passes validation
}
return false;
}
// VULNERABLE: Floating point comparison
checkBalance(amount, required) {
// VULNERABLE: Floating point precision issues
if (0.1 + 0.2 === 0.3) { // False! (0.30000000000000004)
// This code never executes
return amount >= required;
}
return false; // Always returned
}
}
// VULNERABLE: Hoisting issues
function processVulnerable(value) {
if (value > 0) {
return process(value);
}
// VULNERABLE: Variable hoisting makes this undefined, not error
return result; // Always undefined
var result = calculate(value); // Never executed
}
Fixed Code
// SAFE: Correct control flow in C
#include <stdio.h>
#include <string.h>
// SAFE: Proper comparison
int check_auth_safe1(const char* password) {
// SAFE: strcmp for string comparison
if (strcmp(password, "secret") == 0) {
return 1;
}
return 0;
}
// Alternative: Use == with constant on left (Yoda condition)
int check_auth_safe2(const char* password) {
// Compiler error if = used instead of ==
if (NULL == password) {
return 0;
}
return strcmp(password, "secret") == 0;
}
// SAFE: Proper bounds checking
int validate_index_safe(int index, int max_size) {
// SAFE: Signed integer properly checked
if (index >= 0 && index < max_size) {
return 1;
}
return 0;
}
// SAFE: Proper control flow order
int process_safe(int value) {
// Validation first
if (!validate_value(value)) {
log_error("Invalid value");
return -1;
}
if (value > 0) {
return 1;
}
return 0;
}
// SAFE: No semicolon after if
void security_check_safe(int user_level) {
if (user_level >= ADMIN_LEVEL) {
grant_admin_access();
}
}
// SAFE: Logical operators
int check_permissions_safe(int has_perm1, int has_perm2) {
// SAFE: Logical AND
if (has_perm1 && has_perm2) {
return 1;
}
return 0;
}
# SAFE: Python correct control flow
class SafeAuth:
# SAFE: Proper string comparison
def check_password_safe(self, password):
# SAFE: == compares values
if password == "secret":
return True
return False
# SAFE: Correct return placement
def validate_safe(self, data):
# Validation runs first
if not self.is_valid(data):
raise ValueError("Invalid data")
return True # Only after validation
# SAFE: Proper negative handling
def process_safe(self, value):
if value < 0:
raise ValueError("Negative value not allowed")
self.process_value(value)
# SAFE: No mutable default argument
def add_permission_safe(self, perm, perms=None):
if perms is None:
perms = [] # New list each call
perms.append(perm)
return perms
# SAFE: Proper boolean logic
def check_access_safe(self, user, resource):
if self.has_permission(user, resource):
return True
return False
# SAFE: Specific exception handling
def process_request_safe(request):
try:
result = operation(request)
return result
except ValidationError as e:
log_error(f"Validation failed: {e}")
return None
except OperationError as e:
log_error(f"Operation failed: {e}")
raise
// SAFE: Java correct control flow
public class SafeControlFlow {
// SAFE: equals() for string comparison
public boolean checkPassword(String password) {
if ("secret".equals(password)) { // Also null-safe
return true;
}
return false;
}
// SAFE: Null check first
public boolean validateUser(User user) {
if (user != null && "admin".equals(user.getRole())) {
return true;
}
return false;
}
// SAFE: All paths reachable
public int calculate(int value) {
if (isSpecialValue(value)) {
return handleSpecial(value);
}
if (value > 0) {
return value * 2;
} else {
return value * -1;
}
}
// SAFE: Direct boolean usage
public boolean isActive(boolean flag) {
return flag; // No comparison needed
}
// SAFE: Logical instanceof checks
public void process(Object obj) {
if (obj instanceof Integer) {
handleInteger((Integer) obj);
} else if (obj instanceof String) {
handleString((String) obj);
}
}
// SAFE: Clear boolean logic
public void securityCheck(User user, Resource resource) {
// SAFE: Parentheses make intent clear
if (user.isAuthenticated() && user.hasPermission(resource)) {
grantAccess(resource);
}
}
}
// SAFE: JavaScript correct control flow
class SafeAuth {
// SAFE: Strict equality
checkAuth(input) {
if (input === true) { // Only actual true passes
return true;
}
return false;
}
// SAFE: Proper comparison
checkAdmin(role) {
if (role === 'admin') { // Correct comparison
return true;
}
return false;
}
// SAFE: Check array length
checkPermissions(perms) {
if (Array.isArray(perms) && perms.length > 0) {
return true;
}
return false;
}
// SAFE: Correct typeof usage
validateInput(value) {
if (typeof value === 'undefined') { // String comparison
return false;
}
return true;
}
// SAFE: NaN check using Number.isNaN
validateNumber(num) {
if (Number.isNaN(num)) {
return false; // Properly detects NaN
}
return true;
}
// SAFE: Epsilon comparison for floats
checkBalance(amount, required) {
const epsilon = 0.0001;
const sum = 0.1 + 0.2;
if (Math.abs(sum - 0.3) < epsilon) {
return amount >= required;
}
return false;
}
}
// SAFE: Proper variable declaration
function processSafe(value) {
if (value > 0) {
return process(value);
}
// Use let/const to avoid hoisting issues
const result = calculate(value);
return result;
}
// SAFE: Using linter rules
// eslint: eqeqeq, no-cond-assign, no-unreachable
Exploited in the Wild
Authentication Bypass
Inverted conditions granting access to everyone.
Authorization Failures
Security checks that never execute.
Logic Bombs
Unreachable code containing backdoors.
Tools to test/exploit
-
Static analyzers (dead code detection).
-
Linters (eslint, pylint, checkstyle).
-
Compiler warnings (-Wall).
CVE Examples
-
Various CVEs from logic errors in authentication.
-
Security bypass from inverted conditions.
References
-
MITRE. "CWE-670: Always-Incorrect Control Flow Implementation." https://cwe.mitre.org/data/definitions/670.html
-
Static analysis best practices.