Skip to content
Back to skills

Owasp Idor Prevention

ASecurity

> Enforce object-level authorization so users can only access resources they own or are permitted to access

  • 20 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added September 11, 2026
securitytypescriptrustgoapidatabasesecurity

Works with

  • api

Security analysis

A100/100

Pro scans all 2 files and shows the line behind each finding

Scanned September 11, 2026

npx -y skills add Intense-Visions/harness-engineering --skill owasp-idor-prevention --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Owasp Idor Prevention?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Owasp Idor Prevention
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/intense-visions-owasp-idor-prevention/badge)](https://www.skillsdirectory.com/skills/intense-visions-owasp-idor-prevention)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
# OWASP IDOR Prevention

> Enforce object-level authorization so users can only access resources they own or are permitted to access

## When to Use

- Building any endpoint that fetches a resource by ID (GET /orders/:id, GET /files/:id)
- Implementing multi-tenant applications where data isolation is critical
- Reviewing CRUD APIs for missing ownership checks
- Designing authorization middleware or guards for resource access
- Building admin vs. user role separation

## Instructions

### Always Scope Queries to the Authenticated User

The most reliable pattern: include `userId` in every database query, not just in authorization checks after the fact.

```typescript
// BAD — fetches by ID only, attacker can enumerate any order
app.get('/orders/:id', authenticate, async (req, res) => {
  const order = await db.order.findUnique({ where: { id: req.params.id } });
  if (!order) return res.status(404).json({ error: 'Not found' });
  res.json(order); // returns order even if it belongs to another user
});

// GOOD — scope the query to the current user
app.get('/orders/:id', authenticate, async (req, res) => {
  const order = await db.order.findFirst({
    where: {
      id: req.params.id,
      userId: req.user.id, // IDOR prevention at query level
    },
  });
  if (!order) return res.status(404).json({ error: 'Not found' }); // same error for not found and unauthorized
  res.json(order);
});
```

### Authorization Service Pattern

Centralize ownership checks in a dedicated service to avoid scattered, inconsistent checks:

```typescript
// authorization.service.ts
@Injectable()
export class AuthorizationService {
  constructor(private db: PrismaService) {}

  async assertOwnsOrder(userId: string, orderId: string): Promise<Order> {
    const order = await this.db.order.findFirst({
      where: { id: orderId, userId },
    });
    if (!order) throw new ForbiddenException('Access denied');
    return order;
  }

  async assertCanAccessDocument(userId: string, docId: string): Promise<Document> {
    const doc = await this.db.document.findFirst({
      where: {
        id: docId,
        OR: [
          { ownerId: userId },
          { sharedWith: { some: { userId } } },
        ],
      },
    });
    if (!doc) throw new ForbiddenException('Access denied');
    return doc;
  }
}

// order.controller.ts
@Get(':id')
async getOrder(@Param('id') id: string, @CurrentUser() user: User) {
  return this.authz.assertOwnsOrder(user.id, id);
}
```

### Role-Based Access with Resource Guards

```typescript
// resource-owner.guard.ts
@Injectable()
export class ResourceOwnerGuard implements CanActivate {
  constructor(
    private reflector: Reflector,
    private authz: AuthorizationService,
  ) {}

  async canActivate(context: ExecutionContext): Promise<boolean> {
    const req = context.switchToHttp().getRequest();
    const userId = req.user.id;
    const resourceId = req.params.id;
    const resourceType = this.reflector.get<string>('resourceType', context.getHandler());

    await this.authz.assertOwns(userId, resourceType, resourceId);
    return true;
  }
}

// Usage
@Get(':id')
@SetMetadata('resourceType', 'order')
@UseGuards(ResourceOwnerGuard)
getOrder(@Param('id') id: string) { ... }
```

### Indirect Reference Maps (UUIDs over Sequential IDs)

Use UUIDs for public-facing resource identifiers. Sequential IDs make enumeration trivial.

```typescript
// PREDICTABLE — easy to enumerate
// GET /invoices/1, /invoices/2, /invoices/3 ...

// BETTER — UUID makes guessing computationally infeasible
// GET /invoices/550e8400-e29b-41d4-a716-446655440000

// Prisma schema
model Order {
  id     String @id @default(uuid())
  userId String
  // ...
}
```

For extra security with internal sequential IDs, map them to tokens:

```typescript
// Return opaque tokens instead of raw IDs
function encodeResourceId(internalId: number, secret: string): string {
  // Use a deterministic encryption (not hash) so you can decode
  return Buffer.from(`${internalId}:${secret}`).toString('base64url');
}
```

## Details

IDOR (also called BOLA — Broken Object Level Authorization) is the #1 API security issue per OWASP API Security Top 10. Authentication tells you WHO the user is; authorization tells you WHAT they can access.

**Common IDOR mistakes:**

- Checking auth at controller level but using unchecked ID in a service call
- Returning 403 only after fetching the resource (information still leaked in timing)
- Trusting user-supplied `userId` in request body instead of the JWT/session

**Return 404 not 403 for unauthorized resources** — returning 403 confirms the resource exists, enabling enumeration.

**Audit checklist:**

- Every `findById` / `findUnique` call — does it include `userId` or equivalent scope?
- Every bulk list endpoint — does it filter to current user's data?
- Admin routes — are they properly gated behind role checks?

## Source

https://owasp.org/www-project-top-ten/

## Process

1. Read the instructions and examples in this document.
2. Apply the patterns to your implementation, adapting to your specific context.
3. Verify your implementation against the details and edge cases listed above.

## Harness Integration

- **Type:** knowledge — this skill is a reference document, not a procedural workflow.
- **No tools or state** — consumed as context by other skills and agents.

## Success Criteria

- The patterns described in this document are applied correctly in the implementation.
- Edge cases and anti-patterns listed in this document are avoided.

Files in this skill

  • SKILL.md5.4 KB
  • skill.yaml907 B

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.