Type Juggling

what is Type Juggling?

In PHP, type juggling is an internal behaviour that results in the conversion of variables to other data types in specific contexts, such as when performing comparisons. While this is not inherently a security vulnerability, it can result in unexpected or undesired outcomes, potentially leading to security vulnerabilities depending on the specific web application.

image.png

PHP Loose vs. Strict Comparisons

Unlike other programming languages, PHP supports two distinct types of comparisons: loose comparisons, which are performed with two equal signs (==), and strict comparisons, which are performed with three equal signs (===). A loose comparison compares two values after type juggling, whereas a strict comparison compares two values and their corresponding data types. As an example, consider the following code snippet:

$a = 42;
$b = "42";

// loose comparison
if ($a == $b) { echo "Loose Comparison";}

// strict comparison
if ($a === $b) { echo "Strict Comparison";}

image.png

The behavior of type juggling in a comparison context is documented here. Here are some important cases:

Operand 1 Operand 2 Behavior
string string Numerical or lexical comparison
null string Convert null to ""
null anything but string Convert both sides to bool
bool anything Convert both sides to bool
int string Convert string to int
float string Convert string to float

image.png

Type Juggling Examples

For example, consider the comparison 1 == "1HelloWorld" which evaluates to true. Since the first operand is an int and the second operand is a string, PHP converts the string to an integer. When converting "1HelloWorld" to an integer, the result is 1. Thus, the comparison evaluates to true after type juggling.

image.png

A potentially even more odd example is the result of min(-1, null, 1), which is null. The function min computes the minimum of the provided arguments and returns it. To do so, the function compares the different arguments. When evaluating null < 1, both sides are converted to booleans. The integer 1 is converted to true while null is converted to false. It holds that false < true. Furthermore, the same methodology is applied when evaluating null < -1. The integer -1 is also converted to true. Thus, overall it holds that null < 1 and null < -1. Thus, null is the minimum of the provided arguments.

image.png

As a final example, let us consider the comparison "00" == "0e123". Intuitively, this comparison should evaluate to false since the arguments are both strings, and the strings are obviously different. This is a special case in which PHP performs a numerical comparison of the two strings, resulting in a conversion to numbers. The e in the second argument is the scientific notation for floats, as we can see here. When both arguments are converted to numbers, the result is 0 for both sides. Thus, PHP evaluates the comparison as true.

image.png

Now let us have a look at the full behavior of a loose comparison, which can be found here:

true false 1 0 -1 "1" "0" "-1" null [] "php" ""
true
false
1
0 ✓ (< PHP 8.0.0) ✓ (< PHP 8.0.0)
-1
"1"
"0"
"-1"
null
[]
"php" ✓ (< PHP 8.0.0)
"" ✓ (< PHP 8.0.0)