Skip to content

feat: Add IDOR Vulnerability#504

Merged
preetkaran20 merged 3 commits intoSasanLabs:masterfrom
antriksh-9:clean-idor
Mar 7, 2026
Merged

feat: Add IDOR Vulnerability#504
preetkaran20 merged 3 commits intoSasanLabs:masterfrom
antriksh-9:clean-idor

Conversation

@antriksh-9
Copy link
Contributor

@antriksh-9 antriksh-9 commented Feb 19, 2026

Description

This PR introduces a new IDOR (Insecure Direct Object Reference) vulnerability under Broken Access Control.

The implementation demonstrates how improper authorisation checks allow users to access resources belonging to other users.

Fixes: #498

Changes Added

  • Added IDORVulnerability.java

  • Added new enum entry in VulnerabilityType:

    • INSECURE_DIRECT_OBJECT_REFERENCE (CWE-639)
  • Implemented 3 progressive levels:

    • LEVEL_1 – No authentication
    • LEVEL_2 – Authentication present but no authorization check
    • LEVEL_3 (Secure) – Proper ownership validation
  • Added templates for:

    • LEVEL_1
    • LEVEL_2
    • LEVEL_3
  • Added corresponding:

    • HTML
    • CSS
    • JS
  • Added entries in messages.properties

  • Added IDORVulnerabilityTest

  • Covered:

    • Vulnerable behavior (LEVEL_1 & LEVEL_2
    • Secure behavior (LEVEL_3)
  • Verified using:

    ./gradlew test --tests "*IDORVulnerabilityTest"
    

Verification:

  • ✅ Unit tests passing
  • ✅ Verified via browser UI
  • ✅ Confirmed:
    • LEVEL_1 allows unrestricted access
    • LEVEL_2 demonstrates broken authorization
    • LEVEL_3 restricts access correctly (isValid=false)

@codecov-commenter
Copy link

codecov-commenter commented Feb 25, 2026

Codecov Report

❌ Patch coverage is 31.08108% with 102 lines in your changes missing coverage. Please review.
✅ Project coverage is 47.86%. Comparing base (31b2c65) to head (d4cd175).
⚠️ Report is 33 commits behind head on master.

Files with missing lines Patch % Lines
.../service/vulnerability/idor/IDORVulnerability.java 30.55% 82 Missing and 18 partials ⚠️
...labs/configuration/VulnerableAppConfiguration.java 0.00% 2 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##             master     #504      +/-   ##
============================================
- Coverage     49.07%   47.86%   -1.21%     
- Complexity      346      353       +7     
============================================
  Files            56       57       +1     
  Lines          2101     2248     +147     
  Branches        226      243      +17     
============================================
+ Hits           1031     1076      +45     
- Misses          989     1073      +84     
- Partials         81       99      +18     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@preetkaran20
Copy link
Member

@antriksh-9 UI is not consistent with the project theme. Please use right CSS classes.

image

description = "IDOR_LEVEL_2_FAKE_LOGIN_NO_AUTHZ",
payload = "Logged in user is 101 but try accessing 102")
@VulnerableAppRequestMapping(value = LevelConstants.LEVEL_2, htmlTemplate = "LEVEL_2/IDOR")
public ResponseEntity<GenericVulnerabilityResponseBean<String>> idorLevel2(
Copy link
Member

@preetkaran20 preetkaran20 Feb 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't seems right to me. The way I am thinking is: Give a login screen, and let user get details for other user instead of logged in user.

How can we do this is? create 3 users in database (we have H2 db), you can create the user in init script, we already have scripts example: https://github.com/SasanLabs/VulnerableApp/tree/master/src/main/resources/scripts/SQLInjection/db, you can create another script under folder idor/db/ and then refer it in https://github.com/SasanLabs/VulnerableApp/blob/master/src/main/java/org/sasanlabs/configuration/VulnerableAppConfiguration.java#L130.

Login the user in level 1 and give logout button too in level 1 and then let the user access its details like salary etc.
Flow is User login -> we show all the user details like full profile.

Now level 1 would allow to access user profile like all the Personal details even for other users.

Level 2 would be little difficult where user will login again on the level (set cookie on login) but say cookie can be tampered to get other users details.

Level 3 would add a bit more difficulty like JWT or however you want to think on this.

Level 4 be secure or you can think more levels too.
Level 5 can be role based :) additional thing to learn more and introduce vulnerabilities related to RBAC

Level 6 secure RBAC
Level 7 Insecure ABAC (Attribute checks like salary is visible ot everyone)

Level 8 Secure ABAC (only if attribute matches user id)

I am just giving examples of number of Levels but you can implement as per your thought.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Working on it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactored implementation:

  • Level 1 – No authorization check

  • Level 2 – Cookie tampering

  • Level 3 – Base64 token tampering (userId manipulation)

  • Level 4 – Broken RBAC (role escalation via unsigned token)

  • Level 5 – Secure RBAC implementation (proper role validation from DB)

@antriksh-9
Copy link
Contributor Author

@antriksh-9 UI is not consistent with the project theme. Please use right CSS classes.

Screenshot from 2026-03-01 15-07-33

I've updated the UI keeping in mind the project theme, however, if any changes are required please suggest..

