VYPR
Moderate severityNVD Advisory· Published Aug 21, 2023· Updated Oct 3, 2024

Cross-Site Request Forgery (CSRF) in wallabag/wallabag

CVE-2023-4454

Description

Cross-Site Request Forgery (CSRF) in GitHub repository wallabag/wallabag prior to 2.6.3.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
wallabag/wallabagPackagist
>= 2.0.0-alpha.1, < 2.6.32.6.3

Affected products

1

Patches

1
78b0b55c4051

Merge pull request from GHSA-p8gp-899c-jvq9

https://github.com/wallabag/wallabagNicolas LœuilletAug 21, 2023via ghsa
3 files changed · +44 19
  • src/Wallabag/CoreBundle/Controller/ConfigController.php+6 2 modified
    @@ -523,12 +523,16 @@ public function editIgnoreOriginRuleAction(IgnoreOriginUserRule $rule)
         /**
          * Remove all annotations OR tags OR entries for the current user.
          *
    -     * @Route("/reset/{type}", requirements={"id" = "annotations|tags|entries"}, name="config_reset")
    +     * @Route("/reset/{type}", requirements={"id" = "annotations|tags|entries"}, name="config_reset", methods={"POST"})
          *
          * @return RedirectResponse
          */
    -    public function resetAction(string $type, AnnotationRepository $annotationRepository, EntryRepository $entryRepository)
    +    public function resetAction(Request $request, string $type, AnnotationRepository $annotationRepository, EntryRepository $entryRepository)
         {
    +        if (!$this->isCsrfTokenValid('reset-area', $request->request->get('token'))) {
    +            throw $this->createAccessDeniedException('Bad CSRF token.');
    +        }
    +
             switch ($type) {
                 case 'annotations':
                     $annotationRepository->removeAllByUserId($this->getUser()->getId());
    
  • src/Wallabag/CoreBundle/Resources/views/Config/index.html.twig+28 12 modified
    @@ -552,18 +552,34 @@
                             <div class="row">
                                 <h5>{{ 'config.reset.title'|trans }}</h5>
                                 <p>{{ 'config.reset.description'|trans }}</p>
    -                            <a href="{{ path('config_reset', {type: 'annotations'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red">
    -                                {{ 'config.reset.annotations'|trans }}
    -                            </a>
    -                            <a href="{{ path('config_reset', {type: 'tags'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red">
    -                                {{ 'config.reset.tags'|trans }}
    -                            </a>
    -                            <a href="{{ path('config_reset', {type: 'archived'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red">
    -                                {{ 'config.reset.archived'|trans }}
    -                            </a>
    -                            <a href="{{ path('config_reset', {type: 'entries'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red">
    -                                {{ 'config.reset.entries'|trans }}
    -                            </a>
    +                            <p>
    +                                <form action="{{ path('config_reset', { type: 'annotations' }) }}" method="post" onsubmit="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" name="reset-annotations">
    +                                    <input type="hidden" name="token" value="{{ csrf_token('reset-area') }}" />
    +
    +                                    <button class="waves-effect waves-light btn red" type="submit">{{ 'config.reset.annotations'|trans }}</button>
    +                                </form>
    +                            </p>
    +                            <p>
    +                                <form action="{{ path('config_reset', { type: 'tags' }) }}" method="post" onsubmit="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" name="reset-tags">
    +                                    <input type="hidden" name="token" value="{{ csrf_token('reset-area') }}" />
    +
    +                                    <button class="waves-effect waves-light btn red" type="submit">{{ 'config.reset.tags'|trans }}</button>
    +                                </form>
    +                            </p>
    +                            <p>
    +                                <form action="{{ path('config_reset', { type: 'archived' }) }}" method="post" onsubmit="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" name="reset-archived">
    +                                    <input type="hidden" name="token" value="{{ csrf_token('reset-area') }}" />
    +
    +                                    <button class="waves-effect waves-light btn red" type="submit">{{ 'config.reset.archived'|trans }}</button>
    +                                </form>
    +                            </p>
    +                            <p>
    +                                <form action="{{ path('config_reset', { type: 'entries' }) }}" method="post" onsubmit="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" name="reset-entries">
    +                                    <input type="hidden" name="token" value="{{ csrf_token('reset-area') }}" />
    +
    +                                    <button class="waves-effect waves-light btn red" type="submit">{{ 'config.reset.entries'|trans }}</button>
    +                                </form>
    +                            </p>
                             </div>
     
                             {% if enabled_users > 1 %}
    
  • tests/Wallabag/CoreBundle/Controller/ConfigControllerTest.php+10 5 modified
    @@ -929,7 +929,8 @@ public function testReset()
     
             $this->assertSame(200, $client->getResponse()->getStatusCode());
     
    -        $crawler = $client->click($crawler->selectLink('config.reset.annotations')->link());
    +        $form = $crawler->filter('form[name=reset-annotations]')->form();
    +        $client->submit($form);
     
             $this->assertSame(302, $client->getResponse()->getStatusCode());
             $this->assertStringContainsString('flashes.config.notice.annotations_reset', $client->getContainer()->get(SessionInterface::class)->getFlashBag()->get('notice')[0]);
    @@ -945,7 +946,8 @@ public function testReset()
     
             $this->assertSame(200, $client->getResponse()->getStatusCode());
     
    -        $crawler = $client->click($crawler->selectLink('config.reset.tags')->link());
    +        $form = $crawler->filter('form[name=reset-tags]')->form();
    +        $client->submit($form);
     
             $this->assertSame(302, $client->getResponse()->getStatusCode());
             $this->assertStringContainsString('flashes.config.notice.tags_reset', $client->getContainer()->get(SessionInterface::class)->getFlashBag()->get('notice')[0]);
    @@ -961,7 +963,8 @@ public function testReset()
     
             $this->assertSame(200, $client->getResponse()->getStatusCode());
     
    -        $crawler = $client->click($crawler->selectLink('config.reset.entries')->link());
    +        $form = $crawler->filter('form[name=reset-entries]')->form();
    +        $client->submit($form);
     
             $this->assertSame(302, $client->getResponse()->getStatusCode());
             $this->assertStringContainsString('flashes.config.notice.entries_reset', $client->getContainer()->get(SessionInterface::class)->getFlashBag()->get('notice')[0]);
    @@ -1027,7 +1030,8 @@ public function testResetArchivedEntries()
     
             $this->assertSame(200, $client->getResponse()->getStatusCode());
     
    -        $crawler = $client->click($crawler->selectLink('config.reset.archived')->link());
    +        $form = $crawler->filter('form[name=reset-archived]')->form();
    +        $client->submit($form);
     
             $this->assertSame(302, $client->getResponse()->getStatusCode());
             $this->assertStringContainsString('flashes.config.notice.archived_reset', $client->getContainer()->get(SessionInterface::class)->getFlashBag()->get('notice')[0]);
    @@ -1086,7 +1090,8 @@ public function testResetEntriesCascade()
     
             $this->assertSame(200, $client->getResponse()->getStatusCode());
     
    -        $crawler = $client->click($crawler->selectLink('config.reset.entries')->link());
    +        $form = $crawler->filter('form[name=reset-entries]')->form();
    +        $client->submit($form);
     
             $this->assertSame(302, $client->getResponse()->getStatusCode());
             $this->assertStringContainsString('flashes.config.notice.entries_reset', $client->getContainer()->get(SessionInterface::class)->getFlashBag()->get('notice')[0]);
    

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.