Missing Report of Error Condition

Description

Missing Report of Error Condition is a vulnerability that occurs when software encounters an error but does not provide a status code or return value to indicate that an error has occurred. Unlike CWE-390 where errors are detected but ignored, this weakness involves operations that fail to communicate their failure status to callers. The calling code has no way to know an error occurred and proceeds as if the operation succeeded, potentially leading to security vulnerabilities or data corruption.

Risk

When errors go unreported, systems enter unexpected states without any indication of the problem. Security-critical operations that fail silently may appear to have executed correctly, leading to false assurances of protection. Cryptographic operations that fall back to insecure methods without reporting the fallback can expose sensitive data. Authentication and validation functions that return success despite failures enable unauthorized access. Data integrity is compromised when write operations claim success but actually failed. The lack of error reporting makes debugging and incident response extremely difficult.

Solution

Design functions to always communicate their success or failure status through return values, exceptions, or output parameters. Document all possible error conditions and their corresponding return values. For security-critical functions, fail closed by returning an error state rather than proceeding silently. Use appropriate HTTP status codes in web applications to indicate error conditions. Implement proper logging for all error conditions even when returning error status. Consider using exceptions in languages that support them to make error handling explicit and harder to ignore.

Common Consequences

ImpactDetails
IntegrityScope: Integrity

When errors go unreported, systems can enter unexpected states leading to unintended behaviors.
OtherScope: Other

Callers cannot make informed decisions when error conditions are not communicated.

Example Code

Vulnerable Code

// Vulnerable: Returns 200 OK despite error
@WebServlet("/process")
public class VulnerableServlet extends HttpServlet {

    protected void doPost(HttpServletRequest request,
                          HttpServletResponse response)
                          throws ServletException, IOException {
        try {
            processPayment(request);
        } catch (PaymentException e) {
            // Vulnerable: Logs error but returns success
            logger.error("Payment failed: " + e.toString());
            return;  // Returns HTTP 200 OK!
        }

        response.getWriter().write("Success");
    }
}

// Vulnerable: Returns success despite validation failure
public class VulnerableValidator {

    public boolean validateInput(String input) {
        try {
            performValidation(input);
            return true;
        } catch (ValidationException e) {
            // Vulnerable: Returns true despite failure
            logger.warn("Validation issue: " + e);
            return true;  // Should return false!
        }
    }
}
// Vulnerable: No way to report error to caller
void vulnerable_crypto_init() {
    if (hardware_crypto_available()) {
        use_hardware_crypto();
    } else {
        // Vulnerable: Silently falls back to weaker implementation
        use_software_crypto();
        // Caller has no idea weaker crypto is being used!
    }
}

// Vulnerable: Returns success code despite failure
int vulnerable_pin_validate(const char *pin) {
    if (strlen(pin) != 4) {
        log_error("Invalid PIN length");
        return 0;  // Vulnerable: 0 means OK in this API
    }

    if (!is_numeric(pin)) {
        log_error("PIN must be numeric");
        return 0;  // Vulnerable: Returns success!
    }

    return verify_pin(pin);
}
# Vulnerable: Silent fallback to insecure method
def vulnerable_random_bytes(length):
    try:
        return os.urandom(length)
    except NotImplementedError:
        # Vulnerable: Falls back to insecure random without reporting
        import random
        return bytes([random.randint(0, 255) for _ in range(length)])

# Vulnerable: Returns None instead of raising exception
def vulnerable_authenticate(username, password):
    user = database.find_user(username)

    if user is None:
        # Vulnerable: Returns None, same as success case below
        return None

    if verify_password(password, user.password_hash):
        return user

    # Vulnerable: Returns None on auth failure too
    return None

Fixed Code

// Fixed: Return appropriate status codes
@WebServlet("/process")
public class SecureServlet extends HttpServlet {

