VYPR
High severityNVD Advisory· Published Dec 20, 2024· Updated Apr 15, 2026

CVE-2024-56329

CVE-2024-56329

Description

Socialstream is a third-party package for Laravel Jetstream. It replaces the published authentication and profile scaffolding provided by Laravel Jetstream, with scaffolding that has support for Laravel Socialite. When linking a social account to an already authenticated user, the lack of a confirmation step introduces a security risk. This is exacerbated if ->stateless() is used in the Socialite configuration, bypassing state verification and making the exploit easier. Developers should ensure that users explicitly confirm account linking and avoid configurations that skip critical security checks. Socialstream v6.2 introduces a new custom route that requires a user to "Confirm" or "Deny" a request to link a social account. Users are advised to upgrade. There are no known workarounds for this vulnerability.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
joelbutcher/socialstreamPackagist
>= 6.0.0, < 6.2.06.2.0
joelbutcher/socialstreamPackagist
< 5.6.05.6.0

Patches

1
ae4dc3906f54

Merge commit from fork

https://github.com/joelbutcher/socialstreamJoel ButcherDec 20, 2024via ghsa
5 files changed · +128 8
  • resources/views/oauth/prompt.blade.php+47 0 added
    @@ -0,0 +1,47 @@
    +<!DOCTYPE html>
    +<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
    +<head>
    +    <meta charset="utf-8">
    +    <meta name="viewport" content="width=device-width, initial-scale=1">
    +
    +    <title>Laravel</title>
    +
    +    <!-- Fonts -->
    +    <link rel="preconnect" href="https://fonts.bunny.net">
    +    <link href="https://fonts.bunny.net/css?family=figtree:400,500,600&display=swap" rel="stylesheet" />
    +
    +    <!-- Styles / Scripts -->
    +    <script src="https://cdn.tailwindcss.com"></script>
    +</head>
    +<body class="font-sans antialiased">
    +    <div class=" min-h-screen bg-gray-100 flex justify-center items-center dark:bg-gray-900">
    +        <div class="w-full sm:max-w-sm bg-white dark:bg-gray-800 overflow-hidden shadow-xl sm:rounded-lg px-6 py-4">
    +            <h2 class="mb-4 font-semibold text-xl text-gray-800 dark:text-gray-200 leading-tight">
    +                Confirm connection of your {{ \JoelButcher\Socialstream\Providers::name($provider) }} account.
    +            </h2>
    +
    +            <form method="POST" action="{{ route('oauth.callback.confirm', $provider) }}">
    +                @csrf
    +                <p class="text-sm text-gray-600 dark:text-gray-400">
    +                    @if (config('socialstream.confirmation-prompt'))
    +                        {{ config('socialstream.confirmation-prompt') }}
    +                    @else
    +                        To ensure you are the account owner of this {{ \JoelButcher\Socialstream\Providers::name($provider) }} account,
    +                        please confirm or deny the request below to link this provider to your account.
    +                    @endif
    +                </p>
    +
    +                <div class="mt-4 flex items-center justify-between">
    +                    <button type="submit" name="result" value="deny" class="inline-flex items-center justify-center px-4 py-2 bg-red-600 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest hover:bg-red-500 active:bg-red-700 focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2 dark:focus:ring-offset-gray-800 transition ease-in-out duration-150">
    +                        Deny
    +                    </button>
    +
    +                    <button type="submit" name="result" value="confirm" class="inline-flex items-center px-4 py-2 bg-gray-800 dark:bg-gray-200 border border-transparent rounded-md font-semibold text-xs text-white dark:text-gray-800 uppercase tracking-widest hover:bg-gray-700 dark:hover:bg-white focus:bg-gray-700 dark:focus:bg-white active:bg-gray-900 dark:active:bg-gray-300 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 dark:focus:ring-offset-gray-800 disabled:opacity-50 transition ease-in-out duration-150">
    +                        Confirm
    +                    </button>
    +                </div>
    +            </form>
    +        </div>
    +    </div>
    +</body>
    +</html>
    
  • routes/web.php+12 0 added
    @@ -0,0 +1,12 @@
    +<?php
    +
    +use Illuminate\Support\Facades\Route;
    +use JoelButcher\Socialstream\Http\Controllers\OAuthController;
    +
    +
    +Route::group(['middleware' => config('socialstream.middleware', ['web'])], function () {
    +    Route::get('/oauth/{provider}/callback/prompt', [OAuthController::class, 'prompt'])->name('oauth.callback.prompt');
    +    Route::post('/oauth/{provider}/callback/confirm', [OAuthController::class, 'confirm'])->name(
    +        'oauth.callback.confirm'
    +    );
    +});
    
  • src/Actions/AuthenticateOAuthCallback.php+6 8 modified
    @@ -65,7 +65,10 @@ public function authenticate(string $provider, ProviderUser $providerAccount): S
         {
             // If the user is authenticated, link the provider to the authenticated user.
             if ($user = auth()->user()) {
    -            return $this->link($user, $provider, $providerAccount);
    +            // cache the provider account for 10 mins whilst the user is redirected to the confirmation screen.
    +            cache()->put("socialstream.{$user->id}:$provider.provider", $providerAccount, ttl: new \DateInterval('PT10M'));
    +
    +            return redirect()->route('oauth.callback.prompt', $provider);
             }
     
             // Check if the user has an existing OAuth account.
    @@ -198,16 +201,11 @@ function ($request, $next) {
             ]));
         }
     
    -    /**
    -     * Attempt to link the provider to the authenticated user.
    -     *
    -     * Attempt to link the provider with the authenticated user.
    -     */
    -    private function link(Authenticatable $user, string $provider, ProviderUser $providerAccount): SocialstreamResponse
    +    public function link(Authenticatable $user, string $provider, ProviderUser $providerAccount): SocialstreamResponse
         {
             $account = Socialstream::findConnectedAccountForProviderAndId($provider, $providerAccount->getId());
     
    -        if ($account && $user?->id !== $account->user_id) {
    +        if ($account && $user->id !== $account->user_id) {
                 event(new OAuthProviderLinkFailed($user, $provider, $account, $providerAccount));
     
                 $this->flashError(
    
  • src/Http/Controllers/OAuthController.php+62 0 modified
    @@ -2,17 +2,25 @@
     
     namespace JoelButcher\Socialstream\Http\Controllers;
     
    +use Illuminate\Contracts\View\View;
     use Illuminate\Http\RedirectResponse;
     use Illuminate\Http\Request;
     use Illuminate\Http\Response;
     use Illuminate\Routing\Controller;
    +use Illuminate\Support\Facades\Cache;
     use Illuminate\Support\Facades\Session;
    +use Illuminate\Support\MessageBag;
    +use Illuminate\Support\ViewErrorBag;
     use JoelButcher\Socialstream\Contracts\AuthenticatesOAuthCallback;
     use JoelButcher\Socialstream\Contracts\GeneratesProviderRedirect;
     use JoelButcher\Socialstream\Contracts\HandlesInvalidState;
     use JoelButcher\Socialstream\Contracts\HandlesOAuthCallbackErrors;
     use JoelButcher\Socialstream\Contracts\ResolvesSocialiteUsers;
     use JoelButcher\Socialstream\Contracts\SocialstreamResponse;
    +use JoelButcher\Socialstream\Events\OAuthProviderLinkFailed;
    +use JoelButcher\Socialstream\Http\Responses\OAuthProviderLinkFailedResponse;
    +use JoelButcher\Socialstream\Providers;
    +use Laravel\Jetstream\Jetstream;
     use Laravel\Socialite\Two\InvalidStateException;
     use Symfony\Component\HttpFoundation\RedirectResponse as SymfonyRedirectResponse;
     
    @@ -59,4 +67,58 @@ public function callback(Request $request, string $provider): SocialstreamRespon
     
             return $this->authenticator->authenticate($provider, $providerAccount);
         }
    +
    +    /**
    +     * Show the oauth confirmation page.
    +     */
    +    public function prompt(string $provider): View
    +    {
    +        return view('socialstream::oauth.prompt', [
    +            'provider' => $provider,
    +        ]);
    +    }
    +
    +    public function confirm(string $provider): SocialstreamResponse|RedirectResponse
    +    {
    +        $user = auth()->user();
    +        $providerAccount = cache()->pull("socialstream.{$user->id}:$provider.provider");
    +
    +        $result = request()->input('result');
    +
    +        if ($result === 'deny') {
    +            event(new OAuthProviderLinkFailed($user, $provider, null, $providerAccount));
    +
    +            $this->flashError(
    +                __('Failed to link :provider account. User denied request.', ['provider' => Providers::name($provider)]),
    +            );
    +
    +            return app(OAuthProviderLinkFailedResponse::class);
    +        }
    +
    +        if (!$providerAccount) {
    +            throw new \DomainException(
    +                message: 'Could not retrieve social provider information.'
    +            );
    +        }
    +
    +        return $this->authenticator->link($user, $provider, $providerAccount);
    +    }
    +
    +    private function flashError(string $error): void
    +    {
    +        if (auth()->check()) {
    +            if (class_exists(Jetstream::class)) {
    +                Session::flash('flash.banner', $error);
    +                Session::flash('flash.bannerStyle', 'danger');
    +
    +                return;
    +            }
    +        }
    +
    +        Session::flash('errors', (new ViewErrorBag())->put(
    +            'default',
    +            new MessageBag(['socialstream' => $error])
    +        ));
    +    }
    +
     }
    
  • src/SocialstreamServiceProvider.php+1 0 modified
    @@ -141,6 +141,7 @@ private function configureRoutes(): void
                 'domain' => config('socialstream.domain'),
                 'prefix' => config('socialstream.prefix', config('socialstream.path')),
             ], function () {
    +            $this->loadRoutesFrom(path: __DIR__.'/../routes/web.php');
                 $this->loadRoutesFrom(path: __DIR__.'/../routes/'.config('jetstream.stack', 'livewire').'.php');
             });
         }
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

4

News mentions

0

No linked articles in our index yet.