Home / Symfony / Symfony UX 3.2.0 and 2.36.1 released

Symfony UX 3.2.0 and 2.36.1 released

Symfony UX 3.2.0 and 2.36.1 are now available. Both releases fix two security
issues, one in UX Icons and one in UX Toolkit, so every application using these
packages should upgrade as soon as possible. On top of the security fixes,
version 3.2.0 ships several new features for TwigComponent, Toolkit and Native.

Security

Two vulnerabilities were fixed in both maintained branches (2.36.1 and 3.2.0).

UX Icons rendered SVG content without sanitization, both for local icon files
and for the on-demand Iconify responses (enabled by default). Because the
ux_icon() Twig function outputs its SVG as safe HTML, a malicious icon set
or a compromised Iconify endpoint could inject scripts and event handlers,
leading to cross-site scripting. The renderer now sanitizes every icon, from
any source, before it reaches the page (CVE-2026-55877).

UX Toolkit installed recipe files from a kit by copying the paths listed in its
copy-files map, guarded only by a relative-path check. A crafted kit could
use .. segments to escape the target directory and read or overwrite
arbitrary files, up to code execution on a developer machine or CI runner. The
installer now rejects any path that escapes the recipe directory
(CVE-2026-55878).

Both issues were reported by Pascal Cescon and fixed by Hugo Alliaume.

Standalone components with any PSR-11 container


Guillaume Sainthillier
Contributed by
Guillaume Sainthillier
in
#3602

TwigComponent’s runtime no longer requires symfony/dependency-injection.
ComponentFactory and ComponentRuntime only ever call get() and
has() on their service locator, both defined by the PSR-11
PsrContainerContainerInterface, so they now typehint that interface
instead of Symfony’s concrete ServiceLocator.

This decouples the runtime from the DI component, so you can use TwigComponent
standalone, with only Twig and any PSR-11 container:

use PsrContainerContainerInterface;
use SymfonyUXTwigComponentComponentFactory;

// wire the runtime with any PsrContainerContainerInterface
$factory = new ComponentFactory(
    $templateFinder,
    $container,
    $propertyAccessor,
    $eventDispatcher,
    $config,
    $classMap,
    $twig,
);

Inside a full Symfony application, nothing changes: ServiceLocator still
implements the interface and the bundle keeps wiring it for you.

A richer ComponentRendererInterface


Mathias H.
Contributed by
Mathias H.
in
#3600

ComponentRendererInterface only declared createAndRender(), even though
ComponentRuntime also relied on preCreateForRender(),
startEmbeddedComponentRender() and finishEmbeddedComponentRender() from
the concrete, final renderer. Intercepting the render pipeline therefore
meant forking the runtime or reaching into private state through reflection.

These three methods are now part of the interface, and ComponentRuntime
depends on the interface instead of the concrete class. You can decorate or
replace the renderer with a clean, upgrade-safe contract:

use SymfonyUXTwigComponentComponentRendererInterface;

final class ComponentPreloader implements ComponentRendererInterface
{
    public function __construct(
        private ComponentRendererInterface $inner,
    ) {
    }

    // preCreateForRender(), startEmbeddedComponentRender() and
    // finishEmbeddedComponentRender() are now part of the contract
}

Kit-global dependencies in UX Toolkit


Hugo Alliaume
Contributed by
Hugo Alliaume
in
#3671

A Toolkit kit can install some libraries once for the whole kit (for example
Flowbite), but the dependency checker only knew about per-recipe dependencies,
so it flagged those kit-global imports as undeclared on every recipe.

A kit manifest can now declare its own dependencies, shared across all of
its recipes:

{
    "name": "Flowbite v4",
    "dependencies": {
        "npm": ["flowbite"],
        "importmap": ["flowbite"]
    }
}

npm and importmap packages declared at the kit level are now treated as
available for every recipe in the kit.

A linter for Toolkit kits


Hugo Alliaume
Contributed by
Hugo Alliaume
in
#3655

Maintaining a kit means keeping recipes, templates, assets and dependencies in
sync, and it is easy to ship a broken copy-files entry or a Stimulus controller
without its JavaScript file. A new linter catches these regressions before they
reach users:

$ ./vendor/bin/ux-toolkit-kit-lint path/to/your-kit

It runs structural checks (missing recipe manifests, broken copy-files entries,
unknown recipe references) and coherence checks (Stimulus controllers used in
Twig without a matching JavaScript file, undeclared JavaScript imports). The
tool is meant for kit maintainers, so it is exposed as a standalone binary with
no DI wiring, ready to run locally or from CI.

Renamed UX Native build command


Hugo Alliaume
Contributed by
Hugo Alliaume
in
#3611

The UX Native command that produces the JSON configuration for the iOS and
Android Hotwire Native shells was renamed to follow the ux:<...> convention
and to drop the debug-flavored dump verb:

# before
$ php bin/console ux-native:dump

# after
$ php bin/console ux:native:build-configs

UX Native is still experimental, so this rename ships without a backward
compatibility alias; update your scripts and CI accordingly.

Full Changelog

  • CVE-2026-55877 [Icons] Sanitize Iconify SVG output and unify icon creation (@Kocal)
  • CVE-2026-55878 [Toolkit] Harden recipe installer against path traversal (@Kocal)
  • #3682 [Toolkit][Shadcn] Fix position and phantom text-node in tooltip recipe (@Kocal)
  • #3602 [TwigComponent] Allow standalone usage with any PSR-11 container (@guillaume-sainthillier)
  • #3673 [Encore] Pin vue to <3.5.36 to workaround broken upstream publish (@Kocal)
  • #3672 [Toolkit][Flowbite4] Fix linting issues (@Kocal)
  • #3671 [Toolkit] Allow declaring kit-global dependencies in kit manifest (@Kocal)
  • #3659 [Toolkit] Consider recipe deps in StimulusControllerChecker (@Kocal)
  • #3655 [Toolkit] Add lint kit command and CI lint workflow (@Kocal)
  • #3652 [Toolkit][Shadcn] Fix manifest dependencies (@seb-jean)
  • #3600 [TwigComponent] Expose pre/embedded render methods on ComponentRendererInterface (@treztreiz)
  • #3614 [Turbo] Conflict with Mercure >=0.7.0 <0.7.2 (@Kocal)
  • #3611 [Native] Rename ux-native:dump command to ux:native:build-configs (@Kocal)

Sponsor the Symfony project.
Tagged:

Leave a Reply

Your email address will not be published. Required fields are marked *