Skip to content

Enhanced VulnerableApp-facade to support Card generation and toggle b…#111

Merged
preetkaran20 merged 7 commits into
SasanLabs:mainfrom
saurabhkushwaha438:main
May 12, 2026
Merged

Enhanced VulnerableApp-facade to support Card generation and toggle b…#111
preetkaran20 merged 7 commits into
SasanLabs:mainfrom
saurabhkushwaha438:main

Conversation

@saurabhkushwaha438
Copy link
Copy Markdown
Contributor

@saurabhkushwaha438 saurabhkushwaha438 commented Apr 22, 2026

✨ Enhancing VulnerableApp-Facade: Card Generation & Mode Toggle (Scanner ↔ Challenge)

📌 Overview

This PR enhances the VulnerableApp-Facade by introducing:

  • Dynamic card generation for improved UI representation
  • A toggle mechanism to switch between Scanner mode and Challenge mode

These changes improve usability and make it easier for users to interact with different application flows.


🚀 Key Changes

🔹 Card Generation

  • Implemented dynamic rendering of cards based on available data
  • Improved UI structure for better readability and interaction
  • Ensures scalability for future additions

🔹 Mode Toggle (Scanner ↔ Challenge)

  • Added a toggle button to switch between:

    • Scanner Mode
    • Challenge Mode
  • Ensures smooth transition without breaking existing functionality

  • Maintains state consistency across views


🧪 Testing

  • ✅ Verified functionality using local Docker setup

    docker-compose -f docker-compose.without_llm.yml up --build
  • ✅ Tested both modes:

    • Scanner mode rendering
    • Challenge mode rendering
  • ✅ Confirmed UI updates reflect correctly in:

    • http://localhost (Docker)
    • http://localhost:3000 (dev server)
  • ✅ Ensured no regression in existing features


⚙️ Additional Notes

  • No breaking changes introduced
  • Changes are limited to frontend (facade-app)
  • Compatible with existing Docker and build setup

Screenshot 2026-04-22 233920 Screenshot 2026-04-22 233932 Screenshot 2026-04-22 233956

🙌 Summary

This PR improves the usability and flexibility of the VulnerableApp-Facade by enabling dynamic UI rendering and seamless mode switching, aligning with the goals of issue #570.


Closes #570

Summary by CodeRabbit

  • New Features

    • Challenge Mode with interactive challenge cards, progressive hint reveal, and optional payload reveal
    • Header mode toggle to switch between Scanner and Challenge modes; toggle disables when no challenges are available
    • Added mock vulnerability payloads for testing/practice
  • Style

    • New styles for Challenge Card UI and header mode toggle
  • Chores

    • Added DOM sanitization dependency for safe HTML rendering
  • Tests

    • Updated header tests to account for mode flag and simplified assertions

Review Change Stack

@saurabhkushwaha438
Copy link
Copy Markdown
Contributor Author

i retest in local environment with some change . it still didnt pass header test because of new ui change ,where drop down menu is inside toggle button

@saurabhkushwaha438
Copy link
Copy Markdown
Contributor Author

Hi maintainers,
All tests are passing locally and snapshots have been updated.
Please approve the workflow so CI checks can run.

Thanks!

@saurabhkushwaha438
Copy link
Copy Markdown
Contributor Author

Hi maintainers, just a gentle follow-up on this PR.
All checks are passing and changes are ready for review.
Would appreciate your feedback. Thanks!

