CVE-2026-61701 Overview
CVE-2026-61701 is an insecure deserialization vulnerability [CWE-502] in the Laravel MagicLink package. The package creates passwordless authentication links and links for accessing private content. Versions from 2.0.0 through 2.25.0 store serialized action objects in the magic_links.action database column. The package deserializes those objects through src/MagicLink.php and src/Actions/ResponseAction.php without sufficient integrity protection. An unsafe legacy unserialize() fallback remains reachable in vulnerable versions. An attacker who can write to the magic_links table can inject a malicious serialized object graph, triggering arbitrary code execution when the corresponding magic link is visited. The issue is fixed in version 2.25.1.
Critical Impact
Attackers with database write access can achieve remote code execution in the Laravel application process by visiting a crafted magic link.
Affected Products
- Laravel MagicLink versions 2.0.0 through 2.25.0
- Laravel applications embedding the cesargb/laravel-magiclink package
- Deployments retaining legacy serialized action records in the magic_links table
Discovery Timeline
- 2026-09-14 - CVE-2026-61701 published to the National Vulnerability Database
- 2026-09-14 - Last updated in the NVD database
Technical Details for CVE-2026-61701
Vulnerability Analysis
Laravel MagicLink persists action objects for each generated link by serializing them into the magic_links.action database column. When a user visits a magic link, the MagicLinkController retrieves the record by token and invokes run(), which deserializes the stored payload. In vulnerable versions, the package retains a legacy unserialize() code path that does not enforce integrity checks such as signed serialization. This path processes attacker-controlled bytes as native PHP objects.
Because the deserializer accepts arbitrary object graphs, an attacker can inject gadget chains that abuse PHP magic methods such as __wakeup and __destruct. Popular gadgets available in Laravel and its dependencies allow escalation from object instantiation to arbitrary code execution inside the application process. The affected path is limited to already manipulated action records and does not independently grant database write access.
Root Cause
The root cause is unsafe deserialization of a persisted, mutable field combined with a legacy code path that bypasses signed serialization enforcement. ResponseAction previously imported Laravel\SerializableClosure\Serializers\Signed, but the fallback allowed unsigned legacy payloads to be processed, defeating the integrity boundary between the database and application logic.
Attack Vector
Exploitation requires the ability to modify rows in the magic_links table. An attacker chains this vulnerability with a separate SQL injection flaw, compromised administrative access, or stolen database credentials. After inserting a crafted serialized object into the action column, the attacker visits the associated token URL. The controller deserializes the malicious payload and triggers the gadget chain, resulting in code execution as the Laravel process user.
// Patch: src/Controllers/MagicLinkController.php
namespace MagicLink\Controllers;
use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\Log;
use MagicLink\Exceptions\LegacyActionFormatException;
use MagicLink\MagicLink;
class MagicLinkController extends Controller
{
public function access($token)
{
try {
return MagicLink::getMagicLinkByToken($token)->run();
} catch (LegacyActionFormatException $e) {
Log::error('Legacy action format detected for token: '.$token.'. Error: '.$e->getMessage());
return response()->json(['message' => 'This magic link is no longer valid. Please request a new one.'], 419);
}
}
}
Source: GitHub Commit 19fa820
The patch removes the legacy action format path and raises LegacyActionFormatException when unsigned or legacy serialized records are encountered, blocking deserialization of untrusted payloads.
Detection Methods for CVE-2026-61701
Indicators of Compromise
- Unexpected or oversized binary blobs in the magic_links.action column that do not match signed serialization format
- Log entries containing LegacyActionFormatException after upgrading to 2.25.1
- Outbound network connections or spawned child processes originating from the PHP-FPM or Laravel worker process shortly after a magic link request
- Modifications to magic_links rows performed by database accounts that do not normally issue writes
Detection Strategies
- Inspect magic_links.action values for serialized PHP object markers such as O: followed by class names not owned by the application
- Correlate HTTP GET requests to magic link routes with subsequent process creation or file writes on the web server
- Enable Laravel application logging for the MagicLink controller and alert on 419 responses that indicate blocked legacy payloads
- Run database audit logging on the magic_links table to identify unauthorized INSERT or UPDATE statements
Monitoring Recommendations
- Ingest web server, PHP, and database audit logs into a centralized analytics platform for cross-source correlation
- Alert on PHP processes executing shell binaries such as /bin/sh, bash, curl, or wget
- Track version metadata for the cesargb/laravel-magiclink Composer package across all Laravel deployments
How to Mitigate CVE-2026-61701
Immediate Actions Required
- Upgrade cesargb/laravel-magiclink to version 2.25.1 or later using composer update cesargb/laravel-magiclink
- Invalidate all existing magic link tokens by truncating or clearing the magic_links table after upgrade
- Rotate database credentials and review privileges on the magic_links table to enforce least privilege
- Audit application logs and web server access logs for suspicious visits to magic link endpoints
Patch Information
The maintainer released the fix in Laravel MagicLink v2.25.1. The patch is tracked in Pull Request #148 and commit 19fa820. Additional detail is available in the GitHub Security Advisory GHSA-r33w-fg8j-9c94. The fix removes the legacy action format path and enforces the migration to signed serialization.
Workarounds
- Temporarily disable magic link routes by removing the package route registration until the upgrade is deployed
- Restrict database user permissions so that only the Laravel application account can write to the magic_links table
- Deploy a web application firewall rule to block requests to the magic link endpoint from untrusted networks
- Delete any pre-existing legacy serialized records from magic_links.action before re-enabling the feature
# Upgrade the package and clear stale magic link records
composer require cesargb/laravel-magiclink:^2.25.1
php artisan migrate
php artisan tinker --execute="DB::table('magic_links')->truncate();"
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.