Back to Course

Spot the Tax · Card 5 of 20

Authorization belongs in the query, not after

Why Invoice.find(params[:id]) is a security hole, even with authenticate_user!.

The code

What will this cost you in six months?

class InvoicesController < ApplicationController
  before_action :authenticate_user!

  def show
    @invoice = Invoice.find(params[:id])
  end
end

The problem

Any logged-in user can view any invoice in the system just by changing the ID in the URL. The before_action :authenticate_user! ran successfully, but all that did was confirm that the request came from someone who is logged in. It never checked whether this particular user is allowed to see this particular invoice. So the request goes through, the wrong invoice gets rendered, and you have an information leak that's effectively impossible to detect from your logs.

Take a moment. Before revealing, think about how you'd actually close this hole. What's the shape of the safer code, and what would make the unsafe version impossible to write by accident?