Skip to content

remediate: fix SAST scanner mappings and add validation test#608

Draft
Etoile-Bleu wants to merge 5 commits into
SasanLabs:masterfrom
Etoile-Bleu:fix-sast-mappings
Draft

remediate: fix SAST scanner mappings and add validation test#608
Etoile-Bleu wants to merge 5 commits into
SasanLabs:masterfrom
Etoile-Bleu:fix-sast-mappings

Conversation

@Etoile-Bleu
Copy link
Copy Markdown
Contributor

@Etoile-Bleu Etoile-Bleu commented May 9, 2026

Description

This PR cleans up and accurately re-maps the scanner/sast/expectedIssues.csv file by aligning vulnerability entries with actual actionable code sinks (SQL queries, reflection points, etc.) instead of boilerplate or incorrect line references.

Changes

  • CSV Audit & Remediation: Updated mappings for SQL Injection, XSS, Path Traversal, and Open Redirect to point to verified sinks.
  • File Path Fixes: Resolved issues with renamed or missing files (e.g., XSSInImgTagAttribute.java).
  • Regression Prevention: Added ExpectedIssuesCSVTest.java, a cross-platform JUnit test that validates the integrity of the CSV (file existence and line bounds) during the test lifecycle.

Future Recommendation: Dynamic Truth Generation

