Skip to content
Back to home

CODING FINDS

Notes from the terminal.

Short write-ups of things I learned the hard way: the problem, the fix and the result, with the smallest snippet that shows it.

FOR CODING AGENTS

Every note is also available over MCP, so your coding agent can look up a fix before it writes the bug.

[MCP server URL]
All notes
Laravel

Look up user-supplied IDs through the relationship

Problem. When an ID arrives in a request, Task::findOrFail($id) will load any task in the database. Change the number in the form or the URL and you can reach a task in somebody else's project. This is an insecure direct object reference, one of the most common access-control bugs.

The usual guard is a manual check after the query that compares project_id with the current project. It works until someone adds a new endpoint and forgets it.

Fix. Query through the relationship instead. $project->tasks() already constrains the query with where project_id = ?, so findOrFail() only searches that project's tasks, and a task from another project is simply not found.

php
// Before: any task in the database will do$task = Task::findOrFail($request->integer('task_id'));// The check every endpoint has to rememberif ($task->project_id !== $project->id) {    abort(404);}// After: the relationship adds "where project_id = ?"$task = $project->tasks()->findOrFail($request->integer('task_id'));

Result. There is no ownership check left to forget, and a foreign ID gets the same 404 as one that does not exist, so the response gives nothing away. The project itself still needs its own authorization check; this covers everything below it. For IDs in the URL, scoped route model binding does the same job: add ->scopeBindings() to a route like /projects/{project}/tasks/{task} and Laravel resolves the task through $project->tasks().

Stuck on something like this?

Tell me what you are working on. I’ll help you find it, fix it and keep it fixed.

Book a call