SkillAgentSearch skills...

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).

Install / Use

npx skills add utkusen/sast-skills --skill sast-idor

Installs into whichever agent you are using.

About this skill
📄

SKILL.md

Installable skill definition

Quality Score

89/100

Supported Platforms

Universal

Tags

Our assessment of sast-idor

sast-idor scores 89/100 on our quality scale, 1189th of 4,259 Development & Engineering skills we index (top 28%).

Its SKILL.md is 19 KB long, well organised into 31 sections with 14 code examples: a thorough specification that gives an agent plenty to work with.

With 1,321 GitHub stars, it is one of the more widely adopted skills in the catalogue.

Substance
30/30
Structure
20/20
Description
15/15
Adoption
13/20
Freshness
11/15

Maintenance, license and trust

  • The repository was last updated about 6 months ago. That is recent enough to be usable, but agent tooling moves fast, so check the instructions against your agent's current version.
  • It is released under the MIT license, a permissive license that allows use, modification and commercial use with attribution.
  • Its trust signals score 98/100, with no cautions. These come from repository metadata, not a code audit — read the skill file before letting an agent act on it.

sast-idor compared with similar skills

All 4 of these similar skills score higher than sast-idor; compare them before choosing.

SkillScoreStarsUpdatedFormat
sast-idor (this skill)by utkusen891.3k6mo agoSKILL.md
ai-job-searchby MadsLorentzen10044.6k1d agoCLAUDE.md
claude-howtoby luongnv8910041.7ktodayCLAUDE.md
algorithmic-artby anthropics100177.9k8d agoSKILL.md
pptxby anthropics100177.9k8d agoSKILL.md

Frequently asked questions

How do I install sast-idor?
Run npx skills add utkusen/sast-skills --skill sast-idor. The install tabs above show the steps for each supported agent.
Which AI agents does sast-idor work with?
It is written for Universal, as a SKILL.md file. Other agents that read the same format can often use it too.
Is sast-idor safe to use?
It is MIT-licensed and scores 98/100 on trust signals. Skills are instructions an agent will follow, so read the file before installing it and do not approve commands you do not understand.
Is sast-idor still maintained?
The repository was last updated about 6 months ago. That is recent enough to be usable, but agent tooling moves fast, so check the instructions against your agent's current version.

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();
    if (!acct.getOwnerId().equals(auth.getName()))
        throw new AccessDeniedException("Forbidden");
    return acct;
}

Go

// VULNERABLE
func GetOrder(w http.ResponseWriter, r *http.Request) {
    id := chi.URLParam(r, "id")
    order, _ := db.GetOrder(id)
    json.NewEncoder(w).Encode(order)
}

// SECURE
func GetOrder(w http.ResponseWriter, r *http.Request) {
    id := chi.URLParam(r, "id")
    userID := r.Context().Value("userID").(string)
    order, _ := db.GetOrderByUser(id, userID)
    json.NewEncoder(w).Encode(order)
}

PHP — Laravel

// VULNERABLE
public function show($id) {
    return Invoice::findOrFail($id);
}

// SECURE (scoped query)
public function show($id) {
    return auth()->user()->invoices()->findOrFail($id);
}

// SECURE (policy)
public function show($id) {
    $invoice = Invoice::findOrFail($id);
    $this->authorize('view', $invoice);
    return $invoice;
}

C# — ASP.NET Core

// VULNERABLE
[HttpGet("api/profiles/{id}")]
public async Task<IActionResult> GetProfile(int id) {
    var profile = await _db.Profiles.FindAsync(id);
    return Ok(profile);
}

// SECURE
[HttpGet("api/profiles/{id}")]
public async Task<IActionResult> GetProfile(int id) {
    var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
    var profile = await _db.Profiles.FirstOrDefaultAsync(p => p.Id == id && p.UserId == userId);
    if (profile == null) return NotFound();
    return Ok(profile);
}

Execution

This skill runs in three phases using subagents. Pass the contents of sast/architecture.md to all subagents as context.

Phase 1: Recon — Find Candidate Endpoints

