Jun 9, 2026·5 min read·60 visits
Improper sanitization of component attributes in the phoenix_storybook playground allows remote attackers to inject arbitrary Elixir expressions into HEEx templates, resulting in unauthenticated remote code execution.
An unauthenticated remote code execution (RCE) vulnerability exists in phoenix_storybook versions 0.5.0 through 1.0.x due to improper input sanitization during HEEx template generation. By sending crafted WebSocket messages, an attacker can escape HTML attribute boundaries and execute arbitrary Elixir code.
The phoenix_storybook package is an Elixir library designed to showcase and test Phoenix components in an interactive environment. It features a "Playground" that enables users to modify component attributes dynamically and preview the rendered output in real time. The interactive playground operates over a persistent WebSocket connection utilizing Phoenix LiveView to exchange state changes.\n\nThis architecture exposes an attack surface through WebSocket events handled by the playground preview live view. Specifically, the component attributes supplied by the user are processed and compiled dynamically on the server to render the preview. Because the backend does not validate or escape these inputs prior to template rendering, the system is vulnerable to template injection.\n\nThis vulnerability, tracked as CVE-2026-8467, is classified under CWE-94 (Improper Control of Generation of Code). The impact of this vulnerability is critical, as it allows unauthenticated, remote actors to execute arbitrary Elixir expressions and shell commands within the context of the hosting server process.
The root cause of CVE-2026-8467 lies in the unsafe construction of Elixir HTML (HEEx) templates using unsanitized string values. When a user modifies an attribute in the playground UI, the changes are transmitted via a WebSocket event named "psb-assign" to the backend event handler 'Elixir.PhoenixStorybook.Story.PlaygroundPreviewLive':handle_event/3.\n\nThe event handler delegates the parameter storage to 'Elixir.PhoenixStorybook.Helpers.ExtraAssignsHelpers':handle_set_variation_assign/3. This helper stores the user-controlled binary values verbatim in the LiveView socket's assigns map, without performing any validation or sanitization against the input data.\n\nDuring the rendering phase, 'Elixir.PhoenixStorybook.Rendering.ComponentRenderer':attributes_markup/1 attempts to format these assigns into a string representation of HTML attributes. The function interpolates binary values directly inside double quotes using standard Elixir string interpolation (~s|#{name}="#{val}"|). This lack of escaping allows an attacker to break out of the string literal by supplying double quotes and curly braces containing arbitrary Elixir code, which is subsequently parsed and executed.\n\nmermaid\ngraph LR\n A["User Input via WebSocket"] --> B["PlaygroundPreviewLive:handle_event/3"]\n B --> C["ExtraAssignsHelpers:handle_set_variation_assign/3"]\n C --> D["ComponentRenderer:attributes_markup/1"]\n D --> E["EEx.compile_string/2"]\n E --> F["Code.eval_quoted_with_env/3"]\n F --> G["Unsanitized Code Execution"]\n
To understand the vulnerability, it is necessary to examine the vulnerable code path in 'Elixir.PhoenixStorybook.Rendering.ComponentRenderer' where attributes are parsed and formatted into the HEEx markup string.\n\nelixir\n# Vulnerable implementation of attributes_markup/1\ndefp attributes_markup(attributes) do\n Enum.map_join(attributes, " ", fn\n {name, {:eval, val}} ->\n ~s|#{name}={#{val}}|\n\n {name, val} when is_binary(val) ->\n # VULNERABLE: Direct string interpolation allows quotes and curly-brace escaping\n ~s|#{name}=\"#{val}\"|\n\n {name, val} ->\n ~s|#{name}={#{inspect(val, structs: false, limit: :infinity, printable_limit: :infinity)}}|\n end)\nend\n\n\nWhen val contains a payload such as safe\" injected={System.cmd(\"whoami\", [])} bar=\", the returned string evaluates to name="safe" injected={System.cmd("whoami", [])} bar="". This effectively introduces a new attribute injected containing an executable expression.\n\nelixir\n# Unsafe template compilation and evaluation pipeline\ndefp render_component_heex(fun_or_mod, heex, opts) do\n # The compiled string contains the injected AST node\n quoted_code = EEx.compile_string(heex, engine: TagEngine)\n\n # Evaluation occurs in the current environment with full permissions\n {evaluated, _, _} = Code.eval_quoted_with_env(quoted_code, [assigns: %{}], env)\n evaluated\nend\n\n\nThe compiled HEEx template is evaluated using Code.eval_quoted_with_env/3. Because the dynamic execution environment contains the full Elixir Kernel imports and runs without sandboxing, the injected expression is evaluated with the privileges of the running application.
An attack targeting CVE-2026-8467 relies on establishing an active Phoenix LiveView channel to the Storybook playground endpoint. This endpoint is typically exposed at paths such as /storybook or /admin/storybook in development and testing configurations.\n\nOnce the connection is established, the attacker sends a WebSocket frame mimicking the client-side Hook trigger for the "psb-assign" event. The payload overrides a vulnerable component attribute (such as label) with a payload designed to escape the string boundary and run arbitrary code.\n\njson\n[\n \"4\",\n \"5\",\n \"lv:phx-F7v8u9gAAAAB\",\n \"event\",\n {\n \"type\": \"click\",\n \"event\": \"psb-assign\",\n \"value\": {\n \"variation_id\": \"hello\",\n \"label\": \"safe\\\" injected={System.cmd(\\\"touch\\\", [\\\"/tmp/rce_exploit\\\"])} bar=\\\"\"\n }\n }\n]\n\n\nUpon receiving this frame, the server processes the parameters, structures the new HTML template, compiles it via EEx.compile_string/2, and evaluates the code. The system execution occurs synchronously, and the operating system command is executed on the host, as demonstrated by the creation of the /tmp/rce_exploit marker file.
The security impact of CVE-2026-8467 is critical. A successful exploit grants unauthenticated remote code execution (RCE) on the underlying host operating system. The executing code inherits all environment variables, file system permissions, and network access rights granted to the beam/OTP process running the Elixir application.\n\nBecause the code is evaluated with the privileges of the running application, the attacker can read sensitive configuration secrets, leak database credentials, access internal databases, and pivot to adjacent resources within the target environment. If the Elixir application runs as root or with high-privilege service accounts, the entire container or server hosting the application can be fully compromised.\n\nAccording to CVSS v4.0 metrics, this vulnerability receives a base score of 9.5 (Critical). The vector CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H emphasizes that no local user privileges or interactions are required to exploit the flaw, making it highly exploitable once the Storybook endpoint is accessible.
The primary remediation for CVE-2026-8467 is upgrading phoenix_storybook to version 1.1.0 or higher. This version fundamentally changes how parameters are passed to the renderer, replacing vulnerable string template concatenation with secure map attribute-splatting ({Map.fetch!(@psb_variation_attrs, index)}) and enforcing strict attribute name verification using regular expressions.\n\nIf immediate upgrading is not feasible, organizations should implement the following temporary mitigations:\n\n* Restrict Endpoint Access: Ensure that the Storybook routing is entirely disabled in production environments by wrapping the routes in a Mix.env() == :dev conditional block.\n* IP Whitelisting: Restrict network access to the /storybook endpoint via reverse proxy or Web Application Firewall (WAF) rule sets.\n* Enforce Authentication: Protect the Storybook paths with authentication plugs to block unauthenticated WebSocket handshakes.\n\nelixir\n# Example of disabling routes in non-development environments\nif Mix.env() == :dev do\n scope \"/\" do\n pipe_through [:browser]\n live_storybook \"/storybook\", otp_app: :my_app\n end\nend\n
CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H| Product | Affected Versions | Fixed Version |
|---|---|---|
phoenix_storybook phenixdigital | >= 0.5.0, < 1.1.0 | 1.1.0 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-94 |
| Attack Vector | Network (AV:N) |
| CVSS Score | 9.5 (Critical) |
| Exploit Status | Proof-of-Concept Available |
| KEV Status | Not Listed |
| Impact | Unauthenticated Remote Code Execution |
Improper Control of Generation of Code ('Code Injection')
A remote code execution vulnerability exists in Microsoft .NET due to untrusted data deserialization within the PresentationCore component. The flaw stems from implicit auto-conversion flags during clipboard data retrieval operations.
An out-of-bounds write vulnerability in Microsoft .NET Framework, .NET runtime, and Visual Studio allows unauthenticated remote attackers to execute arbitrary code via crafted pixel-shader bytecode or auto-converted clipboard payloads.
ASP.NET Core contains a thread deadlock vulnerability (CWE-833) that allows an unauthenticated remote attacker to cause a denial of service over the network by exhausting server thread pool resources.
CVE-2026-70035 is a high-severity Remote Code Execution (RCE) vulnerability in Microsoft .NET Framework, .NET runtime, and Visual Studio caused by improper handling during the deserialization of untrusted data (CWE-502). An unauthenticated attacker can execute arbitrary code within the context of the affected process by delivering a crafted serialized payload.
An elevation of privilege vulnerability exists in ASP.NET Core and Microsoft Visual Studio due to improper synchronization during concurrent thread execution. Authenticated remote attackers with low privileges can exploit a timing window to manipulate shared resources and assume higher-level execution contexts.
A path traversal vulnerability (CWE-22) in Contao CMS allows unauthenticated remote attackers to bypass directory boundary restrictions in ImagesController and access files within the project directory.