    protected void doPost(HttpServletRequest request,
                          HttpServletResponse response)
                          throws ServletException, IOException {
        try {
            processPayment(request);
            response.setStatus(HttpServletResponse.SC_OK);
            response.getWriter().write("{\"status\": \"success\"}");
        } catch (PaymentException e) {
            // Fixed: Return error status code
            logger.error("Payment failed: " + e.toString());
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            response.getWriter().write("{\"status\": \"error\", \"message\": \"Payment processing failed\"}");
        }
    }
}

// Fixed: Return proper validation result
public class SecureValidator {

    public ValidationResult validateInput(String input) {
        try {
            performValidation(input);
            return ValidationResult.success();
        } catch (ValidationException e) {
            // Fixed: Report the failure
            logger.warn("Validation failed: " + e);
            return ValidationResult.failure(e.getMessage());
        }
    }
}
// Fixed: Return status indicating which crypto is used
typedef enum {
    CRYPTO_HARDWARE,
    CRYPTO_SOFTWARE,
    CRYPTO_FAILED
} CryptoStatus;

CryptoStatus secure_crypto_init() {
    if (hardware_crypto_available()) {
        if (use_hardware_crypto() == 0) {
            return CRYPTO_HARDWARE;
        }
    }

    // Fixed: Report fallback to software crypto
    if (use_software_crypto() == 0) {
        log_warning("Using software cryptography");
        return CRYPTO_SOFTWARE;
    }

    log_error("Crypto initialization failed");
    return CRYPTO_FAILED;
}

// Fixed: Proper error codes
typedef enum {
    PIN_OK = 0,
    PIN_INVALID_LENGTH = -1,
    PIN_NOT_NUMERIC = -2,
    PIN_VERIFY_FAILED = -3
} PinStatus;

PinStatus secure_pin_validate(const char *pin) {
    if (strlen(pin) != 4) {
        log_error("Invalid PIN length");
        return PIN_INVALID_LENGTH;  // Fixed: Error code
    }

    if (!is_numeric(pin)) {
        log_error("PIN must be numeric");
        return PIN_NOT_NUMERIC;  // Fixed: Error code
    }

    if (verify_pin(pin) != 0) {
        return PIN_VERIFY_FAILED;  // Fixed: Error code
    }

    return PIN_OK;
}
# Fixed: Raise exception for fallback or report in return value
def secure_random_bytes(length):
    try:
        return os.urandom(length)
    except NotImplementedError:
        # Fixed: Raise exception for security-critical failure
        raise CryptoError("Secure random not available")

# Alternative: Return status along with result
def secure_random_bytes_with_status(length):
    try:
        return (os.urandom(length), "hardware")
    except NotImplementedError:
        import secrets
        return (secrets.token_bytes(length), "software")

# Fixed: Distinguish error conditions in return
def secure_authenticate(username, password):
    user = database.find_user(username)

    if user is None:
        # Fixed: Raise specific exception
        raise UserNotFoundError(f"User not found: {username}")

    if verify_password(password, user.password_hash):
        return user

    # Fixed: Raise exception for auth failure
    raise AuthenticationError("Invalid password")

# Alternative: Return result object with status
class AuthResult:
    def __init__(self, success, user=None, error=None):
        self.success = success
        self.user = user
        self.error = error

def secure_authenticate_with_result(username, password):
    user = database.find_user(username)

    if user is None:
        return AuthResult(False, error="User not found")

    if verify_password(password, user.password_hash):
        return AuthResult(True, user=user)

    return AuthResult(False, error="Invalid password")

CVE Examples

  • CVE-2004-0063 — Crypto library falls back to insecure random number generation without reporting failure.
  • CVE-2002-1446 — Function returns "OK" despite invalid PIN validation.
  • CVE-2002-0499 — PKCS#11 library returns success on invalid signature detection.
  • CVE-2005-2459 — Kernel truncates pathnames silently, operating on wrong directory.

References

  1. MITRE Corporation. "CWE-392: Missing Report of Error Condition." https://cwe.mitre.org/data/definitions/392.html