Insufficient Numeric Precision

Author: Abdullah Al-Khalaf

NVD Categorization

CWE-1339: Insufficient Precision or Accuracy of a Real Number: The product processes a real number with an implementation in which the number’s representation does not preserve required accuracy and precision in its fractional part, causing an incorrect result.

Description

The use of real numbers with insufficient precision, such as double or float in most languages, can lead to unpredictable results and introduce bugs that attackers can exploit.

Examples

Example 1.0

In this scenario, a vulnerable bank uses the insufficient precision number data type, double:

public class VulnBank {  
    private double balance = 0.0;  
  
    public void deposit(double amount) {  
        balance += amount;  
    } 
    public void showBalance() {  
        System.out.println("Balance: " + balance);  
    }
    
    ...
      
}

An Attacker could deposit 0.1 dollar multiple times like so:

VulnBank attackerAcc = new VulnBank();
attackerAcc.deposit(0.1);
attackerAcc.deposit(0.1);
attackerAcc.deposit(0.1);
attackerAcc.showBalance();

One might believe the output would be Balance: 0.3, as it should. However, it outputs: Balance: 0.30000000000000004

At first glance, this is a negligible amount, but an attacker could do it multiple times, gaining significant profits.

Solution

In many programming languages, they have a reliable decimal data type, for example, BigDecimal in Java, decimal.Decimal in Python, etc.

For example, the fixed code in Example 1.0 would be

import java.math.BigDecimal;

public class FixedVulnBank {  
    BigDecimal balance = BigDecimal.ZERO;  
  
    public void deposit(BigDecimal amount) {  
        balance = balance.add(amount);  
    }  
  
    public void showBalance() {  
        System.out.println("Balance: " + balance);  
    }
    
    ...
    
}

And the program would look like

FixedVulnBank acc = new FixedVulnBank();  
acc.deposit(new BigDecimal("0.1"));  
acc.deposit(new BigDecimal("0.1"));  
acc.deposit(new BigDecimal("0.1"));  
acc.showBalance(); // output: Balance: 0.3

References