-
Notifications
You must be signed in to change notification settings - Fork 8k
Description
Description
This bug may seem trivial and unimportant at first glance, but it's quite a massive security issue where strtotime is used to limit/allow access for example.
The following code: https://3v4l.org/EnM7A#v8.4.13
(echo date('m', strtotime('-1 month', strtotime( '2025-03-31' ) ) ) . PHP_EOL;
has the same bug just fyi)
<?php
echo date('m', strtotime('2025-03-31 -1 month')) . PHP_EOL;
echo date('m', strtotime('2025-03-30 -1 month')) . PHP_EOL;
echo date('m', strtotime('2025-05-31 -1 month')) . PHP_EOL;
echo date('m', strtotime('2025-05-30 -1 month')) . PHP_EOL;
Resulted in this output:
03
03
05
04
But I expected this output instead:
02
02
04
04
When using 2 months, then it works correctly for all months, except the ones that would end up with February it seems, e.g.
echo date('m', strtotime('2025-04-30 -2 months')) . PHP_EOL;
echo date('m', strtotime('2025-06-30 -2 months')) . PHP_EOL;
results in
03
04
but should be
02
04
Same issue with +, e.g.
echo date('m', strtotime('2025-01-30 +1 month')) . PHP_EOL;
echo date('m', strtotime('2025-03-31 +1 month')) . PHP_EOL;
results in
03
05
expected
02
04
This seems to be related/caused by another 2 bugs:
echo date('Y-m-d', strtotime('2025-02-30 -4 weeks')) . PHP_EOL;
echo date('Y-m-d', strtotime('2025-02-32 -4 weeks')) . PHP_EOL;
outputs:
2025-02-02
1970-01-01
But should be false in both cases, since there is no February 30th
The 2nd case however, is where this actually becomes a dangerous issue not only in the full date case example, but especially when not using Y-m-d but just 'm', you'll end up with "01" only, which is extremely bad.
If using this for any kind of validation (e.g. nonce, refund period,...) this is a security risk
It seems to work correctly for + and - when using year (e.g. leap years) though
PHP Version
all PHP versions up to, including PHP 8.5
Operating System
No response