Comment thread facade-app/src/Components/ChallengeCard.tsx
export const ChallengeCard: React.FC<ChallengeCardProps> = ({
challenge,
challengeNumber,
}) => {
Copy link
Copy Markdown
Member

@preetkaran20 preetkaran20 Apr 29, 2026

Choose a reason for hiding this comment

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

Payload is currently revealed automatically once all hints are shown. From a UX perspective, it would be better to gate this behind an explicit user action.

I think we should add a “Reveal Payload” button so the user intentionally chooses to view the final answer. This preserves the challenge experience and improves engagement.

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.

hey i want to know which payload you taking about like in challenge mode or scanner mode , where payload is with hints

Copy link
Copy Markdown
Member

@preetkaran20 preetkaran20 May 9, 2026

Choose a reason for hiding this comment

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

in challenge mode. example:
image
First hint click
image
Second hint click
image

After second hint click, user should be able to see show payload button and after clicking that button, then only payload should be shown


{hints.length > 0 && (
<div
style={{
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.

There is extensive use of inline styles within the component, which makes it harder to maintain and reuse. Can you please move styles into CSS classes instead of inline style props

Copy link
Copy Markdown
Member

@preetkaran20 preetkaran20 left a comment

Choose a reason for hiding this comment

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

Overall Looks good to me. Thanks for the PR. Added a few comments.

Thanks,
Karan

Comment thread facade-app/src/Components/ChallengeCard.tsx
Comment thread facade-app/src/Components/ChallengeCard.tsx
@saurabhkushwaha438
Copy link
Copy Markdown
Contributor Author

bandicam.2026-05-10.12-17-54-219.mp4

hope these changes is fine and i also brought show payload button , removed inline css and converted the fixed pixel values to rem units

@preetkaran20
Copy link
Copy Markdown
Member

bandicam.2026-05-10.12-17-54-219.mp4
hope these changes is fine and i also brought show payload button , removed inline css and converted the fixed pixel values to rem units

Yes this looks good to me. I think you have not pushed the changes. Also can you put the same icon 🧩?

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 11, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: c1a09a4c-f5a7-4f0e-b83a-1d76771390f9

📥 Commits

Reviewing files that changed from the base of the PR and between a9743ba and 32d81ae.

📒 Files selected for processing (3)
  • facade-app/src/App.tsx
  • facade-app/src/Components/ChallengeCard.tsx
  • facade-app/src/interface/State.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • facade-app/src/Components/ChallengeCard.tsx
  • facade-app/src/App.tsx

📝 Walkthrough

Walkthrough

Adds a Challenge Mode: new challenge types and global flag, a ChallengeCard component with hint/payload reveal, Content and Header UI wiring for challenge vs scanner modes, mock challenge data, styles, tests, and small config updates.

Changes

Challenge Mode Feature

Layer / File(s) Summary
State Schema & Types
facade-app/src/interface/State.tsx
Introduces ChallengeHint, Payload, and Challenge types. Extends LevelInformation with optional challengeCards and challenge. Adds isChallengeModeEnabled to GlobalState and AppMode enum.
ChallengeCard Component
facade-app/src/Components/ChallengeCard.tsx
New React component that displays challenge text, reveals hints incrementally via controls, sanitizes and renders hint HTML with DOMPurify, and shows a payload after hints are revealed. Manages local reveal state.
Content Component Integration
facade-app/src/Components/Content.tsx
Adds ContentState for description management. Replaces DOM-based description injection with state-driven rendering. Computes challenge availability and conditionally renders Challenge Mode UI with challenge cards in a two-column layout, or falls back to scanner-mode vulnerability description.
Header Mode Toggle
facade-app/src/Components/Header.tsx
Adds isChallengeAvailable() helper to check for challenge cards in the active level. Implements dual-mode buttons (Challenge/Scanner) that toggle isChallengeModeEnabled in global state and disables Challenge when unavailable.
Application State
facade-app/src/App.tsx
Adds isChallengeModeEnabled: false to initial state. Includes a commented-out mock endpoint option for local testing.
Mock Data
facade-app/public/mockResponse.json
Provides mock vulnerability definitions for AuthenticationVulnerability and ClickjackingVulnerability with multi-level challenges, ordered hints, exploit payloads, and resource URIs for demonstration and testing.
Styling & Configuration
facade-app/src/styles/ChallengeCard.css, facade-app/src/styles/Header.css, facade-app/src/react-app-env.d.ts, facade-app/tsconfig.json, facade-app/package.json
Adds styling for ChallengeCard and header mode toggle, declares *.css as an ambient module, minor tsconfig formatting change, adds dompurify dependency, and refines jest coverage include/exclude patterns.
Test Update
facade-app/src/test/Header.test.tsx
Updates test fixtures to include isChallengeModeEnabled, simplifies some render usage, and removes a few icon assertions.

Sequence Diagram

sequenceDiagram
  participant User
  participant Header
  participant App as GlobalState
  participant Content
  participant ChallengeCard
  
  User->>Header: Click "Challenge Mode" button
  Header->>Header: Check isChallengeAvailable()
  alt Challenge Mode Available
    Header->>App: setGlobalState(isChallengeModeEnabled: true)
    App-->>Content: State update
    Content->>Content: Render challenge cards
    Content->>ChallengeCard: Pass challenge data
    ChallengeCard-->>User: Display challenge text and hints
  else Challenge Mode Unavailable
    Header-->>User: Challenge button disabled
    User->>Header: Click "Scanner Mode" button
    Header->>App: setGlobalState(isChallengeModeEnabled: false)
    App-->>Content: State update
    Content->>Content: Render vulnerability description
    Content-->>User: Display scanner UI
  end
  
  User->>ChallengeCard: Click "Show Hint >"
  ChallengeCard->>ChallengeCard: Increment revealedHints
  ChallengeCard-->>User: Display next hint
  
  User->>ChallengeCard: Click "Reveal Payload"
  ChallengeCard->>ChallengeCard: Toggle isPayloadRevealed
  ChallengeCard-->>User: Show exploit payload
Loading

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

Poem

🐰 A rabbit hops where challenges hide,

Hints unfurl in gentle stride,
Toggle modes and chase the clue,
Reveal the payload when you're through,
Practice, learn, then hop with pride.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title is truncated/incomplete ('Enhanced VulnerableApp-facade to support Card generation and toggle b…') and does not fully convey the main change, making it vague about what toggle feature is being added. Complete the title to clearly specify the toggle feature, e.g., 'Enhanced VulnerableApp-facade to support Challenge Cards and Scanner/Challenge Mode toggle' or similar.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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

Warning

Review ran into problems

🔥 Problems

Git: Failed to clone repository. Please run the @coderabbitai full review command to re-trigger a full review. If the issue persists, set path_filters to include or exclude specific files.

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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.

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: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
facade-app/src/Components/Content.tsx (1)

54-57: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Guard against stale async responses when switching levels quickly.

The callback uses mutable this.selectedLevel; out-of-order responses can inject outdated HTML/resources into the current view.

🔄 Suggested fix with request token check
 export class Content extends React.Component<Props, ContentState> {
   selectedLevel?: LevelInformation;
+  private contentRequestToken = 0;

 ...
           if (selectedLevel) {
             this.selectedLevel = selectedLevel;
+            const token = ++this.contentRequestToken;
             getResource(
               selectedLevel.resourceInformation.htmlResource.uri,
-              this._setLocalState.bind(this),
+              (resp) => this._setLocalState(resp, token, selectedLevel),
               false
             );
           }

-  _setLocalState(
-    vulnerabilityDefinitionResponse: VulnerabilityDefinitionResponse
-  ) {
+  _setLocalState(
+    vulnerabilityDefinitionResponse: VulnerabilityDefinitionResponse,
+    token: number,
+    levelForResponse: LevelInformation
+  ) {
+    if (token !== this.contentRequestToken) return;
     if (vulnerabilityDefinitionResponse.data) {
       manipulateDOM("__content__", vulnerabilityDefinitionResponse.data);
-      if (this.selectedLevel) {
-        appendStaticResourcesToDocument(this.selectedLevel);
-      }
+      appendStaticResourcesToDocument(levelForResponse);
     }
   }

Also applies to: 65-73

🤖 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 `@facade-app/src/Components/Content.tsx` around lines 54 - 57, The async
getResource callbacks can apply stale data because they reference mutable
this.selectedLevel; capture a request-specific token or the selected level
id/uri before calling getResource (e.g., const reqId = this._currentRequestId++
or const requestedUri = selectedLevel.resourceInformation.htmlResource.uri) and
then, inside the callback that calls this._setLocalState, check that the token
or uri still matches the current this.selectedLevel (or this._currentRequestId)
and abort if it does not; apply the same request-token/uri-compare pattern for
both getResource usages so only the latest response updates _setLocalState.
🧹 Nitpick comments (1)
facade-app/src/interface/State.tsx (1)

65-67: ⚡ Quick win

Document the relationship between challengeCards and challenge.

The presence of both challengeCards?: Array<Challenge> and challenge?: Challenge without documentation creates ambiguity. Add JSDoc comments explaining:

  • When each field should be used
  • Whether they're mutually exclusive
  • The fallback behavior (as implemented in Content.tsx)

This will help future maintainers understand the design intent.

📚 Suggested documentation
   resourceInformation: ResourceInformation;
 
-  // Challenge mode
+  /**
+   * Challenge mode data. If both fields are present, challengeCards takes precedence.
+   * - challengeCards: Array of multiple challenge scenarios for this level
+   * - challenge: Single challenge (legacy format or simple use case)
+   */
   challengeCards?: Array<Challenge>;
   challenge?: Challenge;
 }
🤖 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 `@facade-app/src/interface/State.tsx` around lines 65 - 67, Add JSDoc comments
above the State interface properties challengeCards and challenge describing
when to use each: explain that challengeCards?: Array<Challenge> is used for
"challenge mode" multi-card displays, challenge?: Challenge is used when a
single active challenge is selected, whether they are mutually exclusive (e.g.,
only one should be populated at a time) and which one is the fallback (state
should use challenge if challengeCards is empty or undefined, matching the
fallback logic in Content.tsx). Reference the Content.tsx behavior in the
comment so maintainers can trace the implemented fallback and any precedence
rules.
🤖 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 `@facade-app/public/mockResponse.json`:
- Line 6: The "description" field in facade-app/public/mockResponse.json
currently contains placeholder/gibberish; replace its value with a concise,
user-facing sentence that accurately describes the item or feature represented
by this mock (update the "description" JSON property), e.g., a short meaningful
copy that fits the UI context and snapshot tests; ensure the new text uses
proper spelling and punctuation and remains within expected length constraints
for the UI component.
- Line 148: The JSON "description" string contains HTML anchor tags with
target="_blank" which expose window.opener; update each anchor in the
"description" field (the string in mockResponse.json) to include rel="noopener
noreferrer" alongside target="_blank" (e.g., change <a href="..."
target="_blank"> to <a href="..." target="_blank" rel="noopener noreferrer">) so
all external links are safe when rendered.

In `@facade-app/src/Components/ChallengeCard.tsx`:
- Around line 74-76: The hint HTML is rendered directly via
dangerouslySetInnerHTML with hint.text in the ChallengeCard component; sanitize
it first using DOMPurify to prevent XSS. Add DOMPurify as a dependency, import
it in ChallengeCard.tsx, run DOMPurify.sanitize(hint.text) and pass the
sanitized string to dangerouslySetInnerHTML instead of raw hint.text; apply the
same sanitization to the similar dangerouslySetInnerHTML usages in Content.tsx
to cover both instances. Ensure imports/reference to DOMPurify and variable
names (hint, hint.text, dangerouslySetInnerHTML) are updated accordingly.

In `@facade-app/src/Components/Header.tsx`:
- Around line 198-207: The wrap of RSuite interactive items with anchor tags
breaks keyboard navigation; remove the surrounding <a> elements and instead use
RSuite components' routing props: for RSuiteNav.Item set its href prop directly
(e.g., RSuiteNav.Item href="/scanner/..."), and for RSuiteDropDown.Item use the
as prop with your router Link component (e.g., RSuiteDropDown.Item as={Link}
href="/scanner/...")—import the appropriate Link from Next.js or React Router
and apply the same pattern to the other instances of Nav.Item and Dropdown.Item
mentioned in the review.

In `@facade-app/src/interface/State.tsx`:
- Around line 14-20: Remove the temporary development comment above the
ChallengeHint interface in State.tsx (the line containing "NEW - matches your
JSON") and either delete it or replace it with a concise JSDoc-style comment
that describes the purpose and usage of the ChallengeHint interface (fields
order: number, text: string) so the ChallengeHint export has proper
documentation rather than a dev note.
- Around line 44-51: Remove the development artifacts from the Challenge
interface comment and inline field note: delete the "(UPDATED)" text in the
JSDoc header above the Challenge interface and remove or replace the "✅ updated"
inline comment on the hints field; if you need to preserve context, convert them
into a concise JSDoc description for the interface or the hints property (e.g.,
document that hints is optional and an array of ChallengeHint) so the symbols
Challenge, challengeText, hints, and payload remain properly documented without
emoji/dev notes.

---

Outside diff comments:
In `@facade-app/src/Components/Content.tsx`:
- Around line 54-57: The async getResource callbacks can apply stale data
because they reference mutable this.selectedLevel; capture a request-specific
token or the selected level id/uri before calling getResource (e.g., const reqId
= this._currentRequestId++ or const requestedUri =
selectedLevel.resourceInformation.htmlResource.uri) and then, inside the
callback that calls this._setLocalState, check that the token or uri still
matches the current this.selectedLevel (or this._currentRequestId) and abort if
it does not; apply the same request-token/uri-compare pattern for both
getResource usages so only the latest response updates _setLocalState.

---

Nitpick comments:
In `@facade-app/src/interface/State.tsx`:
- Around line 65-67: Add JSDoc comments above the State interface properties
challengeCards and challenge describing when to use each: explain that
challengeCards?: Array<Challenge> is used for "challenge mode" multi-card
displays, challenge?: Challenge is used when a single active challenge is
selected, whether they are mutually exclusive (e.g., only one should be
populated at a time) and which one is the fallback (state should use challenge
if challengeCards is empty or undefined, matching the fallback logic in
Content.tsx). Reference the Content.tsx behavior in the comment so maintainers
can trace the implemented fallback and any precedence rules.
🪄 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: 3d2a44ee-320c-41dc-8697-70f96839b2c9

📥 Commits

Reviewing files that changed from the base of the PR and between 94464f8 and 515cf55.

⛔ Files ignored due to path filters (7)
  • facade-app/package-lock.json is excluded by !**/package-lock.json
  • facade-app/src/test/__snapshots__/App.test.tsx.snap is excluded by !**/*.snap
  • facade-app/src/test/__snapshots__/CommandInjection.test.tsx.snap is excluded by !**/*.snap
  • facade-app/src/test/__snapshots__/Footer.test.tsx.snap is excluded by !**/*.snap
  • facade-app/src/test/__snapshots__/Header.test.tsx.snap is excluded by !**/*.snap
  • facade-app/src/test/__snapshots__/JwtVulnerability.test.tsx.snap is excluded by !**/*.snap
  • facade-app/src/test/__snapshots__/UnrestrictedFileUpload.test.tsx.snap is excluded by !**/*.snap
📒 Files selected for processing (10)
  • facade-app/public/mockResponse.json
  • facade-app/src/App.tsx
  • facade-app/src/Components/ChallengeCard.tsx
  • facade-app/src/Components/Content.tsx
  • facade-app/src/Components/Header.tsx
  • facade-app/src/interface/State.tsx
  • facade-app/src/react-app-env.d.ts
  • facade-app/src/styles/ChallengeCard.css
  • facade-app/src/test/Header.test.tsx
  • facade-app/tsconfig.json

Comment thread facade-app/public/mockResponse.json Outdated
{
"name": "AuthenticationVulnerability",
"id": "AuthenticationVulnerability",
"description": "hi bro ia ma sfasdfasdffal;sdkf;klasdfjldsfkdfjdsalkfjdfjdfldsfjdlflajdsfkdfjkd",
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Replace placeholder/gibberish description with meaningful copy.

This value appears user-facing and currently reads as test noise, which will hurt UI quality and snapshots.

🤖 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 `@facade-app/public/mockResponse.json` at line 6, The "description" field in
facade-app/public/mockResponse.json currently contains placeholder/gibberish;
replace its value with a concise, user-facing sentence that accurately describes
the item or feature represented by this mock (update the "description" JSON
property), e.g., a short meaningful copy that fits the UI context and snapshot
tests; ensure the new text uses proper spelling and punctuation and remains
within expected length constraints for the UI component.

Comment thread facade-app/public/mockResponse.json
Comment on lines +74 to +76
key={hIndex}
dangerouslySetInnerHTML={{ __html: hint.text }}
className="hint-list-item"
Copy link
Copy Markdown

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

🧩 Analysis chain

🏁 Script executed:

find . -name "ChallengeCard.tsx" -type f

Repository: SasanLabs/VulnerableApp-facade

Length of output: 120


🏁 Script executed:

rg "dangerouslySetInnerHTML" --type tsx --type ts -n

Repository: SasanLabs/VulnerableApp-facade

Length of output: 102


🏁 Script executed:

rg "DOMPurify" --type tsx --type ts --type json -n

Repository: SasanLabs/VulnerableApp-facade

Length of output: 102


🏁 Script executed:

cat -n ./facade-app/src/Components/ChallengeCard.tsx | head -100

Repository: SasanLabs/VulnerableApp-facade

Length of output: 3794


🏁 Script executed:

rg "dangerouslySetInnerHTML" --type js -n

Repository: SasanLabs/VulnerableApp-facade

Length of output: 56


🏁 Script executed:

rg "DOMPurify" -n

Repository: SasanLabs/VulnerableApp-facade

Length of output: 56


🏁 Script executed:

rg "dangerouslySetInnerHTML" -n

Repository: SasanLabs/VulnerableApp-facade

Length of output: 379


🏁 Script executed:

cat -n ./facade-app/src/Components/Content.tsx | grep -A 2 -B 2 "dangerouslySetInnerHTML"

Repository: SasanLabs/VulnerableApp-facade

Length of output: 561


🏁 Script executed:

rg "hints" facade-app/src/Components/ChallengeCard.tsx -A 3 -B 1

Repository: SasanLabs/VulnerableApp-facade

Length of output: 1493


🏁 Script executed:

rg "hintCards" -n --type js

Repository: SasanLabs/VulnerableApp-facade

Length of output: 56


🏁 Script executed:

grep -r "sanitize\|escape\|htmlspecialchars" facade-app/src --include="*.ts" --include="*.tsx" -i

Repository: SasanLabs/VulnerableApp-facade

Length of output: 591


🏁 Script executed:

cat facade-app/package.json | grep -A 20 "dependencies"

Repository: SasanLabs/VulnerableApp-facade

Length of output: 707


Sanitize hint HTML before rendering to prevent XSS.

hint.text is injected as raw HTML without sanitization and should be escaped. The hints data comes from challenge.hints or the fallback challenge.hintCards source.

Add DOMPurify to dependencies and sanitize before rendering:

Suggested fix
+ import DOMPurify from "dompurify";

...
- <li
-   key={hIndex}
-   dangerouslySetInnerHTML={{ __html: hint.text }}
-   className="hint-list-item"
- />
+ <li
+   key={hIndex}
+   dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(hint.text) }}
+   className="hint-list-item"
+ />

Note: Similar unsanitized dangerouslySetInnerHTML patterns exist in Content.tsx (lines 128 and 221).

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
key={hIndex}
dangerouslySetInnerHTML={{ __html: hint.text }}
className="hint-list-item"
key={hIndex}
dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(hint.text) }}
className="hint-list-item"
🧰 Tools
🪛 ast-grep (0.42.1)

[warning] 74-74: Usage of dangerouslySetInnerHTML detected. This bypasses React's built-in XSS protection. Always sanitize HTML content using libraries like DOMPurify before injecting it into the DOM to prevent XSS attacks.
Context: dangerouslySetInnerHTML
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml
- https://cwe.mitre.org/data/definitions/79.html

(react-unsafe-html-injection)

🤖 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 `@facade-app/src/Components/ChallengeCard.tsx` around lines 74 - 76, The hint
HTML is rendered directly via dangerouslySetInnerHTML with hint.text in the
ChallengeCard component; sanitize it first using DOMPurify to prevent XSS. Add
DOMPurify as a dependency, import it in ChallengeCard.tsx, run
DOMPurify.sanitize(hint.text) and pass the sanitized string to
dangerouslySetInnerHTML instead of raw hint.text; apply the same sanitization to
the similar dangerouslySetInnerHTML usages in Content.tsx to cover both
instances. Ensure imports/reference to DOMPurify and variable names (hint,
hint.text, dangerouslySetInnerHTML) are updated accordingly.

Comment thread facade-app/src/Components/Header.tsx Outdated
Comment on lines +14 to +20
/**
* Challenge Mode Hint (NEW - matches your JSON)
*/
export interface ChallengeHint {
order: number;
text: string;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Remove development comments before merging.

The comment "NEW - matches your JSON" appears to be a temporary development note. Replace it with proper documentation explaining the purpose and usage of ChallengeHint, or remove it entirely.

📝 Suggested documentation improvement
 /**
- * Challenge Mode Hint (NEW - matches your JSON)
+ * Hint for Challenge Mode with sequential ordering.
+ * Used to progressively guide users toward vulnerability exploitation.
  */
 export interface ChallengeHint {
   order: number;
   text: string;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/**
* Challenge Mode Hint (NEW - matches your JSON)
*/
export interface ChallengeHint {
order: number;
text: string;
}
/**
* Hint for Challenge Mode with sequential ordering.
* Used to progressively guide users toward vulnerability exploitation.
*/
export interface ChallengeHint {
order: number;
text: string;
}
🤖 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 `@facade-app/src/interface/State.tsx` around lines 14 - 20, Remove the
temporary development comment above the ChallengeHint interface in State.tsx
(the line containing "NEW - matches your JSON") and either delete it or replace
it with a concise JSDoc-style comment that describes the purpose and usage of
the ChallengeHint interface (fields order: number, text: string) so the
ChallengeHint export has proper documentation rather than a dev note.

Comment on lines +44 to +51
/**
* Challenge Mode Structure (UPDATED)
*/
export interface Challenge {
challengeText: string;
hints?: Array<ChallengeHint>; // ✅ updated
payload?: Payload;
}
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot May 11, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Clean up development artifacts.

Lines 45 and 49 contain development notes ("(UPDATED)" and "✅ updated") that should be removed or converted to proper documentation before merging.

📝 Suggested cleanup
 /**
- * Challenge Mode Structure (UPDATED)
+ * Challenge Mode structure containing the challenge text, progressive hints,
+ * and an optional payload for the solution.
  */
 export interface Challenge {
   challengeText: string;
-  hints?: Array<ChallengeHint>; // ✅ updated
+  hints?: Array<ChallengeHint>;
   payload?: Payload;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/**
* Challenge Mode Structure (UPDATED)
*/
export interface Challenge {
challengeText: string;
hints?: Array<ChallengeHint>; // ✅ updated
payload?: Payload;
}
/**
* Challenge Mode structure containing the challenge text, progressive hints,
* and an optional payload for the solution.
*/
export interface Challenge {
challengeText: string;
hints?: Array<ChallengeHint>;
payload?: Payload;
}
🤖 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 `@facade-app/src/interface/State.tsx` around lines 44 - 51, Remove the
development artifacts from the Challenge interface comment and inline field
note: delete the "(UPDATED)" text in the JSDoc header above the Challenge
interface and remove or replace the "✅ updated" inline comment on the hints
field; if you need to preserve context, convert them into a concise JSDoc
description for the interface or the hints property (e.g., document that hints
is optional and an array of ChallengeHint) so the symbols Challenge,
challengeText, hints, and payload remain properly documented without emoji/dev
notes.

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.

please fix this.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@preetkaran20, sure! Here's the plan to clean up those development artifacts from facade-app/src/interface/State.tsx:

  • Remove (UPDATED) from the Challenge interface JSDoc and replace it with a meaningful description
  • Remove the // ✅ updated inline comment from the hints field

Failed to handle agent chat message. Please try again.

@saurabhkushwaha438
Copy link
Copy Markdown
Contributor Author

hey maintainer this time i checked all conditions such as-
1 . it pass all test locally and ran npm run pretty before committing
2. remove inline css
3. user scalable unit like rem
4. used flex box for ordering challengecard
5. added show payload button
6. fixed major bug suggested by coderabbit

Please approve the workflow so CI checks can run.

Thanks!

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: 1

🤖 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 `@facade-app/src/Components/ChallengeCard.tsx`:
- Around line 42-50: The fallback for hints uses (challenge as any).hintCards
with no validation and can throw if hintCards or hc.hints are not arrays; update
the logic around the hints assignment so you first check
Array.isArray((challenge as any).hintCards), then iterate only over items where
hc is an object and Array.isArray(hc.hints), use a safe flatMap/filter to
collect strings (coerce or skip non-strings) and map them to { order, text }
entries; reference the existing hints variable, the hintCards property, and the
flatMap usage when replacing the current unguarded fallback.
🪄 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: a60111a7-b457-4eef-aa98-57bd00459383

📥 Commits

Reviewing files that changed from the base of the PR and between 515cf55 and 5fa65c6.

⛔ Files ignored due to path filters (3)
  • facade-app/package-lock.json is excluded by !**/package-lock.json
  • facade-app/src/test/__snapshots__/App.test.tsx.snap is excluded by !**/*.snap
  • facade-app/src/test/__snapshots__/Header.test.tsx.snap is excluded by !**/*.snap
📒 Files selected for processing (6)
  • facade-app/package.json
  • facade-app/public/mockResponse.json
  • facade-app/src/App.tsx
  • facade-app/src/Components/ChallengeCard.tsx
  • facade-app/src/Components/Header.tsx
  • facade-app/src/test/Header.test.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
  • facade-app/public/mockResponse.json
  • facade-app/src/Components/Header.tsx
  • facade-app/src/App.tsx

Comment thread facade-app/src/Components/ChallengeCard.tsx
Comment thread facade-app/src/Components/ChallengeCard.tsx
Copy link
Copy Markdown
Member

@preetkaran20 preetkaran20 left a comment

Choose a reason for hiding this comment

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

Overall looks good to me. please fix small cosmetic changes and we are good to merge it.

Comment on lines +44 to +51
/**
* Challenge Mode Structure (UPDATED)
*/
export interface Challenge {
challengeText: string;
hints?: Array<ChallengeHint>; // ✅ updated
payload?: Payload;
}
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.

please fix this.

Comment thread facade-app/src/Components/Header.tsx Outdated

<RSuiteNav pullRight>
<RSuiteNav.Item style={{ padding: "0 5px" }}>
<div
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.

can we avoid this inline styling?

Comment thread facade-app/src/Components/Header.tsx Outdated

const effectiveMode =
globalState.isChallengeModeEnabled && !isChallengeDisabled
? "challenge"
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.

Better to create an Enum for effectiveMode such that we don't have to do string comparison


if (!applicationData) return false;

const app = applicationData.find(
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.

we have an object defined for ApplicationState, can you please use that?

Comment thread facade-app/src/Components/ChallengeCard.tsx
@codecov
Copy link
Copy Markdown

codecov Bot commented May 12, 2026

Codecov Report

❌ Patch coverage is 45.37037% with 59 lines in your changes missing coverage. Please review.
✅ Project coverage is 70.16%. Comparing base (977e387) to head (a9743ba).
⚠️ Report is 3 commits behind head on main.

Files with missing lines Patch % Lines
facade-app/src/Components/ChallengeCard.tsx 2.27% 43 Missing ⚠️
facade-app/src/Components/Header.tsx 75.00% 8 Missing and 2 partials ⚠️
facade-app/src/Components/Content.tsx 75.00% 6 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##             main     #111       +/-   ##
===========================================
- Coverage   86.39%   70.16%   -16.23%     
===========================================
  Files           9       10        +1     
  Lines         147      238       +91     
  Branches       38       95       +57     
===========================================
+ Hits          127      167       +40     
- Misses         18       69       +51     
  Partials        2        2               

☔ 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: 1

🧹 Nitpick comments (2)
facade-app/src/Components/Header.tsx (1)

107-140: ⚡ Quick win

Add accessibility attributes to mode toggle buttons.

The toggle buttons lack ARIA attributes for screen readers:

  1. Add aria-pressed to indicate toggle state
  2. Add title attribute to explain why Challenge Mode is disabled
  3. Consider adding aria-label for clarity
♿ Proposed accessibility improvements
 <button
   disabled={isChallengeDisabled}
+  aria-pressed={effectiveMode === AppMode.CHALLENGE}
+  aria-label="Switch to Challenge Mode"
+  title={isChallengeDisabled ? "No challenges available for this page" : "Switch to Challenge Mode"}
   onClick={() =>
     setGlobalState({
       ...globalState,
       isChallengeModeEnabled: true,
     })
   }
   className={`mode-button challenge-btn ${
     effectiveMode === AppMode.CHALLENGE
       ? "mode-button-active"
       : ""
   } ${isChallengeDisabled ? "mode-button-disabled" : ""}`}
 >
   Challenge Mode
 </button>

 {/* Scanner Mode */}
 <button
+  aria-pressed={effectiveMode === AppMode.SCANNER}
+  aria-label="Switch to Scanner Mode"
   onClick={() =>
     setGlobalState({
       ...globalState,
       isChallengeModeEnabled: false,
     })
   }
   className={`mode-button scanner-btn ${
     effectiveMode === AppMode.SCANNER
       ? "mode-button-active"
       : ""
   }`}
 >
   Scanner Mode
 </button>
🤖 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 `@facade-app/src/Components/Header.tsx` around lines 107 - 140, The two mode
toggle buttons (the Challenge Mode button using isChallengeDisabled and the
Scanner Mode button using setGlobalState/globalState and isChallengeModeEnabled)
need ARIA attributes: add aria-pressed to each button (true when effectiveMode
=== AppMode.CHALLENGE for the Challenge button, and true when effectiveMode ===
AppMode.SCANNER for the Scanner button), add an aria-label on each button that
clearly describes the action (e.g., "Enable Challenge Mode" / "Enable Scanner
Mode"), and add a title on the Challenge Mode button that conditionally shows
the reason it is disabled (derive the message when isChallengeDisabled is true).
Ensure these attributes are placed on the same button elements that reference
isChallengeDisabled, effectiveMode, and setGlobalState.
facade-app/src/styles/Header.css (1)

6-9: ⚡ Quick win

Consider reducing z-index: 9999 to a more standard value.

While no actual z-index conflicts exist in the codebase, a value of 9999 is excessive for a navbar element. RSuite components typically use z-index values around 1050 by default. Reducing this to 1000-1050 aligns with best practices and keeps the header above standard UI elements without being unnecessarily high.

🤖 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 `@facade-app/src/styles/Header.css` around lines 6 - 9, The .header-container
currently uses an excessive z-index of 9999; change the value to a more standard
level (e.g., 1000–1050) in the Header.css rule for .header-container so the
navbar stays above typical UI layers without using an overly large z-index;
update the z-index declaration in the .header-container selector accordingly.
🤖 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 `@facade-app/src/Components/ChallengeCard.tsx`:
- Around line 42-56: The code uses (challenge as any).hintCards; add a proper
optional type for hintCards (e.g., hintCards?: Array<{ hints: string[] }>) to
the existing Challenge interface or to ChallengeCardProps so the component sees
hintCards typed, update the ChallengeCard component prop type to use that
interface, then remove all (challenge as any) casts and access
challenge.hintCards directly in the block that builds hints (filter, flatMap,
map) so TypeScript knows hintCards is Array<{ hints: string[] }>.

---

Nitpick comments:
In `@facade-app/src/Components/Header.tsx`:
- Around line 107-140: The two mode toggle buttons (the Challenge Mode button
using isChallengeDisabled and the Scanner Mode button using
setGlobalState/globalState and isChallengeModeEnabled) need ARIA attributes: add
aria-pressed to each button (true when effectiveMode === AppMode.CHALLENGE for
the Challenge button, and true when effectiveMode === AppMode.SCANNER for the
Scanner button), add an aria-label on each button that clearly describes the
action (e.g., "Enable Challenge Mode" / "Enable Scanner Mode"), and add a title
on the Challenge Mode button that conditionally shows the reason it is disabled
(derive the message when isChallengeDisabled is true). Ensure these attributes
are placed on the same button elements that reference isChallengeDisabled,
effectiveMode, and setGlobalState.

In `@facade-app/src/styles/Header.css`:
- Around line 6-9: The .header-container currently uses an excessive z-index of
9999; change the value to a more standard level (e.g., 1000–1050) in the
Header.css rule for .header-container so the navbar stays above typical UI
layers without using an overly large z-index; update the z-index declaration in
the .header-container selector accordingly.
🪄 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: c0ff9d54-04d3-4b20-a019-ff054b97e930

📥 Commits

Reviewing files that changed from the base of the PR and between 5fa65c6 and a9743ba.

⛔ Files ignored due to path filters (2)
  • facade-app/src/test/__snapshots__/App.test.tsx.snap is excluded by !**/*.snap
  • facade-app/src/test/__snapshots__/Header.test.tsx.snap is excluded by !**/*.snap
📒 Files selected for processing (4)
  • facade-app/src/Components/ChallengeCard.tsx
  • facade-app/src/Components/Header.tsx
  • facade-app/src/interface/State.tsx
  • facade-app/src/styles/Header.css
🚧 Files skipped from review as they are similar to previous changes (1)
  • facade-app/src/interface/State.tsx

Comment thread facade-app/src/Components/ChallengeCard.tsx
@saurabhkushwaha438
Copy link
Copy Markdown
Contributor Author

hey maintainer i implemented all requested changes . please review it

Copy link
Copy Markdown
Member

@preetkaran20 preetkaran20 left a comment

Choose a reason for hiding this comment

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

LGTM, thanks a lot @saurabhkushwaha438 for such a great PR.

@preetkaran20 preetkaran20 merged commit 779ac5e into SasanLabs:main May 12, 2026
2 checks passed
@preetkaran20
Copy link
Copy Markdown
Member

🎉 Thanks for contributing @saurabhkushwaha438!

We’d love to stay in touch and grow SasanLabs 🚀
👉 Please fill this (takes 30 sec): form

Also consider ⭐ starring the repo if you like it!

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.

2 participants