Skip to content

Potential fix for code scanning alert no. 123: DOM text reinterpreted as HTML#64

Merged
Jackson57279 merged 1 commit intomainfrom
alert-autofix-123
Aug 16, 2025
Merged

Potential fix for code scanning alert no. 123: DOM text reinterpreted as HTML#64
Jackson57279 merged 1 commit intomainfrom
alert-autofix-123

Conversation

@Jackson57279
Copy link
Owner

@Jackson57279 Jackson57279 commented Aug 14, 2025

Potential fix for https://github.com/otdoges/zapdev/security/code-scanning/123

To fix the problem, we need to ensure that any user-supplied URL is both validated and sanitized before being used as an href attribute and as link text. The best way is to:

  • Sanitize the URL before rendering: Only allow URLs with http or https protocols, and ensure the string does not contain any dangerous characters or sequences.
  • For the link text, React escapes it by default, but for extra safety, we can use a component like SafeText (already imported) to render the URL.
  • For the href attribute, we should use a helper function to validate and sanitize the URL before passing it to the <a> tag. If the URL is invalid or unsafe, we can render a fallback (e.g., # or nothing).

Changes required:

  • In src/components/ChatInterface.tsx, add a helper function (e.g., getSafeUrl) to validate and sanitize the URL before rendering.
  • Use SafeText to render the link text.
  • Use the sanitized URL for the href attribute.
  • No new dependencies are needed, as all required functionality can be implemented with standard JS and existing imports.

Suggested fixes powered by Copilot Autofix. Review carefully before merging.

Summary by CodeRabbit

  • Bug Fixes

    • Website Analysis links are now validated and sanitized before opening; invalid or non-http(s) URLs no longer navigate and are safely handled.
    • Displayed URL text is safely rendered to prevent injection and visual glitches.
    • Title input now enforces a minimum length of 1 character, preventing empty titles.
  • Chores

    • Strengthened input validation and link handling to reduce the risk of malformed URLs and improve reliability.

… as HTML

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
@vercel
Copy link

vercel bot commented Aug 14, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
zapdev Ready Preview Comment Aug 14, 2025 9:55pm

@Jackson57279 Jackson57279 marked this pull request as ready for review August 14, 2025 21:54
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 14, 2025

Walkthrough

Introduces a URL sanitization helper and applies it in the Website Analysis UI to validate hrefs and safely render link text. Adds a new MIN_TITLE_LENGTH constant to input validation alongside existing limits. No changes to exported/public APIs.

Changes

Cohort / File(s) Summary
URL sanitization and UI updates
src/components/ChatInterface.tsx
Added getSafeUrl(url) to canonicalize/validate http(s) URLs; invalid or non-http(s) return '#'. Updated Website Analysis link to use sanitized href and SafeText for display. Introduced MIN_TITLE_LENGTH = 1 in validation constants.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Poem

I thump my paws: we scrub each link,
From risky schemes to safe, I wink.
A tidy title, short yet bright,
The chat now hops in safer light.
Carrot-secure, our clicks take flight—
Hippity-hop, no XSS tonight! 🥕✨

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch alert-autofix-123

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@claude
Copy link

claude bot commented Aug 14, 2025

Claude finished @otdoges's task —— View job


Code Review Complete ✅

I've thoroughly reviewed PR #64 which addresses security code scanning alert #123 about DOM text reinterpreted as HTML. Here's my comprehensive analysis:

Security Assessment ✅ STRONG

Effective XSS Protection

The fix implements a robust multi-layer security approach:

  1. URL Sanitization (getSafeUrl function, lines 52-63):

    • Validates URLs using native URL() constructor
    • Only allows http: and https: protocols
    • Returns safe fallback # for invalid URLs
    • Prevents javascript:, data:, and other dangerous protocols
  2. Content Sanitization (SafeText component):

    • Uses DOMPurify with strict configuration
    • Strips ALL HTML tags and attributes (text-only output)
    • Comprehensive XSS protection beyond basic escaping
  3. Application at Risk Point (lines 922-924):

    <a href={getSafeUrl(websiteAnalysis.url)} target="_blank" rel="noopener noreferrer">
      <SafeText text={websiteAnalysis.url} />
    </a>
    • URL is sanitized for href attribute
    • Same URL is sanitized for display text
    • Prevents both navigation and display-based attacks

Code Quality ✅ EXCELLENT

Best Practices Followed

  • Proper error handling: URL validation in try/catch
  • Secure defaults: Returns # instead of original URL on failure
  • Defense in depth: Multiple sanitization layers
  • Consistent patterns: Uses existing SafeText component throughout codebase
  • No new dependencies: Leverages existing DOMPurify integration

Clean Implementation

  • Function is pure with no side effects
  • Clear, descriptive naming (getSafeUrl)
  • Minimal and focused (11 lines)
  • Follows TypeScript best practices

Potential Issues ⚠️ MINOR

⚠️ Limited Test Coverage

  • No unit tests found for getSafeUrl function
  • No integration tests for the security fix
  • Recommendation: Add tests covering:
    describe('getSafeUrl', () => {
      it('should allow valid https URLs', () => {
        expect(getSafeUrl('https://example.com')).toBe('https://example.com/');
      });
      
      it('should block javascript: URLs', () => {
        expect(getSafeUrl('javascript:alert(1)')).toBe('#');
      });
      
      it('should handle malformed URLs', () => {
        expect(getSafeUrl('not-a-url')).toBe('#');
      });
    });

ℹ️ Minor Enhancements (Optional)

  • Could add logging for blocked URLs for security monitoring
  • Consider normalizing URLs (e.g., removing fragments/credentials)

Performance ✅ GOOD

  • Minimal performance impact
  • URL validation is fast native operation
  • DOMPurify is already loaded globally

Security Completeness ✅ COMPREHENSIVE

This fix effectively addresses the original alert by:

  1. Preventing malicious URLs in href attributes
  2. Preventing malicious content in link text
  3. Using battle-tested sanitization (DOMPurify)
  4. Following security best practices (allowlist approach)

Overall Assessment: ✅ APPROVED

Strong security fix that follows best practices. Ready to merge with minor test coverage improvement recommended.

The implementation successfully prevents DOM-based XSS through URL manipulation while maintaining clean, maintainable code.


Copy link
Contributor

@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

🔭 Outside diff range comments (6)
src/components/ChatInterface.tsx (6)

850-852: Sanitize 3rd‑party search content with SafeText

Titles and descriptions come from external search and must be treated as untrusted. Wrap them with SafeText.

-<h5 className="font-medium text-sm truncate">{result.title}</h5>
-<p className="text-xs text-muted-foreground line-clamp-2 mt-1">{result.description}</p>
+<h5 className="font-medium text-sm truncate"><SafeText>{result.title}</SafeText></h5>
+<p className="text-xs text-muted-foreground line-clamp-2 mt-1"><SafeText>{result.description}</SafeText></p>

852-861: Sanitize search result links: use getSafeUrl for href and SafeText for link text

This is the same attack surface as the scanner alert. Avoid inserting raw URLs; sanitize the href and escape the visible text.

-<a 
-  href={result.url} 
+<a 
+  href={getSafeUrl(result.url)} 
   target="_blank" 
   rel="noopener noreferrer"
   className="text-xs text-primary hover:underline flex items-center gap-1 mt-1"
   onClick={(e) => e.stopPropagation()}
 >
-  {result.url}
+  <SafeText>{result.url}</SafeText>
   <ExternalLink className="w-3 h-3" />
 </a>

927-931: Sanitize website analysis metadata (title/description) before rendering

These fields are also externally sourced. Wrap with SafeText to prevent XSS.

-{websiteAnalysis.title && (
-  <div><span className="font-medium">Title:</span> {websiteAnalysis.title}</div>
-)}
-{websiteAnalysis.description && (
-  <div><span className="font-medium">Description:</span> {websiteAnalysis.description}</div>
-)}
+{websiteAnalysis.title && (
+  <div><span className="font-medium">Title:</span> <SafeText>{websiteAnalysis.title}</SafeText></div>
+)}
+{websiteAnalysis.description && (
+  <div><span className="font-medium">Description:</span> <SafeText>{websiteAnalysis.description}</SafeText></div>
+)}

933-954: Sanitize other website analysis fields (technologies, layout, components)

These arrays/strings may originate from untrusted content. Escape them with SafeText.

 {websiteAnalysis.technologies && websiteAnalysis.technologies.length > 0 && (
   <div>
     <span className="font-medium">Technologies:</span>
     <div className="flex flex-wrap gap-1 mt-1">
       {websiteAnalysis.technologies.map((tech, index) => (
-        <Badge key={index} variant="secondary" className="text-xs">{tech}</Badge>
+        <Badge key={index} variant="secondary" className="text-xs"><SafeText>{tech}</SafeText></Badge>
       ))}
     </div>
   </div>
 )}
 {websiteAnalysis.layout && (
-  <div><span className="font-medium">Layout:</span> {websiteAnalysis.layout}</div>
+  <div><span className="font-medium">Layout:</span> <SafeText>{websiteAnalysis.layout}</SafeText></div>
 )}
 {websiteAnalysis.components && websiteAnalysis.components.length > 0 && (
   <div>
     <span className="font-medium">Components:</span>
     <div className="flex flex-wrap gap-1 mt-1">
       {websiteAnalysis.components.map((comp, index) => (
-        <Badge key={index} variant="outline" className="text-xs">{comp}</Badge>
+        <Badge key={index} variant="outline" className="text-xs"><SafeText>{comp}</SafeText></Badge>
       ))}
     </div>
   </div>
 )}

1008-1013: Sanitize crawled pages links and text

Crawl results are untrusted. Sanitize href and escape the text to prevent DOM text being interpreted as HTML.

-<a href={p.url} target="_blank" rel="noopener noreferrer" className="text-primary truncate">
-  {p.title || p.url}
-</a>
-<a href={p.url} target="_blank" rel="noopener noreferrer" className="text-muted-foreground">
+<a href={getSafeUrl(p.url)} target="_blank" rel="noopener noreferrer" className="text-primary truncate">
+  <SafeText>{p.title || p.url}</SafeText>
+</a>
+<a href={getSafeUrl(p.url)} target="_blank" rel="noopener noreferrer" className="text-muted-foreground">
   <ExternalLink className="w-3 h-3" />
 </a>

1-1: Sanitize unsanitized hrefs and correct SafeText usage

The audit uncovered several <a href={…}> usages that aren’t wrapped in getSafeUrl and one SafeText instance using the text prop. Please update the following:

• src/pages/Settings.tsx
– Line 569: <a href={inv.hosted_invoice_url}…>href={getSafeUrl(inv.hosted_invoice_url)}
– Line 572: <a href={inv.invoice_pdf}…>href={getSafeUrl(inv.invoice_pdf)}

• src/components/ChatInterface.tsx
– Line 923: <SafeText text={websiteAnalysis.url} />
<SafeText>{websiteAnalysis.url}</SafeText>
– Lines 1008 & 1011: <a href={p.url}…>
href={getSafeUrl(p.url)}

• src/components/E2BCodeExecution.tsx
– Line 377: <a href={artifact.url}…>
href={getSafeUrl(artifact.url)}

• src/components/AnimatedResultShowcase.tsx
– Line 129: <a href={a.url}…>
href={getSafeUrl(a.url)}

Existing usages of href={getSafeUrl(…)} (e.g. ChatInterface.tsx 922) are fine.

🧹 Nitpick comments (2)
src/components/ChatInterface.tsx (2)

52-63: Harden URL sanitizer: trim input before parsing and early-return on empty

Good approach restricting to http/https. Minor hardening: trim whitespace/newlines before parsing and bail out on empty inputs to avoid edge cases.

Consider moving this helper to a shared util (e.g., @/lib/security/url.ts) since it’s useful in multiple places in this file.

-function getSafeUrl(url: string): string {
-  try {
-    const urlObj = new URL(url);
+function getSafeUrl(url: string): string {
+  const raw = typeof url === 'string' ? url.trim() : '';
+  if (!raw) return '#';
+  try {
+    const urlObj = new URL(raw);
     if (urlObj.protocol === 'http:' || urlObj.protocol === 'https:') {
       return urlObj.toString();
     }
   } catch {
     // Invalid URL
   }
   return '#';
 }

1311-1314: Preserve message formatting per chat UI pattern

Add whitespace preservation to message content for better readability and consistency with patterns.

-<div className="text-sm leading-relaxed text-gray-100">
+<div className="text-sm leading-relaxed text-gray-100 whitespace-pre-wrap break-words">
   <SafeText>{getMessageContent(message)}</SafeText>
 </div>
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these settings in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 0675041 and 9012e7d.

📒 Files selected for processing (1)
  • src/components/ChatInterface.tsx (2 hunks)
🧰 Additional context used
📓 Path-based instructions (7)
**/{pages,components}/**/*.tsx

📄 CodeRabbit Inference Engine (.cursor/rules/authentication-patterns.mdc)

Handle all authentication states in components by showing a loading spinner when loading, a sign-in prompt when unauthenticated, and protected content when authenticated.

Files:

  • src/components/ChatInterface.tsx
**/*ChatInterface*.tsx

📄 CodeRabbit Inference Engine (.cursor/rules/chat-ui-patterns.mdc)

Chat interfaces should follow the specified component structure: state management for selectedChatId, input, isTyping; useQuery for chats and messages; layout with ChatSidebar and ChatArea components.

Files:

  • src/components/ChatInterface.tsx
**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/convex-security.mdc)

**/*.{ts,tsx}: All Convex queries and mutations MUST use proper authentication. Never accept user IDs from client parameters.
Always verify user owns the data before allowing access.
Use the authenticated user's identity.subject for user references.
Implement proper error messages that don't leak information.
Authentication verification in every function.
Authorization checks for data ownership.
Input validation and sanitization.
Error handling without information leakage.

**/*.{ts,tsx}: Use Sonner for toast notifications to provide consistent user feedback, including success, error, and loading states.
Always handle errors gracefully using try-catch blocks in asynchronous functions, providing user feedback and logging errors.
Provide specific, actionable error messages for form validation errors using toast notifications.
Handle common network error scenarios in catch blocks, providing appropriate toast messages for network errors, authentication errors, and unexpected errors.

If using TypeScript, use an enum to store flag names.

Strict TypeScript must be used with no 'any' types allowed

**/*.{ts,tsx}: NEVER use any type - use proper TypeScript types
Use unknown for truly unknown data types
Implement proper interface definitions
Do not use empty interfaces; use a type alias instead (e.g., type InputProps = ... instead of interface InputProps {})
All function parameters must be typed
All return types should be explicit for public APIs
Use proper generic constraints
Implement discriminated unions for state management
Use proper interface definitions for error handling types (e.g., interface ValidationResult { isValid: boolean; error?: string; })

**/*.{ts,tsx}: Always sanitize user input before storing or displaying using a sanitization function like sanitizeText.
Implement comprehensive input validation, including length checks and detection of malicious patterns, as shown in the validateInput function.
Define and use security constants suc...

Files:

  • src/components/ChatInterface.tsx
**/*.tsx

📄 CodeRabbit Inference Engine (.cursor/rules/error-handling.mdc)

**/*.tsx: Always provide loading feedback to users during asynchronous operations.
Use proper error boundaries to handle component crashes and display user-friendly error UI.

Use proper React component typing (e.g., const MyComponent: React.FC<Props> = ...)

**/*.tsx: Use the SafeText React component for all user-generated content to ensure safe text display.
NEVER use dangerouslySetInnerHTML with user content.
NEVER use direct string interpolation in HTML with user content.

Files:

  • src/components/ChatInterface.tsx
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/posthog-integration.mdc)

**/*.{js,jsx,ts,tsx}: Use a consistent naming convention for this storage. enum/const object members should be written UPPERCASE_WITH_UNDERSCORE.
If a custom property for a person or event is at any point referenced in two or more files or two or more callsites in the same file, use an enum or const object, as above in feature flags.

Files:

  • src/components/ChatInterface.tsx
src/components/**/*.tsx

📄 CodeRabbit Inference Engine (.cursor/rules/project-overview.mdc)

Input sanitization and validation must be implemented throughout the codebase to provide XSS protection

Files:

  • src/components/ChatInterface.tsx
src/**/*.tsx

📄 CodeRabbit Inference Engine (CLAUDE.md)

src/**/*.tsx: Use React Hook Form with Zod validation for client-side forms
Prevent XSS by sanitizing any user-generated content before rendering (avoid unsafe HTML, or sanitize it)
Implement proper error handling with typed error boundaries in React

Files:

  • src/components/ChatInterface.tsx
🧠 Learnings (8)
📚 Learning: 2025-08-09T23:03:33.406Z
Learnt from: CR
PR: otdoges/zapdev#0
File: .cursor/rules/project-overview.mdc:0-0
Timestamp: 2025-08-09T23:03:33.406Z
Learning: Applies to src/components/**/*.tsx : Input sanitization and validation must be implemented throughout the codebase to provide XSS protection

Applied to files:

  • src/components/ChatInterface.tsx
📚 Learning: 2025-08-09T23:03:47.108Z
Learnt from: CR
PR: otdoges/zapdev#0
File: .cursor/rules/xss-protection.mdc:0-0
Timestamp: 2025-08-09T23:03:47.108Z
Learning: Applies to **/*.tsx : Use the `SafeText` React component for all user-generated content to ensure safe text display.

Applied to files:

  • src/components/ChatInterface.tsx
📚 Learning: 2025-08-12T03:04:41.034Z
Learnt from: CR
PR: otdoges/zapdev#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-12T03:04:41.034Z
Learning: Applies to src/**/*.tsx : Prevent XSS by sanitizing any user-generated content before rendering (avoid unsafe HTML, or sanitize it)

Applied to files:

  • src/components/ChatInterface.tsx
📚 Learning: 2025-08-09T23:03:01.775Z
Learnt from: CR
PR: otdoges/zapdev#0
File: .cursor/rules/chat-ui-patterns.mdc:0-0
Timestamp: 2025-08-09T23:03:01.775Z
Learning: Applies to **/*.{tsx} : Render messages safely using a SafeText component inside a div with 'whitespace-pre-wrap' to preserve formatting.

Applied to files:

  • src/components/ChatInterface.tsx
📚 Learning: 2025-08-09T23:03:01.775Z
Learnt from: CR
PR: otdoges/zapdev#0
File: .cursor/rules/chat-ui-patterns.mdc:0-0
Timestamp: 2025-08-09T23:03:01.775Z
Learning: Applies to **/*.{tsx} : Ensure proper keyboard navigation throughout the chat interface for accessibility.

Applied to files:

  • src/components/ChatInterface.tsx
📚 Learning: 2025-08-09T23:03:01.775Z
Learnt from: CR
PR: otdoges/zapdev#0
File: .cursor/rules/chat-ui-patterns.mdc:0-0
Timestamp: 2025-08-09T23:03:01.775Z
Learning: Applies to **/*ChatInterface*.tsx : Chat interfaces should follow the specified component structure: state management for selectedChatId, input, isTyping; useQuery for chats and messages; layout with ChatSidebar and ChatArea components.

Applied to files:

  • src/components/ChatInterface.tsx
📚 Learning: 2025-08-12T03:04:41.034Z
Learnt from: CR
PR: otdoges/zapdev#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-12T03:04:41.034Z
Learning: Applies to src/App.tsx : Maintain routing protection: protect /chat and /settings with AuthGuard; keep public routes unprotected as specified

Applied to files:

  • src/components/ChatInterface.tsx
📚 Learning: 2025-08-09T23:03:47.108Z
Learnt from: CR
PR: otdoges/zapdev#0
File: .cursor/rules/xss-protection.mdc:0-0
Timestamp: 2025-08-09T23:03:47.108Z
Learning: Applies to **/*.{ts,tsx} : Define and use security constants such as `MAX_MESSAGE_LENGTH`, `MAX_TITLE_LENGTH`, and `MAX_CODE_BLOCK_LENGTH` to enforce input size limits.

Applied to files:

  • src/components/ChatInterface.tsx
🧬 Code Graph Analysis (1)
src/components/ChatInterface.tsx (1)
src/components/ui/SafeText.tsx (1)
  • SafeText (13-37)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: claude-review

@Jackson57279 Jackson57279 merged commit 92dd548 into main Aug 16, 2025
11 of 12 checks passed
@Jackson57279 Jackson57279 deleted the alert-autofix-123 branch August 16, 2025 01:18
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.

1 participant