To eliminate manual maintenance drift, the repository could transition to a dynamic generation model:

  1. Source Markers: Add specialized comments (e.g., // SAST_SINK) directly on vulnerable lines.
  2. Metadata Harvesting: Use a build-time script to scan @AttackVector annotations and link them to the nearest marker.
  3. Automated Sync: Generate expectedIssues.csv as a build artifact, ensuring the SAST ground truth is always 100% synchronized with the source code.

This approach would provide the "ultimate" source of truth while removing the need for manual CSV updates.

Summary by CodeRabbit

  • Bug Fixes

    • Improved authentication token validation with cryptographic signing and expiration verification to prevent unauthorized access.
  • Tests

    • Expanded test coverage for authentication token handling, including validation of tampered, expired, and malformed tokens.
    • Added automated validation tests for security configuration files.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 9, 2026

Review Change Stack

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: ddc3e0dc-e192-43a5-b54c-3c11acb5cb38

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR migrates the IDOR authentication service from Base64-encoded JSON tokens to cryptographically signed HS256 JWTs with per-service random secrets, adds comprehensive tampering and expiration validation tests, and introduces CSV integrity validation for the SAST expected issues file.

Changes

IDOR Token JWT Migration

Layer / File(s) Summary
JWT Dependencies and Imports
src/main/java/org/sasanlabs/service/vulnerability/idor/IDORLoginService.java
Replaces Jackson and Base64 imports with Nimbus JOSE/JWT, SecureRandom, and Date classes for JWT creation and validation.
Shared Secret State
src/main/java/org/sasanlabs/service/vulnerability/idor/IDORLoginService.java
Introduces per-instance sharedSecret field initialized via SecureRandom in constructor; removes legacy ObjectMapper.
JWT Token Creation
src/main/java/org/sasanlabs/service/vulnerability/idor/IDORLoginService.java
loginWithToken now creates HS256-signed JWT with sub (user ID), role claim, and 1-hour expiration; returns token string wrapped in IDORLoginDetails.
JWT Token Validation and Decoding
src/main/java/org/sasanlabs/service/vulnerability/idor/IDORLoginService.java
decodeToken parses JWT, verifies MAC signature with sharedSecret, validates expiration, and reconstructs User from claims; throws IllegalArgumentException on any failure.
Legacy Code Removal
src/main/java/org/sasanlabs/service/vulnerability/idor/IDORLoginService.java
Removes Base64-encoded token payload handling and serialization helpers.
Test Infrastructure and Helpers
src/test/java/org/sasanlabs/service/vulnerability/idor/IDORLoginServiceTest.java
Adds Nimbus JOSE/JWT and reflection imports; provides getSharedSecret() helper to access service's shared secret during test execution.
Token Tampering and Expiration Tests
src/test/java/org/sasanlabs/service/vulnerability/idor/IDORLoginServiceTest.java
Adds three negative test cases: tampered token (modified payload/signature mismatch), expired token (past expiration time), and missing expiration claim.

SAST Expected Issues CSV Validation

Layer / File(s) Summary
CSV Path Configuration
src/test/java/org/sasanlabs/service/vulnerability/sast/ExpectedIssuesCSVTest.java
Defines CSV_PATH constant pointing to scanner/sast/expectedIssues.csv.
CSV Validation Logic
src/test/java/org/sasanlabs/service/vulnerability/sast/ExpectedIssuesCSVTest.java
Implements testExpectedIssuesCSV() to validate CSV existence, enforce row format, parse target line numbers, verify referenced files exist, and assert line numbers fall within file bounds.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

  • Secure Token Handling for IDOR Module #604: The PR directly implements secure token handling with HS256-signed JWTs using per-service random secrets and adds token verification/expiration validation as proposed in the issue.

Possibly related PRs

  • SasanLabs/VulnerableApp#605: Both PRs modify IDORLoginService to replace Base64-encoded user payloads with HS256-signed JWTs using shared secrets and add token tampering/expiration tests.

Poem

🐰 A rabbit hops through tokens signed with care,
HS256 secrets floating in the air,
Tampered payloads caught, expiration's key,
The CSV checklist verified by thee!
From Base64 chains to cryptography's might, 🔐✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title 'remediate: fix SAST scanner mappings and add validation test' clearly and accurately summarizes the main changes: fixing SAST scanner CSV mappings and adding a validation test for the CSV file.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@Etoile-Bleu Etoile-Bleu force-pushed the fix-sast-mappings branch from d05af58 to 29b04d7 Compare May 9, 2026 02:01
@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented May 9, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 57.52%. Comparing base (8e3055a) to head (023183c).
⚠️ Report is 4 commits behind head on master.

Additional details and impacted files
@@             Coverage Diff              @@
##             master     #608      +/-   ##
============================================
+ Coverage     53.12%   57.52%   +4.40%     
- Complexity      510      638     +128     
============================================
  Files            72       84      +12     
  Lines          2850     3275     +425     
  Branches        296      366      +70     
============================================
+ Hits           1514     1884     +370     
- Misses         1201     1223      +22     
- Partials        135      168      +33     

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

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/test/java/org/sasanlabs/service/vulnerability/idor/IDORLoginServiceTest.java (1)

100-112: ⚡ Quick win

Consider renaming tests to reflect JWT validation.

The test names WhenPayloadIsNotJson and WhenBase64IsInvalid suggest the old Base64-encoded JSON token format. With the JWT implementation, both tests now verify that malformed JWT strings trigger IllegalArgumentException during parsing. While the tests still provide value, renaming them would improve clarity.

💡 Suggested test names
 `@Test`
-void decodeToken_ShouldThrowIllegalArgumentException_WhenPayloadIsNotJson() {
+void decodeToken_ShouldThrowIllegalArgumentException_WhenTokenIsNotValidJWT() {
     String nonJsonPayload = java.util.Base64.getEncoder().encodeToString("not-json".getBytes());

     assertThrows(
             IllegalArgumentException.class, () -> idorLoginService.decodeToken(nonJsonPayload));
 }

 `@Test`
-void decodeToken_ShouldThrowIllegalArgumentException_WhenBase64IsInvalid() {
+void decodeToken_ShouldThrowIllegalArgumentException_WhenTokenIsMalformed() {
     assertThrows(
             IllegalArgumentException.class,
             () -> idorLoginService.decodeToken("@@not-base64@@"));
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/test/java/org/sasanlabs/service/vulnerability/idor/IDORLoginServiceTest.java`
around lines 100 - 112, The test method names
decodeToken_ShouldThrowIllegalArgumentException_WhenPayloadIsNotJson and
decodeToken_ShouldThrowIllegalArgumentException_WhenBase64IsInvalid no longer
match the JWT parsing behavior; rename them to reflect JWT validation (e.g.,
decodeToken_ShouldThrowIllegalArgumentException_ForMalformedJwt and
decodeToken_ShouldThrowIllegalArgumentException_ForInvalidJwtSegment) and update
any test annotations or references so idorLoginService.decodeToken is clearly
tested for malformed/invalid JWT input rather than legacy Base64 JSON payloads.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@src/test/java/org/sasanlabs/service/vulnerability/sast/ExpectedIssuesCSVTest.java`:
- Around line 34-35: The test uses new File(filePath) which treats relative file
paths against the process working directory; update ExpectedIssuesCSVTest to
resolve any relative CSV-referenced paths against the CSV file's directory
instead (use csvPath.getParent() or csvPath.toAbsolutePath().getParent() as the
stable base) and construct the target path via Paths.get(baseDir.toString(),
filePath) or baseDir.resolve(filePath).toFile(); apply the same change to both
places mentioned (lines 58–59) so all file lookups use the CSV's directory as
the base.
- Around line 16-21: Reformat the Javadoc comment on the ExpectedIssuesCSVTest
class (lines ~16-21) to satisfy Spotless wrapping rules (wrap lines to project
max line length and use standard Javadoc punctuation/spacing) and fix the
assertion formatting at lines ~62-63 in ExpectedIssuesCSVTest so it follows
project's assertion style (correct argument order and not splitting the
assertion across lines in a way that violates Spotless). Update the Javadoc and
the specific assertions in the ExpectedIssuesCSVTest class to be properly
wrapped and formatted so spotlessJavaCheck passes.

---

Nitpick comments:
In
`@src/test/java/org/sasanlabs/service/vulnerability/idor/IDORLoginServiceTest.java`:
- Around line 100-112: The test method names
decodeToken_ShouldThrowIllegalArgumentException_WhenPayloadIsNotJson and
decodeToken_ShouldThrowIllegalArgumentException_WhenBase64IsInvalid no longer
match the JWT parsing behavior; rename them to reflect JWT validation (e.g.,
decodeToken_ShouldThrowIllegalArgumentException_ForMalformedJwt and
decodeToken_ShouldThrowIllegalArgumentException_ForInvalidJwtSegment) and update
any test annotations or references so idorLoginService.decodeToken is clearly
tested for malformed/invalid JWT input rather than legacy Base64 JSON payloads.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 3bce97a5-c6c8-4afa-9b43-7f17fe2ce18c

📥 Commits

Reviewing files that changed from the base of the PR and between b586a5b and b6fb2b7.

⛔ Files ignored due to path filters (1)
  • scanner/sast/expectedIssues.csv is excluded by !**/*.csv
📒 Files selected for processing (3)
  • src/main/java/org/sasanlabs/service/vulnerability/idor/IDORLoginService.java
  • src/test/java/org/sasanlabs/service/vulnerability/idor/IDORLoginServiceTest.java
  • src/test/java/org/sasanlabs/service/vulnerability/sast/ExpectedIssuesCSVTest.java

Comment on lines +34 to +35
assertTrue(Files.exists(csvPath), "expectedIssues.csv not found at " + csvPath.toAbsolutePath());

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot May 9, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Resolve CSV-referenced file paths from a stable base directory.

Line 58 currently uses new File(filePath), which is interpreted relative to the current working directory. That can make this test fail in environments where user.dir differs from repo root. Resolve relative paths against the resolved CSV location instead.

Proposed path-resolution fix
         assertTrue(Files.exists(csvPath), "expectedIssues.csv not found at " + csvPath.toAbsolutePath());
+        Path repoRoot = csvPath.toAbsolutePath().normalize().getParent().getParent().getParent();

         try (BufferedReader br = new BufferedReader(new FileReader(csvPath.toFile()))) {
@@
-                File file = new File(filePath);
-                assertTrue(file.exists(), "Source file not found: " + filePath + " (referenced at CSV line " + csvLineNumber + ")");
+                Path sourcePath = Paths.get(filePath);
+                if (!sourcePath.isAbsolute()) {
+                    sourcePath = repoRoot.resolve(sourcePath).normalize();
+                }
+                File file = sourcePath.toFile();
+                assertTrue(
+                        file.exists(),
+                        "Source file not found: "
+                                + sourcePath
+                                + " (referenced at CSV line "
+                                + csvLineNumber
+                                + ")");

Also applies to: 58-59

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/test/java/org/sasanlabs/service/vulnerability/sast/ExpectedIssuesCSVTest.java`
around lines 34 - 35, The test uses new File(filePath) which treats relative
file paths against the process working directory; update ExpectedIssuesCSVTest
to resolve any relative CSV-referenced paths against the CSV file's directory
instead (use csvPath.getParent() or csvPath.toAbsolutePath().getParent() as the
stable base) and construct the target path via Paths.get(baseDir.toString(),
filePath) or baseDir.resolve(filePath).toFile(); apply the same change to both
places mentioned (lines 58–59) so all file lookups use the CSV's directory as
the base.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes good gatch :')

I'm moving this PR to Draft status for now. I've noted the feedback regarding the path resolution in ExpectedIssuesCSVTest.java.

Tomorrow, I will update the logic to ensure the test is environment-agnostic.

I think i will

  • Use the absolute path of the CSV file as a stable anchor to resolve the project root.
  • Construct all source file paths using repoRoot.resolve(filePath).normalize().

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@Etoile-Bleu Sounds like a solid plan! Your two-step approach is exactly right. One small note: since the CSV lives at scanner/sast/expectedIssues.csv (three path segments deep), you'll need three .getParent() calls to reach the repo root from the resolved CSV path:

Path csvPath = Paths.get(CSV_PATH);
if (!Files.exists(csvPath)) {
    csvPath = Paths.get(System.getProperty("user.dir"), CSV_PATH);
}
assertTrue(Files.exists(csvPath), "expectedIssues.csv not found at " + csvPath.toAbsolutePath());

// Derive repo root: scanner/sast/expectedIssues.csv → 3 levels up
Path repoRoot = csvPath.toAbsolutePath().normalize()
        .getParent()  // scanner/sast
        .getParent()  // scanner
        .getParent(); // repo root

try (BufferedReader br = new BufferedReader(new FileReader(csvPath.toFile()))) {
    // ...
    Path sourcePath = Paths.get(filePath);
    if (!sourcePath.isAbsolute()) {
        sourcePath = repoRoot.resolve(sourcePath).normalize();
    }
    File file = sourcePath.toFile();
    assertTrue(
            file.exists(),
            "Source file not found: " + sourcePath + " (referenced at CSV line " + csvLineNumber + ")");
    // ...
}

This way, no matter what user.dir is at test runtime (IDE, CI, Maven wrapper, etc.), paths are always resolved relative to the project root inferred from the CSV's own location. Ready to re-review whenever you push the update! 🚀

@Etoile-Bleu Etoile-Bleu marked this pull request as draft May 9, 2026 02:20
@Etoile-Bleu
Copy link
Copy Markdown
Contributor Author

Hi Karan and the SasanLabs team,

Following the discussion about the maintenance of expectedIssues.csv, I have performed a rigorous cleanup of the file to ensure it remains a high-quality ground truth for SAST scanners.

You will notice that the file is now more concise. I think it's betterto improve the accuracy of the baseline. Here is a summary of the technical rationale behind this reduction:

  • I removed entries that did not point to actual vulnerabilities. A SAST scanner flagging these would technically produce a false positive:
  • Annotations and Metadata: Removed lines pointing to @AttackVector or method descriptions.
  • Structural Code: Removed lines pointing to try { blocks (e.g., ErrorBasedSQLInjectionVulnerability:218) or closing brackets } (e.g., PathTraversalVulnerability:65).
  • Correction of Refactored Files
    Several files (like UrlParamBasedImgTagAttrInjection.java) no longer exist in the current branch. I have mapped these entries to their current implementations, such as XSSInImgTagAttribute.java, ensuring the levels (1-5) remain consistent.

  • Precise Sink Targeting
    I updated line numbers to point exactly to the Sink (the dangerous instruction, e.g., the ProcessBuilder call) rather than the surrounding setup code. This makes the CSV a much better benchmark for tool comparison.


My solution:

To solve the maintenance struggle you mentioned, I have integrated a JUnit test (ExpectedIssuesCSVTest.java).

  • It automatically validates that every entry in the CSV points to an existing file and a valid line number.
  • From now on, any refactoring that moves a vulnerable line without updating the CSV will trigger a build failure, preventing the data from getting outdated again.

Question for the maintainers

My audit was based on the current CSV in the workspace. However, I noticed that files like BlindSQLInjectionVulnerability.java and UnionBasedSQLInjectionVulnerability.java were missing from the original list.

How would you like me to proceed?

  1. Would you like me to manually add these missing vulnerabilities (with their corrected sinks) to the CSV?
  2. Or should we stick to this refined version of existing entries first to stabilize the current baseline?

@preetkaran20
Copy link
Copy Markdown
Member

Hi Karan and the SasanLabs team,

Following the discussion about the maintenance of expectedIssues.csv, I have performed a rigorous cleanup of the file to ensure it remains a high-quality ground truth for SAST scanners.

You will notice that the file is now more concise. I think it's betterto improve the accuracy of the baseline. Here is a summary of the technical rationale behind this reduction:

  • I removed entries that did not point to actual vulnerabilities. A SAST scanner flagging these would technically produce a false positive:

  • Annotations and Metadata: Removed lines pointing to @AttackVector or method descriptions.

  • Structural Code: Removed lines pointing to try { blocks (e.g., ErrorBasedSQLInjectionVulnerability:218) or closing brackets } (e.g., PathTraversalVulnerability:65).

  • Correction of Refactored Files
    Several files (like UrlParamBasedImgTagAttrInjection.java) no longer exist in the current branch. I have mapped these entries to their current implementations, such as XSSInImgTagAttribute.java, ensuring the levels (1-5) remain consistent.

  • Precise Sink Targeting
    I updated line numbers to point exactly to the Sink (the dangerous instruction, e.g., the ProcessBuilder call) rather than the surrounding setup code. This makes the CSV a much better benchmark for tool comparison.

My solution:

To solve the maintenance struggle you mentioned, I have integrated a JUnit test (ExpectedIssuesCSVTest.java).

  • It automatically validates that every entry in the CSV points to an existing file and a valid line number.
  • From now on, any refactoring that moves a vulnerable line without updating the CSV will trigger a build failure, preventing the data from getting outdated again.

Question for the maintainers

My audit was based on the current CSV in the workspace. However, I noticed that files like BlindSQLInjectionVulnerability.java and UnionBasedSQLInjectionVulnerability.java were missing from the original list.

How would you like me to proceed?

  1. Would you like me to manually add these missing vulnerabilities (with their corrected sinks) to the CSV?
  2. Or should we stick to this refined version of existing entries first to stabilize the current baseline?

If you can add missing vulnerabilities that is always great and we want to have that. The CSV is outdated due to addition or updation of code. it would be great to update the CSV with newer line numbers.

if (csvLineNumber == 1) continue;
if (line.trim().isEmpty()) continue;

String[] parts = line.split(",");
Copy link
Copy Markdown
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 library for this.

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.

3 participants