-
Welcome to today’s challenge
-
I have decided to fully run it through
Claude MCPwithin Burp. -
Since I have recently fallen in love with how
Claude Codeworks and behaves as well as what it can offer compared toCodex, I felt it would be fitting to test it out -
As usual, I browsed the page to see how it works and then checked within Burp what is the behaviour in the background
-
I then asked
Claude MCPto find anything it can
MCP

- On its own, without much pushing, it found small snippet issues, and continued in that direction, however did not run for too long realising it is a dead end

- Snippet
#4was a potential for about 30 seconds …

- After 2 minutes of trying it managed to find the issue
- It has burned through fair few tokens to get there but nevertheless it was a very satisfying moment watching it realise its own mistakes

MCP Approach lessons
-
I asked Claude:
Since it took longer and we were a bit all over the place, tell me how you would have tested it differently? -
Looking back at my approach, here’s what I should have done differently:
-
What I Did Wrong
- Focused too much on read-based IDOR - I kept trying to access snippets by ID, admin endpoints, etc. I was looking for unauthorized read access.
- Ignored state-changing operations - The profile endpoint returned 500 errors and I dismissed it as broken rather than investigating further.
- Didn’t enumerate all endpoints systematically - I found PUT /api/profile existed (returned 500) but never tried sub-paths like /api/profile/password.
-
Better Approach
-
Map all authenticated functionality first - When testing BAC, list every action a user can perform: create snippet, edit snippet, delete snippet, change password, update profile, etc. - Each of these is a potential IDOR target.
-
For each endpoint, check for user_id/id parameters - Any request that includes a user identifier (user_id, id, owner_id) is a prime IDOR candidate. - Test by changing the ID to another user (1 is always a good guess for admin).
-
Prioritise write operations over read - Password change, profile update, delete operations are higher impact than just reading data. - When the hint is “broken access control,” think about what damage an attacker could do - account takeover via password change is classic.
-
When an endpoint returns errors, dig deeper - The 500 “Database error” on PUT /api/profile was a signal - it meant the endpoint existed but my payload was wrong. - I should have fuzzed the path (/api/profile/password, /api/profile/email) and field names.
-
-
Lesson: Always test password/credential change functionality for IDOR - it’s one of the most common and critical patterns.
Security Takeaways
- Always test credential-changing endpoints for IDOR - password reset, email change, and similar sensitive operations are high-value targets
- Client-supplied user identifiers cannot be trusted - the user_id in the request body was used directly without validation
- Error messages reveal endpoint existence - 500 “Database error” vs 404 “Cannot PUT” helped identify valid endpoints
- JWT tokens should be the source of truth - user identity should come from the authenticated token, not request parameters
Impact
- Severity:
Critical - Account Takeover: Full compromise of any user account including administrator
- Data Breach: Access to all private snippets and user data
- Privilege Escalation: Regular user can become admin
- Business Impact: Complete loss of confidentiality, integrity, and trust
Vulnerability Classification
- OWASP Top 10 2021: A01:2021 - Broken Access Control
- CWE-639: Authorization Bypass Through User-Controlled Key (IDOR)
- CWE-284: Improper Access Control
- CVSS 3.1 Score: 9.8 (Critical)
Root Cause
The /api/profile/password endpoint accepted a user_id parameter from the request body and used it directly in the database query without verifying that:
- The
user_idmatches the authenticated user’s ID from the JWT token - The requesting user has permission to modify that account
// Vulnerable code pattern (pseudocode)
app.put('/api/profile/password', authenticate, (req, res) => {
const { user_id, password } = req.body; // VULNERABLE: trusts client input
db.query('UPDATE users SET password = ? WHERE id = ?', [hash(password), user_id]);
});Remediation
- Use session/token for user identity:
// Fixed code pattern
app.put('/api/profile/password', authenticate, (req, res) => {
const user_id = req.user.id; // FIXED: from JWT token, not request body
const { password } = req.body;
db.query('UPDATE users SET password = ? WHERE id = ?', [hash(password), user_id]);
});- If
user_idmust be in request, validate ownership:
if (req.body.user_id !== req.user.id) {
return res.status(403).json({ error: 'Forbidden' });
}- Implement proper authorization checks at the middleware level
- Log and alert on attempts to modify other users’ data
- Security testing - include IDOR checks in CI/CD pipeline