VYPR
Medium severity4.9GHSA Advisory· Published May 8, 2026· Updated May 12, 2026

CVE-2026-41887

CVE-2026-41887

Description

Flarum is open-source forum software. Prior to versions 1.8.16 and 2.0.0-rc.1, Flarum's patch for CVE-2023-27577 restricted the @import and data-uri() LESS features in the custom_less setting, but the same restriction was never applied to other settings registered as LESS config variables (for example theme_primary_color and theme_secondary_color, as well as any key registered via Extend\Settings::registerLessConfigVar()). Those values are interpolated verbatim into the LESS source at compile time, allowing an authenticated administrator to craft a theme-color value that injects an arbitrary @import directive into the compiled forum.css. Because the underlying LESS parser honours @import (inline) '<path>', an attacker can read arbitrary files reachable by the PHP process (local file inclusion) or trigger outbound HTTP(S) requests (server-side request forgery). This issue has been patched in versions 1.8.16 and 2.0.0-rc.1.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
flarum/corePackagist
< 1.8.161.8.16
flarum/corePackagist
>= 2.0.0-beta.1, < 2.0.0-rc.12.0.0-rc.1

Affected products

1

Patches

1
2d90a1f19f0e

Merge commit from fork

https://github.com/flarum/frameworkIanMApr 18, 2026via ghsa
2 files changed · +72 6
  • framework/core/src/Forum/ValidateCustomLess.php+19 6 modified
    @@ -43,13 +43,26 @@ public function whenSettingsSaving(Saving $event): void
                 return;
             }
     
    -        // Restrict what features can be used in custom LESS
    -        if (isset($event->settings['custom_less']) && preg_match('/@import|data-uri\s*\(/i', $event->settings['custom_less'])) {
    -            $translator = $this->container->make(TranslatorInterface::class);
    +        // Restrict what features can be used in custom LESS. This applies to
    +        // the `custom_less` setting as well as any setting registered as a
    +        // LESS config variable (e.g. `theme_primary_color`), since those
    +        // values are interpolated directly into the LESS source.
    +        $lessFeatureKeys = array_merge(
    +            isset($event->settings['custom_less']) ? ['custom_less'] : [],
    +            array_intersect(
    +                array_keys($event->settings),
    +                array_column($this->customLessSettings, 'key')
    +            )
    +        );
    +
    +        foreach ($lessFeatureKeys as $key) {
    +            if (is_string($event->settings[$key]) && preg_match('/@import|data-uri\s*\(/i', $event->settings[$key])) {
    +                $translator = $this->container->make(TranslatorInterface::class);
     
    -            throw new ValidationException([
    -                'custom_less' => $translator->trans('core.admin.appearance.custom_styles_cannot_use_less_features')
    -            ]);
    +                throw new ValidationException([
    +                    $key => $translator->trans('core.admin.appearance.custom_styles_cannot_use_less_features')
    +                ]);
    +            }
             }
     
             // We haven't saved the settings yet, but we want to trial a full
    
  • framework/core/tests/integration/api/settings/SetTest.php+53 0 modified
    @@ -78,4 +78,57 @@ public function max_setting_length_validated()
     
             $this->assertEquals(422, $response->getStatusCode());
         }
    +
    +    #[Test]
    +    public function theme_primary_color_rejects_less_import()
    +    {
    +        $response = $this->send(
    +            $this->request('POST', '/api/settings', [
    +                'authenticatedAs' => 1,
    +                'json' => [
    +                    'theme_primary_color' => "#4D698E;@import (inline) '/etc/passwd';",
    +                ],
    +            ])
    +        );
    +
    +        $this->assertEquals(422, $response->getStatusCode());
    +        $this->assertNotEquals(
    +            "#4D698E;@import (inline) '/etc/passwd';",
    +            $this->app->getContainer()->make('flarum.settings')->get('theme_primary_color')
    +        );
    +    }
    +
    +    #[Test]
    +    public function theme_secondary_color_rejects_less_import()
    +    {
    +        $response = $this->send(
    +            $this->request('POST', '/api/settings', [
    +                'authenticatedAs' => 1,
    +                'json' => [
    +                    'theme_secondary_color' => "#4D698E;@import (inline) '/etc/passwd';",
    +                ],
    +            ])
    +        );
    +
    +        $this->assertEquals(422, $response->getStatusCode());
    +        $this->assertNotEquals(
    +            "#4D698E;@import (inline) '/etc/passwd';",
    +            $this->app->getContainer()->make('flarum.settings')->get('theme_secondary_color')
    +        );
    +    }
    +
    +    #[Test]
    +    public function theme_primary_color_rejects_data_uri()
    +    {
    +        $response = $this->send(
    +            $this->request('POST', '/api/settings', [
    +                'authenticatedAs' => 1,
    +                'json' => [
    +                    'theme_primary_color' => "#4D698E;background:data-uri('/etc/passwd');",
    +                ],
    +            ])
    +        );
    +
    +        $this->assertEquals(422, $response->getStatusCode());
    +    }
     }
    

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

8

News mentions

18