Try BS100234 / password123, or bypass with ADMIN001' -- (trailing space).
78 $sql = "SELECT id, customer_id, name, role FROM users "79 . "WHERE customer_id = '" . $cid . "' "80 . "AND password_md5 = '" . md5($password) . "' LIMIT 1";30 $stmt = $pdo->prepare(31 'SELECT id, customer_id, name, role, password_hash, is_locked, locked_until32 FROM users WHERE customer_id = :cid LIMIT 1'33 );34 $stmt->execute([':cid' => $customerId]);35 $row = $stmt->fetch();53 if ($row && password_verify($password, (string) $row['password_hash'])) {54 auth_reset_failures($pdo, (int) $row['id']);55 unset($row['password_hash'], $row['is_locked'], $row['locked_until']);56 return ['ok' => true, 'user' => $row, 'error' => null, 'locked' => false];57 }91 if ($secure) {92 // Rate-limit OTP verification the same way as login (shared counter).93 if (auth_is_locked($pdo, $userId)) {94 return false;95 }96 }91 if ($secure) {92 // Rate-limit OTP verification the same way as login (shared counter).93 if (auth_is_locked($pdo, $userId)) {94 return false;95 }96 }61 if ($level === 0) {62 return ['otp' => $code];63 }64 if ($level === 1) {65 // "Nested deeper" so it looks like an innocuous debug block.66 return ['debug' => ['sms' => ['to' => '+91*****', 'otp' => $code, 'sent' => true]]];67 }70 return [];64 if (self::isSecureLevel()) {65 self::regenerate();66 }67 // level 0: deliberately do nothing -> fixation.64 if (self::isSecureLevel()) {65 self::regenerate();66 }67 // level 0: deliberately do nothing -> fixation.102 $exists = $pdo->prepare('SELECT 1 FROM users WHERE customer_id = :cid LIMIT 1');103 $exists->execute([':cid' => $customerId]);104 $error = $exists->fetchColumn()105 ? 'Incorrect password.'106 : 'Customer ID not found.';110 $error = 'Invalid credentials.';⚠ Intentionally vulnerable application — local security training only.