Jun 9, 2026·5 min read·24 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 missing authorization vulnerability (CWE-862) exists in Open WebUI from version 0.8.12 before 0.10.0. This flaw allows authenticated non-administrative users to access restricted underlying backend models via specific task endpoints, bypassing configured model permissions.
An authorization bypass and cross-session cache leakage vulnerability exists in the model-listing backend of Open WebUI. The flaw stems from a configuration error in the @cached decorator of the aiocache library, which maps all unique user session queries to a single static cache key.
A Broken Object Level Authorization (BOLA) / Insecure Direct Object Reference (IDOR) vulnerability in Open WebUI prior to v0.10.0 allows authenticated users to access and disclose private message contents, thread context, and channel metadata from other restricted private or Direct Message (DM) channels without proper authorization.
Open WebUI versions starting from 0.7.0 up to, but excluding, 0.10.0 are vulnerable to a sensitive data exposure flaw in the channels API. The GET /api/v1/channels/{id}/members endpoint exposes full user database representations, including private API keys and webhook configurations. This allows authenticated users to extract private credentials of other members within the same channel.
CVE-2026-59219 identifies a session-revocation bypass vulnerability in Open WebUI versions 0.9.0 through 0.9.99. While standard HTTP REST endpoints enforce stateful JWT revocation using a Redis-backed blacklist, WebSocket and Socket.IO endpoints bypassed these checks. Consequently, a token revoked via sign-out or OIDC logout remains valid for establishing real-time communication channels and accessing server terminal proxies.
CVE-2026-59864 is a critical path traversal vulnerability in Microsoft Kiota occurring when custom OpenAPI extensions specify a nested static template file. Lack of input sanitization allows malicious inputs to write directory traversal sequences directly into plugin manifests, causing out-of-package local file disclosure in downstream environments like Microsoft 365 Copilot.