Skip to content

CWE-398: Indicator of Poor Code Quality

Overview

Poor code quality indicators (complex logic, dead code, inconsistent error handling, lack of input validation, poor resource management) create conditions where security vulnerabilities thrive, making code harder to review, test, and maintain securely.

Risk

Medium: Poor code quality enables overlooked vulnerabilities, difficult security reviews, untested edge cases, resource leaks, inconsistent security controls, maintenance errors introducing bugs, and reduced confidence in security posture.

Remediation Steps

Core principle: Treat poor error/edge-case handling as security risk; make defensive checks explicit and consistent.

Locate the poor code quality indicators

  • Review the flaw details to identify the specific file, line number, and code pattern with quality issues
  • Identify the quality issue: empty catch blocks, dead code, unused variables, missing validation, resource leaks, high complexity
  • Determine the security impact: does this quality issue create or hide a vulnerability
  • Trace the code to understand what it's supposed to do and why the quality issue exists

Implement consistent error handling (Primary Defense)

  • Don't ignore exceptions (empty catch blocks): Replace catch (Exception e) { } with proper error handling
  • Log errors appropriately (not sensitive data): Log exception message and stack trace, but redact PII/credentials
  • Return meaningful error responses: Return user-friendly error messages to client, detailed errors to logs
  • Use structured exception handling: Catch specific exceptions (FileNotFoundException) instead of generic Exception

Remove dead/unreachable code

  • Delete commented-out code: Remove old code that's been commented out; use version control instead
  • Remove unused variables, functions: Delete variables that are declared but never used
  • Eliminate unreachable branches: Remove if (false) blocks, code after return statements
  • Clean up debugging code: Remove System.out.println(), console.log(), temporary test code

Reduce complexity

  • Break large functions into smaller ones: Extract methods when function exceeds 50 lines or does multiple things
  • Reduce cyclomatic complexity: Simplify nested if/else chains, reduce number of decision points
  • Simplify nested conditionals: Use early returns, combine conditions with &&/||, extract condition into named method
  • Use early returns: Return early on error conditions instead of nesting the success path

Follow secure coding standards

  • Validate all inputs: Check parameters for null, range, format, length before use
  • Use parameterized queries: Prevent SQL injection with prepared statements
  • Implement proper resource cleanup: Use try-with-resources, finally blocks, or using statements
  • Apply principle of least privilege: Don't run with admin/root unless necessary

Test the code quality improvements

  • Run static analysis tools: SonarQube, PMD, FindBugs to verify improvements
  • Verify complexity metrics improved: Check cyclomatic complexity reduced
  • Test that error handling works: Trigger error conditions, verify proper error responses
  • Verify no dead code remains: Run code coverage, ensure all code paths are reachable
  • Re-scan with security scanner to confirm the issue is resolved

Common Poor Quality Patterns

// Empty catch
try {
    dangerous();
} catch (Exception e) {
    // TODO: handle
}

// Dead code
if (false) {
    // Never executes
}

// Unused variables
String password = getPassword();  // Never used

// No validation
public void setAge(int age) {
    this.age = age;  // No range check
}

// Resource leak
InputStream is = new FileInputStream(file);
// No close()

Better Patterns

// Proper error handling
try {
    dangerous();
} catch (SpecificException e) {
    log.error("Operation failed", e);
    throw new ServiceException("Unable to process", e);
}

// Input validation
public void setAge(int age) {
    if (age < 0 || age > 150) {
        throw new IllegalArgumentException("Invalid age");
    }
    this.age = age;
}

// Resource management
try (InputStream is = new FileInputStream(file)) {
    process(is);
}

Additional Resources