The admin is a privileged surface. This engine ships the request-forgery, framing, and destructive-action controls itself; a few things are left for the host to opt into.
- CSRF.
protect_from_forgery(with: :exception)is hardcoded. A non-GET request without a valid token is rejected (ActionController::InvalidAuthenticityToken→ HTTP 422). There is no host-configurable forgery option to weaken it. - Clickjacking. Every admin response carries
X-Frame-Options: SAMEORIGIN. - Export. The CSV/JSON/XML data stream requires a non-GET, CSRF-protected request;
GETonly renders the export form, so the table can't be exfiltrated via a crafted link. - Destructive actions.
deleteandbulk_deleterender a confirmation page and additionally carrydata-turbo-confirmon the destructive submit (Turbo's confirmation, not@rails/ujs). - Mass assignment. Submitted attributes are sliced to the model config's
visible_fieldsbeforepermit!, at the top level and at every nested depth, regardless of the submitted nested-attributes cardinality (hash or array).
The engine enforces no CSP by default. When you opt in, it applies the policy per-request to
admin responses only (never to the host app) and threads a per-request nonce onto every inline tag
it emits (the importmap JSON, the import entry point, the index column-width <style>), so a
:self + nonce policy does not block the admin's own pinned modules.
# config/initializers/rails_admin_next.rb
RailsAdminNext.config do |config|
config.content_security_policy do |policy|
policy.default_src :self
policy.script_src :self
policy.style_src :self, :unsafe_inline # see note below
policy.img_src :self, :data
policy.font_src :self
policy.connect_src :self
end
endTune it without breaking pages first by reporting only:
RailsAdminNext.config do |config|
config.content_security_policy(report_only: true) do |policy|
policy.default_src :self
end
endNote on
style-src. The admin still renders five inlinestyle="…"attributes, which a CSP nonce cannot cover (nonces apply to<script>/<style>elements, not style attributes), so astyle-srcdirective needs:unsafe_inlinefor now. The engine's own<style>element (the index column-width block) is nonced. The remaining attributes:
- the
#loadingbadge's positioning in the layout, and the delete-notice<li>spacing — static values, removable by moving them into the stylesheet;- the file-upload delete toggle's initial
display:none— conditional initial state, removable by switching to thehiddenattribute;- the dashboard's
.progressmargin (static) and each progress bar'swidth: N%(a per-row dynamic value — the one that genuinely resists removal; it would need the nonced-<style>route or a native<progress>element).Once those five are reauthored,
:unsafe_inlinecan be dropped.