cd /news/artificial-intelligence/idor-in-ai-generated-apis-the-owners… · home topics artificial-intelligence article
[ARTICLE · art-26263] src=dev.to ↗ pub= topic=artificial-intelligence verified=true sentiment=↓ negative

IDOR in AI-Generated APIs: The Ownership Check Cursor Always Skips

A developer discovered that AI code generators like Cursor consistently omit ownership checks in API endpoints, leading to Insecure Direct Object Reference (IDOR) vulnerabilities. The AI correctly implements authentication middleware but fails to verify that the authenticated user owns the requested resource, a pattern traced back to training data that focuses on authentication rather than authorization. The developer recommends adding a simple ownership check after every resource fetch and using tools like semgrep or SafeWeave to catch the pattern before deployment.

read3 min publishedJun 13, 2026

findById

call fixes the entire patternI reviewed a friend's side project last month. Solid app -- JWT auth, protected routes, refresh token rotation. Then I ran a quick test: logged in as User A, grabbed a document ID from the URL, opened a private tab as User B, and requested the same endpoint.

User A's data came back clean.

He'd built the whole backend in Cursor. The AI had done a genuinely good job with authentication -- middleware, token validation, all wired up correctly. But every single resource endpoint had the same gap: it checked whether you were logged in. It never checked whether the resource belonged to you.

That's CWE-639. Authorization Bypass Through User-Controlled Key. OWASP Top 10, A01: Broken Access Control. And AI code generators reproduce it at scale.

Here's what Cursor generates for a document endpoint:

// CWE-639: authenticated but no ownership check
app.get('/api/documents/:id', authenticate, async (req, res) => {
  const doc = await Document.findById(req.params.id);
  if (!doc) return res.status(404).json({ error: 'Not found' });
  res.json(doc);
});

Authentication passes. The route looks protected. But swap :id

for any valid document ID in the database and you get the data -- regardless of who owns it. Change the number. Get the record. That's IDOR.

The same pattern shows up in PUT and DELETE routes. Cursor wires up authenticate

correctly every time. It skips the one line that makes the route actually private.

I've seen this pattern in payment record endpoints, private message threads, medical note APIs. The auth middleware is there. The access control is not.

The reason is boring. AI models train on tutorials, StackOverflow answers, and open-source repos. Most of that code is written to teach how authentication works -- JWT validation, session middleware, token refresh. It demonstrates the concept correctly.

What tutorial code almost never models: the ownership check after the fetch. That's assumed to be obvious. It's left as an exercise. The post is about JWTs, not about who owns the document.

The model learned the template. It didn't learn the gap.

One check. After every resource fetch:

// Fixed: ownership validated after fetch
app.get('/api/documents/:id', authenticate, async (req, res) => {
  const doc = await Document.findById(req.params.id);
  if (!doc || doc.userId.toString() !== req.user.id) {
    return res.status(403).json({ error: 'Forbidden' });
  }
  res.json(doc);
});

Two notes on this:

Return 403, not 404. Returning 404 when "the document exists but isn't yours" leaks less about what IDs exist. Some teams prefer it. Either way, the ownership check is what matters.

For larger codebases, a policy layer (CASL, Casbin, or a simple assertOwnership(doc, req.user)

helper) is cleaner than repeating this inline everywhere. But even the raw version above eliminates the bug class entirely.

A quick semgrep rule or grep for findById

without an ownership check in the same function scope will surface every unprotected endpoint in a codebase. Takes about 15 seconds to run.

I've been running SafeWeave for this. It hooks into Cursor and Claude Code as an MCP server and flags these patterns before I move on. That said, even a basic semgrep rule targeting findById

without ownership assertions will catch most of what's in this post. The important thing is catching it before it ships, whatever tool you use.

── more in #artificial-intelligence 4 stories · sorted by recency
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/idor-in-ai-generated…] indexed:0 read:3min 2026-06-13 ·