1. Insecure direct object reference
Symptom
Authenticated endpoint, correct-looking code, and any user can read any record by changing a number in the URL.
The pattern
app.get("/api/invoices/:id", requireAuth, async (req, res) => {
const invoice = await db.invoice.findUnique({ where: { id: req.params.id } });
res.json(invoice);
});Why it bites
`requireAuth` proves the caller is logged in and nothing more. The lookup is keyed entirely on user-supplied input, so invoice 1002 is readable by the owner of invoice 1001. Tests pass because they request the invoice the test user owns.
The fix
app.get("/api/invoices/:id", requireAuth, async (req, res) => {
// Scope the query by owner so the wrong record can't be addressed at all.
const invoice = await db.invoice.findFirst({
where: { id: req.params.id, orgId: req.user.orgId },
});
if (!invoice) return res.status(404).end(); // 404, not 403 — don't confirm existence
res.json(invoice);
});