Build1 distinct publisher3 min readPublished
A dev.to post walks through a Rails action that authenticates the caller and then loads any invoice by id. The defect is an absence, and the model's own tests confirm it.
The Engineer · Build desk
Compiled by The EngineerSomething wrong?How this is made
Start with the diff, because the diff is the whole problem. The vulnerable lookup is `Invoice.find(params[:id])` and the safe one is `current_user.invoices.find(params[:id])` [2][6]. The two differ by one expression, the receiver of `.find` [1]. There is no dangerous token in the bad version, no injection, no sprawl: the controller is small and readable and the author of the dev.to post says so plainly before pulling it apart [2]. What is wrong is missing, and missing code does not show up in a diff or a grep.
The generation mechanism is pattern completion at two levels that never meet. An authentication guard is a familiar shape. A record lookup by `params[:id]` is a familiar shape. Both are individually plausible, and composing them produces something that reads as secure without the model ever reasoning about the relationship between the authenticated user and the object being loaded [11]. The post's formulation is the useful one for reviewers: the failure is not that security is absent, it is that security exists and is not applied to this resource, which is much harder to catch casually [5]. Logged in as user 42, requesting invoice 124 instead of 123 hands you someone else's record [3]. The standard names are BOLA, or IDOR in the older vocabulary [4].
Then the tests, which is where this stops being a code-quality anecdote. When the same model writes the implementation and the spec, you get a test that signs in, fetches the user's own invoice, asserts 200, and proves almost nothing about authorization [8]. The test that would catch the bug signs in and requests another user's invoice, expecting a not-found or whatever the app's denial behaviour is [9]. Those two tests differ only in which record is requested and which status is expected [2]. So the single artefact separating a safe endpoint from an exposed one is the one the generating model has no reason to produce, and its absence presents as coverage. The post's author declines to treat a green suite as evidence for exactly this reason: a suite can faithfully confirm the same misunderstanding that produced the code [10].
The review question has to change shape to match. "Is there authentication?" is answerable by search and is answered comfortably by the presence of middleware, `current_user`, and role helpers [7]. "Can I trace the current user's permission all the way to the specific object being accessed?" requires walking the path: request, authenticated user, authorization decision, specific resource, data access [7][12]. Where the chain jumps straight from authenticated user to `Model.find(params[:id])`, something has to name what prevents cross-user or cross-tenant access [12]. If nothing does, it is a finding that needs verification rather than a style note [7].
The scoped-lookup fix is worth preferring for a structural reason rather than an aesthetic one. Constraining the query puts the other user's record outside the queryable scope in the first place, so denial is a lookup miss rather than a conditional that a later refactor can quietly drop; in bigger systems that boundary arrives as a policy object, tenant scope, permission service, or domain rule instead [6].
Ranked by verification strength, evidence, and original report placement.
The example Rails action returns head :unauthorized unless current_user, then loads @invoice = Invoice.find(params[:id]) and renders it; the post notes the user must be logged in, there is no obvious injection vulnerability, and the controller is small and readable.
Logged in as user 42 and requesting /invoices/123, the code checks only authentication; if changing 123 to 124 returns somebody else's invoice, authentication has done nothing to protect that data.
The post identifies this as the class of problem commonly described as BOLA (Broken Object Level Authorization) or, in older terminology, IDOR: object-level access control missing even though authentication exists.
The failure is not 'there is no security' but 'security exists, but it is not being applied to this resource', which the post says is much harder to catch casually.
The suggested fix is to constrain data access to the user's permitted scope, e.g. @invoice = current_user.invoices.find(params[:id]), so the resource is outside the queryable scope in the first place rather than failing a later if statement; in a more complex system that boundary may come from a policy object, tenant scope, permission service, or domain rule.
The review question the author uses is 'Can I trace the current user's permission all the way to the specific object being accessed?', and if he can't, he treats it as a security finding that needs verification; he asks 'Is authorization enforced for this exact operation on this exact resource?' rather than 'Is there authentication?', wording that forces review away from the comforting presence of middleware, current_user, role checks and authentication helpers.
Follow any of these and your For You feed starts watching them — no settings page required.
Evidence-backed comparisons of source perspectives and observed adoption signals. Read the methodology
Which Builder, Operator, and Investor concerns the observed source mix emphasized—not a truth score.
Evidence, demonstrated adoption, hype gap, incentives, and confidence are assessed independently, each on its own current evidence. How these are measured.
Self-contained code demonstration, no external corroboration
The technical core is verifiable on its face: the vulnerable and fixed Rails lookups, the id-substitution exploit path, and the two test specs are complete enough for a reader to reason about or reproduce, and the BOLA/IDOR classification is a standard, well-established category. What is not evidenced is the generalization that AI assistants often produce this shape of code — that rests on one practitioner's unquantified review experience in a single self-published post with no second source.
No adoption signal in supplied sources
The cluster contains no release, deployment, benchmark, incident, pricing, licensing, or usage disclosure. No tool, scanner, policy framework, or organizational practice is reported as shipped or adopted, and no exploited-in-the-wild instance is cited, so adoption cannot be scored without inventing facts.
Modest overstatement in the prevalence framing
The post's substantive claims are restrained and even self-limiting — it declines to invent vulnerabilities, tells the reviewer to mark framework assumptions as needing verification, and defers negative testing to a later article. The overstatement is narrow: the headline framing that AI-generated code 'often' skips object-level authorization, and the story's implication that IDOR is now a default review item, exceed what one illustrative snippet can support for a vulnerability class that predates AI assistants by decades.
Practitioner post referencing the author's own review prompts
The piece is self-published on dev.to and cites 'the Security Deep-Dive' prompt the author uses, plus a second adversarial prompt pass, positioning the author's own review methodology and prompt material. That is a mild promotional interest that shapes emphasis toward reviewer technique. There is no vendor sponsorship, model-vendor stake, or product pitch disclosed in the source, and the technical guidance is generic and framework-standard rather than tied to a paid tool, so the incentive pressure is moderate rather than strong.
Logic is checkable; scope claim is single-sourced
Confidence is bounded by the one-source, one-publisher cluster and the absence of any adoption or incident evidence. It is not lower because the mechanism does not depend on trust: the code, the exploit path, and the test asymmetry can be evaluated directly by any reader familiar with Rails, and the vulnerability class is independently well known. The prevalence and 'default review item' framing remain unverified.
build
Four indexes, none of them covering: the 78-second page and the one index that fixed it1 distinct publisher
build
Coverage at 80% was a price on human attention, and CI is the wrong place to charge it1 distinct publisher
build
An AI test suite hit 94% coverage and missed the one branch that mattered1 distinct publisher
build
The query ran and the number was 38 percent high: reviewing AI-written SQL1 distinct publisher
Distinct publishers with included, body-backed reporting in this cluster.
dev.to
1 article · August 25, 2026