@antriksh-9 antriksh-9 requested a review from preetkaran20 March 1, 2026 12:05
vulnerabilityExposed = VulnerabilityType.INSECURE_DIRECT_OBJECT_REFERENCE,
description = "IDOR_LEVEL_2_COOKIE_TAMPERING",
payload = "IDOR_PAYLOAD_LEVEL_2")
@VulnerableAppRequestMapping(value = LevelConstants.LEVEL_2, htmlTemplate = "LEVEL_2/IDOR")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest using POST request as Login and GET are not considered good.
requestMethod = RequestMethod.POST can be added to Annotation to make it post endpoint.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is applicable to all levels.

sql,
new Object[] {loggedInUser},
(rs, rowNum) ->
"User: "
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Return a User Object instead of returning string.

Create a User POJO with UserName , Id , Salary etc and return that. In UI you can read it. it is good practice.

sql,
new Object[] {username, password},
(rs, rowNum) ->
"{\"userId\":"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here, return POJO


int userId = Integer.parseInt(decoded.split("userId\":")[1].split(",")[0]);

String role = decoded.split("role\":\"")[1].split("\"")[0];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better way is to use JSON and convert it into POJO instead of splitting as split is error prone and it is not a good practice

sql,
new Object[] {userId},
(rs, rowNum) ->
"User: "
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please return POJO and that would clean up entire code.


String decoded = new String(Base64.getDecoder().decode(token));

int tokenUserId = Integer.parseInt(decoded.split("userId\":")[1].split(",")[0]);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please use POJO and JSON Deserialize into POJO

// Proper authorization
if ("ADMIN".equalsIgnoreCase(actualRole) || tokenUserId == id) {

String sql = "SELECT username, salary, role FROM idor_users WHERE id=?";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this can be made constant string.

// LOGIN FLOW
if (username != null && password != null) {

String sql = "SELECT id, role FROM idor_users WHERE username=? AND password=?";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this could be made string constant and then reused at multiple placed.

String role = decoded.split("role\":\"")[1].split("\"")[0];

// RBAC logic
if ("ADMIN".equalsIgnoreCase(role) || tokenUserId == id) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make it a String constant as well.

<div id="loggedInDisplay"></div>

<h5>Fetch Profile</h5>
<div id="profileSection">
Copy link
Member

@preetkaran20 preetkaran20 Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should just have fetch profile button and that is based on logged in user and let user/scanner find out that there is a way to fetch other users details as well.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this dropdown is not needed.

let password = document.getElementById("password").value;

let url = getUrlForVulnerabilityLevel();
let queryParams = "?username=" + username + "&password=" + password;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please use POST API


<div id="infoSection">
<p>
The application uses a Base64 encoded token.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is kind of a hint. let user find it out from the hint? Hint comes from AttackVector annotation


<div id="infoSection">
<p>
The application enforces role-based access.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is again another hint. Let user find it out from hint section.,

@@ -0,0 +1,50 @@
<div id="idor_level_4">

<h3>IDOR - Level 4 (Broken RBAC)</h3>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can remove Broken RBAC from this and let user find it out

</div>

<div id="response"></div>
<div id="hint">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hints come automatically from AttackVector Annotation. Use that annotation for this.


<div id="infoSection">
<p>
This version validates user role from the database.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not needed i think.


<div id="response"></div>
<div id="hint">
<p>Hint: You can use <code>atob(token)</code> and <code>btoa()</code>in the browser console to decode/encode Base64.</p>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hints can be removed.

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.RequestParam;

@VulnerableAppRestController(descriptionLabel = "IDOR_VULNERABILITY", value = "IDORVulnerability")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can add more details into IDOR_Vulnerability label eg. COMMAND_INJECTION_VULNERABILITY

It can have details like reference for users to learn. This value is shown

Image

@@ -0,0 +1,5 @@
IDOR_PAYLOAD_LEVEL_1=Login as one user and modify the 'id' request parameter to access another user's data.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these are hints. you can enahcne them and then it will be rendered in UI.

Example:

Image

@preetkaran20
Copy link
Member

image

Overall Looks good. Small changes in code and UI can be made a bit more good looking by reducing spaces as pointed by arrows.

@preetkaran20
Copy link
Member

@antriksh-9 thanks a lot for the PR. I will refactor the code but overall logic remains same. thanks for all the help. Feel free to pick another level.

@preetkaran20 preetkaran20 merged commit 55d3356 into SasanLabs:master Mar 7, 2026
1 of 2 checks passed
@antriksh-9
Copy link
Contributor Author

antriksh-9 commented Mar 8, 2026

@antriksh-9 thanks a lot for the PR. I will refactor the code but overall logic remains same. thanks for all the help. Feel free to pick another level.

I was working on it, would have commit changes today.
Apologies but was this merged as there was delay in commiting changes?

@preetkaran20
Copy link
Member

preetkaran20 commented Mar 8, 2026

@antriksh-9 thanks a lot for the PR. I will refactor the code but overall logic remains same. thanks for all the help. Feel free to pick another level.

I was working on it, would have commit changes today. Apologies but was this merged as there was delay in commiting changes?

oh sorry, Apologies for taking over the PR, Yes this PR is merged but I added another PR with refactoring. Sorry for the mess up, I will be more concisions from now onwards.

@antriksh-9
Copy link
Contributor Author

@antriksh-9 thanks a lot for the PR. I will refactor the code but overall logic remains same. thanks for all the help. Feel free to pick another level.

I was working on it, would have commit changes today. Apologies but was this merged as there was delay in commiting changes?

oh sorry, Apologies for taking over the PR, Yes this PR is merged but I added another PR with refactoring. Sorry for the mess up, I will be more concisions from now onwards.

Oh no worries, probably I should have left "Working on the changes" comment here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add any tech related vulnerability to VulnerableAPP

3 participants