Skip to content

[mgt] For 4.3.4 - Drop unsafe-eval and unsafe-inline from the management UI Content Security Policy#16916

Merged
michaelklishin merged 9 commits into
mainfrom
rmq-2542
Jul 20, 2026
Merged

[mgt] For 4.3.4 - Drop unsafe-eval and unsafe-inline from the management UI Content Security Policy#16916
michaelklishin merged 9 commits into
mainfrom
rmq-2542

Conversation

@MarcialRosales

@MarcialRosales MarcialRosales commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Motivation

This is a security improvement that removes two CSP directives: unsafe-inline
and unsafe-eval.

Removing unsafe-inline was straightforward: any inline <script> block in
index.html was moved to a dedicated external JavaScript file. Also, we have to remove all the inline event handlers in overview, queues, feature-flags and oauth2.

Removing unsafe-eval required deeper changes. The management UI relies on the
EJS 1.0 template engine, which — at runtime — fetches each .ejs file from the
server via XHR, then compiles it using JavaScript's eval() to produce the
function that renders the HTML. As long as that runtime compilation step
existed, unsafe-eval could not be removed from the CSP.

Proposed Changes

All .ejs templates for a given plugin are compiled to JavaScript at build
time
and bundled into a single <plugin>-ejs.js file (e.g.
management-ejs.js for rabbitmq_management, stream_management-ejs.js for
rabbitmq_stream_management).

The management plugin's own bundle is loaded as a static <script> tag in
index.html because it contains the core templates required before login. All
other plugins register their bundle via the web_ui/0 callback so it is loaded
as an extension after a successful login.

Build-time compilation

The .ejs.js conversion is performed by an Erlang escript
(scripts/precompile_ejs_templates). Using an escript keeps the build
dependency-free for the majority of developers, who only need the Erlang
runtime that is already required to build and run the broker.

For developers who also have Node.js available (typically those working on the
management UI), the Makefile automatically runs a sanity check after
compilation: it compiles the same templates using the original EJS 1.0
JavaScript compiler and verifies that both renderers produce identical output.

Working on templates

After modifying a .ejs file, run the following to regenerate the JavaScript
bundle and reload the management UI in the browser:

gmake compile-ejs-templates
scripts/precompile_ejs_templates priv/www/js/tmpl priv/www/js/management-ejs.js
Running EJS sanity check...
ok: all 62 templates match

The complete developer workflow and the limitations of the sanity check are
documented in deps/rabbitmq_management/mk/rabbitmq-management-plugin.mk.

Creating new UI components or updating existing ones

We cannot use inline event handlers. They will not work based on the default CSP directive. We have to register the events programmatically.

Benefits

  1. Fewer network round-trips. Instead of up to 77 individual XHR requests
    (one per .ejs file, issued lazily as the user navigates), the browser
    downloads at most 6 script files — one per plugin — all via <script> tags
    or the extension mechanism.

  2. Lower bandwidth. The 6 bundles transferred gzip-compressed total 49 KB,
    versus 63 KB for the 77 individually-compressed .ejs files. The saving
    comes from gzip's ability to exploit repetition across a larger input.
    Additionally, ejs-1.0.min.js is no longer loaded at runtime; it has been
    replaced by a small shim (ejs-runtime.js) that provides only the
    EJS.Scanner.to_text helper still referenced by the compiled templates.

  3. Stronger CSP. Eliminating runtime template compilation removes the need
    for both unsafe-eval and unsafe-inline, resulting in a stricter
    Content Security Policy.

  4. Less work at startup. The browser no longer fetches a large number of
    small template files on first use, nor compiles them before rendering.
    Templates are available as plain JavaScript functions from the moment the
    script is parsed.

  5. Earlier error detection. Structural template errors (malformed EJS
    delimiters, JavaScript syntax errors inside code blocks) are caught at build
    time rather than at runtime. Errors that depend on real data or on helper
    functions defined elsewhere in the UI are caught by the Selenium test suite.

Types of Changes

What types of changes does your code introduce to this project?
Put an x in the boxes that apply

  • Bug fix (non-breaking change which fixes issue #NNNN)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause an observable behavior change in existing systems)
  • Documentation improvements (corrections, new content, etc)
  • Cosmetic change (whitespace, formatting, etc)
  • Build system and/or CI

@MarcialRosales MarcialRosales changed the title [mgt] Remove the need of unsafe-eval and unsafe-inline in management ui [mgt] Remove the need of unsafe-eval and unsafe-inline from management ui Jul 10, 2026
@mergify mergify Bot added the make label Jul 10, 2026
@MarcialRosales MarcialRosales self-assigned this Jul 10, 2026
@MarcialRosales MarcialRosales changed the title [mgt] Remove the need of unsafe-eval and unsafe-inline from management ui [mgt] Drop unsafe-eval and unsafe-inline from the management UI Content Security Policy Jul 10, 2026
@MarcialRosales
MarcialRosales marked this pull request as ready for review July 14, 2026 08:39
@mergify

mergify Bot commented Jul 14, 2026

Copy link
Copy Markdown

Tick the box to add this pull request to the merge queue (same as @mergifyio queue).

  • Queue this pull request

michaelklishin added a commit that referenced this pull request Jul 15, 2026
while at it, fix a subtle event propagation
bug that only affects this branch.
michaelklishin added a commit that referenced this pull request Jul 15, 2026

@michaelklishin michaelklishin left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MarcialRosales I have fixed a subtle bug and improved Selenium test coverage for these templates.

Please take a look.

@MarcialRosales

Copy link
Copy Markdown
Contributor Author

@michaelklishin nice changes ! specially the suggested changes to the selenium tests around feature flags.

MarcialRosales pushed a commit that referenced this pull request Jul 16, 2026
while at it, fix a subtle event propagation
bug that only affects this branch.
MarcialRosales pushed a commit that referenced this pull request Jul 16, 2026
@michaelklishin michaelklishin added this to the 4.4.0 milestone Jul 17, 2026
@michaelklishin

Copy link
Copy Markdown
Collaborator

@MarcialRosales I have rebased on top of main. This is ready to go if you are happy with the current state.

Note that we can only backport these changes after 4.3.3 ships, see how the currently open PR are tagged in the title.

@MarcialRosales MarcialRosales changed the title [mgt] Drop unsafe-eval and unsafe-inline from the management UI Content Security Policy [mgt] For 4.3.4 - Drop unsafe-eval and unsafe-inline from the management UI Content Security Policy Jul 17, 2026
@MarcialRosales

Copy link
Copy Markdown
Contributor Author

@michaelklishin i am happy with the current state. I have added to the title "For 4.3.4".

@michaelklishin
michaelklishin merged commit 277836f into main Jul 20, 2026
188 of 189 checks passed
@michaelklishin
michaelklishin deleted the rmq-2542 branch July 20, 2026 16:03
michaelklishin added a commit that referenced this pull request Jul 20, 2026
michaelklishin added a commit that referenced this pull request Jul 20, 2026
[mgt] For 4.3.4 - Drop unsafe-eval and unsafe-inline from the management UI Content Security Policy (backport #16916)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants