Skip to content
Security
Skill

/sast-idor

Detect Insecure Direct Object Reference (IDOR) vulnerabilities in a codebase using a three-phase approach: recon (find candidates), batched verify (check authorization in parallel subagents, 3 candidates each), and merge (consolidate batch results). Checks endpoints for missing

From plugin
sast-skills
1.3k16 skills
Install
$ npx -y skills add utkusen/sast-skills --skill sast-idor --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/sast-idor

Context preview

The summary Claude sees to decide when to auto-load this skill.

Detect Insecure Direct Object Reference (IDOR) vulnerabilities in a codebase using a three-phase approach: recon (find candidates), batched verify (check authorization in parallel subagents, 3 candidates each), and merge (consolidate batch results). Checks endpoints for missing

SKILL.md

sast-idor.SKILL.md
name: sast-idor
description: >-
  Detect Insecure Direct Object Reference (IDOR) vulnerabilities in a codebase
  using a three-phase approach: recon (find candidates), batched verify (check
  authorization in parallel subagents, 3 candidates each), and merge (consolidate
  batch results). Checks endpoints for missing ownership or authorization checks
  on user-supplied identifiers. Requires sast/architecture.md (run sast-analysis
  first). Outputs findings to sast/idor-results.md. Use when asked to find IDOR
  or authorization bypass bugs.

IDOR (Insecure Direct Object Reference) Detection

You are performing a focused security assessment to find IDOR vulnerabilities in a codebase. This skill uses a three-phase approach with subagents: **recon** (find candidate endpoints), **batched verify** (check authorization in parallel batches of 3), and **merge** (consolidate results).

**Prerequisites**: `sast/architecture.md` must exist. Run the analysis skill first if it doesn't.

---

What is IDOR

IDOR occurs when an application uses a user-supplied identifier (ID, slug, filename, etc.) to directly access an object **without verifying the requesting user is authorized to access that specific object**. The application authenticates the user but fails to check ownership or permissions on the requested resource.

The core pattern: *authenticated user A can access or modify resources belonging to user B by changing an identifier in the request.*

What IDOR IS

  • Changing `/api/orders/1001` to `/api/orders/1002` and seeing another user's order
  • Sending `DELETE /api/documents/555` to delete a document you don't own
  • Modifying `{"account_id": 789}` in a request body to transfer money from someone else's account
  • Changing a file download parameter `?file_id=42` to access another user's private file
  • Updating another user's profile via `PUT /api/users/other-user-id`

What IDOR is NOT

Do not flag these as IDOR:

  • **Missing authentication**: Endpoint requires no login at all → that's "Unauthenticated Access", a different class
  • **Broken function-level access control**: Regular user accessing `/admin/dashboard` → that's vertical privilege escalation, not IDOR
  • **Public resources**: Accessing `/api/posts/123` where posts are intentionally public is not IDOR
  • **Parameter tampering on non-object fields**: Changing `role=admin` or `price=0` in a request → that's mass assignment or business logic, not IDOR
  • **SQL injection via ID fields**: `?id=1 OR 1=1` → that's SQLi, not IDOR

Authorization Patterns That Prevent IDOR

When you see these patterns, the endpoint is likely **not vulnerable**:

**1. Query scoped to current user (most common fix)**

# The query itself ensures only the user's own records are returned
Order.objects.filter(id=order_id, user=request.user)       # Django
current_user.orders.find(params[:id])                       # Rails
Order.findOne({ _id: orderId, userId: req.user.id })        # Mongoose
SELECT * FROM orders WHERE id = ? AND user_id = ?           # Raw SQL

**2. Explicit ownership check after fetch**

order = Order.find(order_id)
if order.user_id != current_user.id:
    raise Forbidden

**3. Policy / ability / authorization middleware**

authorize('view', order)                    # Laravel Policy
can?(:read, @order)                         # CanCanCan (Rails)
@PreAuthorize("@auth.ownsOrder(#orderId)")  # Spring Security

**4. Tenant/organization scoping**

# Multi-tenant apps that scope all queries to the tenant
tenant = get_current_tenant(request)
Order.objects.filter(id=order_id, tenant=tenant)

---

Vulnerable vs. Secure Examples

Python — Django

# VULNERABLE: fetches any order by ID, no ownership check
def get_order(request, order_id):
    order = Order.objects.get(id=order_id)
    return JsonResponse(model_to_dict(order))

# SECURE: query scoped to requesting user
def get_order(request, order_id):
    order = get_object_or_404(Order, id=order_id, user=request.user)
    return JsonResponse(model_to_dict(order))

Python — Flask / SQLAlchemy

# VULNERABLE
@app.route('/api/documents/<int:doc_id>')
@login_required
def get_document(doc_id):
    doc = Document.query.get_or_404(doc_id)
    return jsonify(doc.serialize())

# SECURE
@app.route('/api/documents/<int:doc_id>')
@login_required
def get_document(doc_id):
    doc = Document.query.filter_by(id=doc_id, owner_id=current_user.id).first_or_404()
    return jsonify(doc.serialize())

Node.js — Express / Mongoose

// VULNERABLE
router.get('/api/orders/:id', auth, async (req, res) => {
  const order = await Order.findById(req.params.id);
  res.json(order);
});

// SECURE
router.get('/api/orders/:id', auth, async (req, res) => {
  const order = await Order.findOne({ _id: req.params.id, userId: req.user.id });
  if (!order) return res.status(404).json({ error: 'Not found' });
  res.json(order);
});

Node.js — Express / Prisma

// VULNERABLE
router.get('/api/invoices/:id', auth, async (req, res) => {
  const invoice = await prisma.invoice.findUnique({ where: { id: req.params.id } });
  res.json(invoice);
});

// SECURE
router.get('/api/invoices/:id', auth, async (req, res) => {
  const invoice = await prisma.invoice.findFirst({
    where: { id: req.params.id, userId: req.user.id }
  });
  if (!invoice) return res.status(404).json({ error: 'Not found' });
  res.json(invoice);
});

Ruby on Rails

# VULNERABLE
def show
  @order = Order.find(params[:id])
end

# SECURE
def show
  @order = current_user.orders.find(params[:id])
end

Java — Spring Boot

// VULNERABLE
@GetMapping("/api/accounts/{id}")
public Account getAccount(@PathVariable Long id) {
    return accountRepo.findById(id).orElseThrow();
}

// SECURE
@GetMapping("/api/accounts/{id}")
public Account getAccount(@PathVariable Long id, Authentication auth) {
    Account acct = accountRepo.findById(id).orElseThrow();
Read more
Ships withsast-skills

A collection of agent skills that turn your LLM coding assistant into a fully functional SAST scanner to find vulnerabilities in your codebase. Works natively with Claude Code, Codex, Opencode, Cursor and any other assistant that supports agent skills.

Get the whole plugin
Stats
1,266
Stars
61
Forks
Maintained
Maintenance
MIT
License
4mo ago
Last commit
4mo ago
Created

Repo: utkusen/sast-skills

Other skills on sast-skills.