BETA Shoulder is in beta — Findings may sometimes be wrong. Your feedback shapes what we fix next. Share feedback
🗝️

Authorization Bypass Through User-Controlled Key

🛡️ 8 rules detect this

Authorization Bypass Through User-Controlled Key

The system's authorization functionality does not prevent one user from gaining access to another user's data or record by modifying the key value identifying the data.

Retrieval of a user record usually occurs in the system based on some key value. When a value that is directly specified by the user is used to look up that record, the key value can be modified to access records belonging to other users.

Prevalence
High
Frequently exploited
Impact
Critical
1 critical-severity rules
Prevention
Documented
8 fix examples
2 Prevention
2 Prevention

How to fix this vulnerability

Prevention strategies for Authorization Bypass via User Key based on 8 Shoulder detection rules.

Horizontal Privilege Escalation HIGH

Validate resource ownership before allowing modifications using user-supplied IDs

+8 -1 go
  func updateProfile(c *gin.Context) {
      profileID := c.Param("id")
-     db.Model(&Profile{}).Where("id = ?", profileID).Updates(data)
+     userID := c.GetString("user_id")
+     var profile Profile
+     db.First(&profile, profileID)
+     if profile.UserID != userID {
+         c.JSON(403, gin.H{"error": "unauthorized"})
+         return
+     }
+     db.Model(&profile).Updates(data)
  }
  
Insecure Direct Object Reference (IDOR) HIGH

Validate resource ownership before database access using user-supplied IDs

+8 -3 go
  func getUser(c *gin.Context) {
-     userID := c.Param("id")
-     var user User
-     db.First(&user, userID)
+     requestedID := c.Param("id")
+     currentID := c.GetString("user_id")
+     if requestedID != currentID {
+         c.JSON(403, gin.H{"error": "unauthorized"})
+         return
+     }
+     var user User
+     db.First(&user, requestedID)
      c.JSON(200, user)
  }
  
Potential IDOR - Generic Data Access MEDIUM

Verify resource ownership before returning data accessed by user-supplied identifiers

+6 -1 go
  func getOrder(c *gin.Context) {
      orderID := c.Param("id")
-     order := orders[orderID]
+     currentUserID := c.GetString("user_id")
+     order := orders[orderID]
+     if order.UserID != currentUserID {
+         c.JSON(403, gin.H{"error": "Forbidden"})
+         return
+     }
      c.JSON(200, order)
  }
  
Horizontal Privilege Escalation CRITICAL

Filter queries by authenticated user ID to verify resource ownership

+4 -1 javascript
  app.get('/api/profile/:userId', async (req, res) => {
-   const profile = await User.findOne({ where: { id: req.params.userId } });
+   const profile = await User.findOne({
+     where: { id: req.params.userId, userId: req.user.id }
+   });
+   if (!profile) return res.status(403).json({ error: 'Forbidden' });
    res.json(profile);
  });
  
Insecure Direct Object Reference (IDOR) HIGH

Include userId in database queries to verify resource ownership before access

+4 -1 javascript
  app.get('/api/orders/:id', async (req, res) => {
-   const order = await Order.findByPk(req.params.id);
+   const order = await Order.findOne({
+     where: { id: req.params.id, userId: req.user.id }
+   });
+   if (!order) return res.status(404).json({ error: 'Not found' });
    res.json(order);
  });
  
Potential IDOR - Generic Data Access MEDIUM

Verify resource ownership before returning data by checking it belongs to the authenticated user

+3 -0 javascript
  app.get('/api/orders/:id', (req, res) => {
    const order = orderRepo.findById(req.params.id);
+   if (order.userId !== req.user.id) {
+     return res.status(403).json({ error: 'Forbidden' });
+   }
    res.json(order);
  });
  
Insecure Direct Object Reference (IDOR) HIGH

Include the authenticated user as a filter condition in all ORM queries that use user-supplied IDs

+9 -3 python
- def get_document(request, doc_id):
-     requested_id = request.GET.get('id')
-     document = Document.objects.get(id=requested_id)
+ from django.contrib.auth.decorators import login_required
+ 
+ @login_required
+ def get_document(request, doc_id):
+     requested_id = request.GET.get('id')
+     document = Document.objects.get(
+         id=requested_id,
+         owner=request.user
+     )
      return JsonResponse(document.to_dict())
  
3 Detection
3 Detection

Find vulnerabilities in your code

Use Shoulder to scan your codebase for Authorization Bypass Through User-Controlled Key patterns. 8 rules.

terminal
# Scan with Shoulder CLI
npx @shoulderdev/cli trust --cwe=639

# Or scan entire project
npx @shoulderdev/cli trust .

Detection Rules (8)

4 Warning Signs
4 Warning Signs

What to watch for in code reviews

These patterns indicate potential Authorization Bypass Through User-Controlled Key vulnerabilities. Look for these during code reviews and security audits.

🟠
User can access other users' resources without authorization go-horizontal-privilege-escalation
🟠
horizontal privilege escalation where users can access or modify other users' resources go-horizontal-privilege-escalation
🟠
User-supplied ID used to access resource without authorization check go-idor
🟠
IDOR vulnerabilities where user-supplied IDs access resources without authorization checks go-idor
🟠
when user-controlled input (from URL parameters, query strings, or request body) is used directly to javascript-idor
🟠
database object access using user-provided IDs without ownership verification python-idor
🟡
route parameters flowing to data access without visible ownership verification go-idor-generic
🟡
endpoints where route parameters flow to generic data access patterns (Map javascript-idor-generic
🔍

Scan your codebase for Authorization Bypass Through User-Controlled Key

Shoulder CLI finds vulnerable patterns across your entire codebase.