Launch a subagent with the following instructions:

Goal: Find every endpoint, controller action, or handler that retrieves, modifies, or deletes a specific object using a user-supplied identifier. Write results to sast/idor-recon.md.

Context: You will be given the project's architecture summary. Use it to understand the tech stack, frameworks, route definitions, and data access patterns.

What to search for:

  1. Route definitions that contain ID parameters:

    • Path parameters: :id, {id}, <int:id>, [id]
    • Search patterns: route/path/endpoint definitions with parameter placeholders
  2. Controller/handler methods that accept ID arguments and use them to fetch or mutate objects:

    • ORM lookups: find(id), findById(), get(id=), objects.get(), findOne(), findUnique(), findFirst(), query.get(), where(id:)
    • Raw queries: SELECT ... WHERE id = ?, etc.
    • Also look for delete, update operations with user-supplied IDs
  3. Request body or query parameter IDs used in operations:

    • req.body.userId, req.query.id, request.data['account_id'], etc.
  4. GraphQL resolvers and mutations that accept ID arguments

  5. File/resource access by user-supplied path or filename

What to ignore:

  • Endpoints that are intentionally public (no auth required by design)
  • Admin-only endpoints behind role-based checks (these are a different class)
  • Endpoints where the only ID used is the authenticated user's own ID (e.g., GET /api/me/profile)
  • Static asset serving

Output format — write to sast/idor-recon.md:

# IDOR Recon: [Project Name]

## Summary
Found [N] candidate endpoints that use user-supplied identifiers to access objects.

## Candidates

### 1. [Descriptive name]
- **File**: `path/to/file.ext` (lines X-Y)
- **Endpoint**: `METHOD /path/:param`
- **Identifier source**: [path param / query param / body field]
- **Operation**: [read / update / delete]
- **Object accessed**: [model/table name]
- **Code snippet**:

[relevant code]


[Repeat for each candidate]

Phase 2: Verify — Check Authorization (Batched)

After Phase 1 completes, read sast/idor-recon.md and split the candidates into batches of up to 3 candidates each. Launch one subagent per batch in parallel. Each subagent verifies only its assigned candidates and writes results to its own batch file.

Batching procedure (you, the orchestrator, do this — not a subagent):

  1. Read sast/idor-recon.md and count the numbered candidate sections (### 1., ### 2., etc.).
  2. Divide them into batches of up to 3. For example, 8 candidates → 3 batches (1-3, 4-6, 7-8).
  3. For each batch, extract the full text of those candidate sections from the recon file.
  4. Launch all batch subagents in parallel, passing each one only its assigned candidates.
  5. Each subagent writes to sast/idor-batch-N.md where N is the 1-based batch number.
  6. Identify the project's primary language/framework from sast/architecture.md and select only the matching examples from the "Vulnerable vs. Secure Examples" section above. For example, if the project uses Node.js/Express with Prisma, include only the "Node.js — Express / Prisma" and "Node.js — Express / Mongoose" examples. Include these selected examples in each subagent's instructions where indicated by [TECH-STACK EXAMPLES] below.

Give each batch subagent the following instructions (substitute the batch-specific values):

Goal: Verify the following IDOR (Insecure Direct Object Reference) candidates and determine whether adequate authorization checks exist. Our goal is to find IDOR vulnerabilities. Write results to sast/idor-batch-[N].md.

Your assigned candidates (from the recon phase):

[Paste the full text of the assigned candidate sections here, preserving the original numbering]

Context: You will be given the project's architecture summary. Use it to understand the auth mechanism, middleware stack, and ORM patterns.

IDOR Reference — What to look for:

IDOR occurs when an authenticated user can access or modify resources belonging to another user by changing an identifier in the request. Focus on *horizontal privilege escalation

Truncated for display — read the full file on GitHub.

Related Skills

View on GitHub
GitHub Stars1.3k
CategoryDevelopment
Updated5mo ago
Forks65

Trust signals

98/100

From repository metadata: license, adoption, age and documentation. Not a code audit — see the Safety scan above for what the skill file itself contains.

1 info