HIGH clickjackinghanamiruby

Clickjacking in Hanami (Ruby)

Clickjacking in Hanami with Ruby — how this specific combination creates or exposes the vulnerability

Clickjacking is a client-side injection flaw that manipulates a user into interacting with a hidden interface element inside an iframe. In Hanami, a Ruby web framework, this typically arises when views do not enforce a same-origin policy via X-Frame-Options or Content-Security-Policy (CSP) frame-ancestors, and the application exposes sensitive actions (such as account updates or token-bearing POSTs) without additional anti-CSRF considerations. Ruby’s default templating (e.g., Tilt/ERB) does not automatically add frame-busting headers, so the responsibility falls on the developer to set them explicitly.

When a Hanami app renders pages that include forms or links intended for direct interaction, and those pages are served without restrictive framing headers, an attacker can embed the target URL inside an invisible iframe on a malicious site. Because Hanami routes are mapped to Ruby classes with conventional action methods (e.g., Posts::Create), the request lifecycle processes the forged request as a legitimate user action if the session cookie is present and no same-site or anti-CSRF protections are enforced. This combination—Ruby-based server-side rendering in Hanami plus missing CSP frame-ancestors or X-Frame-Options—creates a surface where clickjacking can succeed.

Consider an example where a Hanami Ruby view renders a form to change the user’s email without enforcing strict CSP. An attacker crafts a page with an invisible iframe pointing to /account/update-email and overlays transparent UI elements to trick the user into clicking the visible button, which actually submits the hidden form. Because Hanami can rely on cookie-based sessions, the forged request executes in the victim’s authenticated context if the browser sends the session cookie. The Ruby backend processes the request as valid, demonstrating how the framework’s typical patterns can inadvertently enable clickjacking when headers are omitted.

OpenAPI/Swagger analysis (supported in multiple versions with full $ref resolution) can highlight endpoints that lack security headers in runtime tests, but note that middleBrick detects missing framing protections as part of its 12 checks, specifically under Data Exposure and related to improper CSP configuration. This is important because scanning your Hanami endpoints with a tool that performs black-box testing can surface these missing headers before an attacker exploits them.

Ruby-Specific Remediation in Hanami — concrete code fixes

Remediation focuses on setting HTTP response headers and ensuring that forms are protected by anti-CSRF tokens. In Hanami, you can configure default headers in the application or per action, and you should include frame-busting and CSP headers that restrict frame-ancestors. Below are concrete Ruby code examples for Hanami applications.

Setting default headers in Hanami

Use a Rack middleware or Hanami’s built-in configuration to inject security headers for all responses. Here is a Ruby initializer that adds X-Frame-Options and a strict CSP with frame-ancestors 'self':

# config/initializers/security_headers.rb
module SecurityHeaders
  class Middleware
    def initialize(app)
      @app = app
    end

    def call(env)
      status, headers, body = @app.call(env)
      headers['X-Frame-Options'] = 'DENY'
      headers['Content-Security-Policy'] = "default-src 'self'; frame-ancestors 'self';"
      [status, headers, body]
    end
  end
end

require 'hanami/configuration'
Hanami.configure do |config|
  config.middleware.use SecurityHeaders::Middleware
end

This Ruby snippet wraps the Hanami app with a custom middleware that sets headers on every response, ensuring that browsers will not render the page in an iframe unless it originates from the same origin.

Per-action header control in Hanami actions

If you need tighter control, you can set headers directly in a specific Ruby action. The following Hanami action demonstrates how to add headers to a response for a sensitive operation, such as updating account details:

# apps/web/controllers/account/update.rb
module Web::Controllers::Account
  class Update
    include Web::Action

    def call(params)
      # business logic for updating account
      headers['X-Frame-Options'] = 'DENY'
      headers['Content-Security-Policy'] = "default-src 'self'; frame-ancestors 'self';"
      # redirect or render as appropriate
    end
  end
end

Additionally, ensure your forms include anti-CSRF tokens. Hanami provides built-in helpers when using its view components; for example, include the authenticity token in forms:

<%= form_for @account, action: Routes.account_update_path do |f| %>
  <%= f.hidden_field :_csrf_token, value: current_session.csrf_token %>
  <%= f.input :email %>
  <%= f.submit 'Update' %>
<%= end %>

By combining Ruby middleware for headers with per-action customization and proper CSRF token usage, you mitigate clickjacking risks specific to Hanami applications. For ongoing monitoring, consider integrating middleBrick’s scans (via the CLI: middlebrick scan <url>, the GitHub Action for CI/CD, or the MCP Server in your IDE) to validate that these headers are present and effective across deployed environments.

Frequently Asked Questions

How does Hanami's default behavior increase clickjacking risk in Ruby applications?
Hanami does not set framing headers by default; without explicit X-Frame-Options or CSP frame-ancestors in Ruby responses, pages can be embedded in iframes, enabling clickjacking.
Can middleBrick detect missing frame-ancestors headers in Hanami apps?
Yes, middleBrick’s Data Exposure and CSP checks identify missing or weak frame-ancestors headers, and you can run scans via the CLI, GitHub Action, or MCP Server.