Skip to content

Comments

Add attachments to ai processing#601

Merged
elie222 merged 1 commit intostagingfrom
feat/attachment-processing
Jul 28, 2025
Merged

Add attachments to ai processing#601
elie222 merged 1 commit intostagingfrom
feat/attachment-processing

Conversation

@elie222
Copy link
Owner

@elie222 elie222 commented Jul 28, 2025

Summary by CodeRabbit

  • New Features
    • Email attachments are now included and displayed with relevant details (filename, type, and size) when viewing or processing emails.
  • Enhancements
    • Email data serialization now incorporates attachment information for improved clarity.

@vercel
Copy link

vercel bot commented Jul 28, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Updated (UTC)
inbox-zero 🔄 Building (Inspect) Visit Preview Jul 28, 2025 7:45pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jul 28, 2025

Walkthrough

The changes introduce support for email attachments in the email utility functions. The EmailForLLM type is updated to include an optional attachments array, and both the logic for extracting email data and serializing emails are extended to handle this new property.

Changes

Cohort / File(s) Change Summary
Attachment Extraction Logic
apps/web/utils/get-email-from-message.ts
The function now includes an attachments property in its return value, mapping message attachments to objects with filename, mimeType, and size.
Attachment Serialization
apps/web/utils/stringify-email.ts
The function now serializes email attachments into XML-like tags if present, appending them to the output string.
Type Definition Update
apps/web/utils/types.ts
The EmailForLLM type is extended to optionally include an attachments array with relevant fields.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Poem

A rabbit hops through fields of mail,
Now attachments join the tale.
Filenames, types, and sizes too,
Wrapped in tags, all shiny and new.
With every hop, the inbox grows—
More details in each message flows!
🐇📎

Note

⚡️ Unit Test Generation is now available in beta!

Learn more here, or try it out under "Finishing Touches" below.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/attachment-processing

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
🪧 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.
    • Explain this complex logic.
    • 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. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • 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 src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

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

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

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.

Documentation and Community

  • 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 Jul 28, 2025

Claude finished @elie222's task —— View job


Code Review Complete ✅

I've reviewed this PR that adds attachment processing functionality to the email handling utilities. Overall, the implementation is clean and follows good TypeScript practices, but there are some important security and robustness concerns to address.

Review Tasks:

  • Analyze apps/web/utils/get-email-from-message.ts changes
  • Analyze apps/web/utils/stringify-email.ts changes
  • Analyze apps/web/utils/types.ts changes
  • Check for potential bugs and security issues
  • Evaluate performance considerations
  • Provide comprehensive feedback

🔍 Review Findings

Positive Aspects

  • Clean TypeScript usage: Proper optional chaining (message.attachments?.map()) and type safety
  • Consistent API design: The attachment structure is simple and focused on essential metadata
  • Performance-conscious: Uses efficient array methods and conditional rendering
  • Minimal surface area: Only extracts necessary attachment metadata (filename, mimeType, size)

🚨 Security Concerns

High Priority - XML Injection Vulnerability in apps/web/utils/stringify-email.ts:20

`<attachment filename="${att.filename}" type="${att.mimeType}" size="${att.size}" />`

The filename and mimeType values are inserted directly into XML attributes without escaping, creating potential for XML injection attacks. Malicious filenames could break the XML structure or inject malicious content.

Recommended fix:

// Add XML escaping function
function escapeXml(unsafe: string): string {
  return unsafe.replace(/[<>&'"]/g, (c) => {
    switch (c) {
      case '<': return '&lt;';
      case '>': return '&gt;';
      case '&': return '&amp;';
      case "'": return '&apos;';
      case '"': return '&quot;';
      default: return c;
    }
  });
}

// Use in the template
`<attachment filename="${escapeXml(att.filename)}" type="${escapeXml(att.mimeType)}" size="${att.size}" />`

⚠️ Potential Issues

  1. No input validation in apps/web/utils/get-email-from-message.ts:18-22

    • No checks for undefined/null filename, mimeType, or size
    • Could pass through malformed attachment data
  2. Missing type safety in apps/web/utils/types.ts:116-120

    • The Attachment interface exists (lines 63-69) but EmailForLLM redefines a subset
    • Consider reusing or extending the existing Attachment type for consistency

💡 Suggestions for Improvement

  1. Add input validation:
attachments: message.attachments
  ?.filter(att => att.filename && att.mimeType && typeof att.size === 'number')
  ?.map((attachment) => ({
    filename: attachment.filename,
    mimeType: attachment.mimeType,
    size: attachment.size,
  })),
  1. Type consistency - Consider creating a shared type:
export type AttachmentMetadata = Pick<Attachment, 'filename' | 'mimeType' | 'size'>;

export type EmailForLLM = {
  // ... other properties
  attachments?: AttachmentMetadata[];
};
  1. Handle edge cases in stringification:
    • Very long filenames
    • Zero or negative file sizes
    • Empty attachment arrays

🚀 Performance Considerations

  • The current implementation is efficient with O(n) complexity for attachment processing
  • Consider adding early returns if performance becomes critical with large attachment lists

📋 Summary

The feature implementation is architecturally sound and follows good practices, but the XML injection vulnerability must be addressed before merging. The other suggestions would improve robustness and maintainability but are not blocking.

Priority Actions:

  1. Critical: Fix XML escaping in stringify-email.ts:20
  2. Recommended: Add input validation for attachment data
  3. Optional: Improve type consistency across the codebase

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

🧹 Nitpick comments (1)
apps/web/utils/stringify-email.ts (1)

29-46: Consider attachment support in other stringify functions.

The stringifyEmailSimple and stringifyEmailFromBody functions don't include attachment support. While this might be intentional given their "simple" nature, consider whether attachments should be included for consistency, especially if these functions are used in LLM contexts where attachment metadata could be relevant.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a136405 and 2f91c0b.

📒 Files selected for processing (3)
  • apps/web/utils/get-email-from-message.ts (1 hunks)
  • apps/web/utils/stringify-email.ts (1 hunks)
  • apps/web/utils/types.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (8)
apps/web/**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (apps/web/CLAUDE.md)

apps/web/**/*.{ts,tsx}: Use TypeScript with strict null checks
Path aliases: Use @/ for imports from project root
Use proper error handling with try/catch blocks
Format code with Prettier
Leverage TypeScript inference for better DX

Files:

  • apps/web/utils/get-email-from-message.ts
  • apps/web/utils/stringify-email.ts
  • apps/web/utils/types.ts
!{.cursor/rules/*.mdc}

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

Never place rule files in the project root, in subdirectories outside .cursor/rules, or in any other location

Files:

  • apps/web/utils/get-email-from-message.ts
  • apps/web/utils/stringify-email.ts
  • apps/web/utils/types.ts
**/*.ts

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

**/*.ts: The same validation should be done in the server action too
Define validation schemas using Zod

Files:

  • apps/web/utils/get-email-from-message.ts
  • apps/web/utils/stringify-email.ts
  • apps/web/utils/types.ts
**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/logging.mdc)

**/*.{ts,tsx}: Use createScopedLogger for logging in backend TypeScript files
Typically add the logger initialization at the top of the file when using createScopedLogger
Only use .with() on a logger instance within a specific function, not for a global logger

Import Prisma in the project using import prisma from "@/utils/prisma";

**/*.{ts,tsx}: Don't use TypeScript enums.
Don't use TypeScript const enum.
Don't use the TypeScript directive @ts-ignore.
Don't use primitive type aliases or misleading types.
Don't use empty type parameters in type aliases and interfaces.
Don't use any or unknown as type constraints.
Don't use implicit any type on variable declarations.
Don't let variables evolve into any type through reassignments.
Don't use non-null assertions with the ! postfix operator.
Don't misuse the non-null assertion operator (!) in TypeScript files.
Don't use user-defined types.
Use as const instead of literal types and type annotations.
Use export type for types.
Use import type for types.
Don't declare empty interfaces.
Don't merge interfaces and classes unsafely.
Don't use overload signatures that aren't next to each other.
Use the namespace keyword instead of the module keyword to declare TypeScript namespaces.
Don't use TypeScript namespaces.
Don't export imported variables.
Don't add type annotations to variables, parameters, and class properties that are initialized with literal expressions.
Don't use parameter properties in class constructors.
Use either T[] or Array consistently.
Initialize each enum member value explicitly.
Make sure all enum members are literal values.

Files:

  • apps/web/utils/get-email-from-message.ts
  • apps/web/utils/stringify-email.ts
  • apps/web/utils/types.ts
apps/web/utils/**

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

Create utility functions in utils/ folder for reusable logic

Files:

  • apps/web/utils/get-email-from-message.ts
  • apps/web/utils/stringify-email.ts
  • apps/web/utils/types.ts
apps/web/utils/**/*.ts

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

apps/web/utils/**/*.ts: Use lodash utilities for common operations (arrays, objects, strings)
Import specific lodash functions to minimize bundle size

Files:

  • apps/web/utils/get-email-from-message.ts
  • apps/web/utils/stringify-email.ts
  • apps/web/utils/types.ts
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/ultracite.mdc)

**/*.{js,jsx,ts,tsx}: Don't use elements in Next.js projects.
Don't use elements in Next.js projects.
Don't use namespace imports.
Don't access namespace imports dynamically.
Don't use global eval().
Don't use console.
Don't use debugger.
Don't use var.
Don't use with statements in non-strict contexts.
Don't use the arguments object.
Don't use consecutive spaces in regular expression literals.
Don't use the comma operator.
Don't use unnecessary boolean casts.
Don't use unnecessary callbacks with flatMap.
Use for...of statements instead of Array.forEach.
Don't create classes that only have static members (like a static namespace).
Don't use this and super in static contexts.
Don't use unnecessary catch clauses.
Don't use unnecessary constructors.
Don't use unnecessary continue statements.
Don't export empty modules that don't change anything.
Don't use unnecessary escape sequences in regular expression literals.
Don't use unnecessary labels.
Don't use unnecessary nested block statements.
Don't rename imports, exports, and destructured assignments to the same name.
Don't use unnecessary string or template literal concatenation.
Don't use String.raw in template literals when there are no escape sequences.
Don't use useless case statements in switch statements.
Don't use ternary operators when simpler alternatives exist.
Don't use useless this aliasing.
Don't initialize variables to undefined.
Don't use the void operators (they're not familiar).
Use arrow functions instead of function expressions.
Use Date.now() to get milliseconds since the Unix Epoch.
Use .flatMap() instead of map().flat() when possible.
Use literal property access instead of computed property access.
Don't use parseInt() or Number.parseInt() when binary, octal, or hexadecimal literals work.
Use concise optional chaining instead of chained logical expressions.
Use regular expression literals instead of the RegExp constructor when possible.
Don't use number literal object member names th...

Files:

  • apps/web/utils/get-email-from-message.ts
  • apps/web/utils/stringify-email.ts
  • apps/web/utils/types.ts
!pages/_document.{js,jsx,ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/ultracite.mdc)

!pages/_document.{js,jsx,ts,tsx}: Don't import next/document outside of pages/_document.jsx in Next.js projects.
Don't import next/document outside of pages/_document.jsx in Next.js projects.

Files:

  • apps/web/utils/get-email-from-message.ts
  • apps/web/utils/stringify-email.ts
  • apps/web/utils/types.ts
🧠 Learnings (3)
apps/web/utils/get-email-from-message.ts (10)

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-07-18T15:06:40.272Z
Learning: Applies to apps/web/utils/{ai,llms}/**/*.ts : Include relevant context in log messages for LLM-related code.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-07-18T15:06:40.272Z
Learning: Applies to apps/web/utils/{ai,llms}/**/*.ts : Use TypeScript types for all parameters and return values in LLM-related code.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-07-18T15:06:40.272Z
Learning: Applies to apps/web/utils/{ai,llms}/**/*.ts : Format data consistently across similar LLM-related functions.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-07-18T15:06:40.272Z
Learning: Applies to apps/web/utils/{ai,llms}/**/*.ts : Use proper error types and logging in LLM-related code.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-07-18T15:06:40.272Z
Learning: Applies to apps/web/utils/{ai,llms}/**/*.ts : Extract common patterns into utility functions in LLM-related code.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-07-18T15:06:40.272Z
Learning: Applies to apps/web/utils/{ai,llms}/**/*.ts : Implement early returns for invalid inputs in LLM-related functions.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-07-18T15:06:40.272Z
Learning: Applies to apps/web/utils/{ai,llms}/**/*.ts : Implement fallbacks for AI failures in LLM-related functions.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-07-18T15:06:40.272Z
Learning: Applies to apps/web/utils/{ai,llms}/**/*.ts : Define clear interfaces for complex input/output structures in LLM-related code.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-07-18T15:06:40.272Z
Learning: Applies to apps/web/utils/{ai,llms}/**/*.ts : Make Zod schemas as specific as possible to guide the LLM output.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-07-18T15:05:34.899Z
Learning: Applies to apps/web/utils/gmail/**/*.ts : Keep provider-specific implementation details isolated in the appropriate utils subfolder (e.g., 'apps/web/utils/gmail/')

apps/web/utils/stringify-email.ts (2)

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-07-18T15:05:34.899Z
Learning: Applies to apps/web/utils/gmail/**/*.ts : Keep provider-specific implementation details isolated in the appropriate utils subfolder (e.g., 'apps/web/utils/gmail/')

Learnt from: edulelis
PR: #576
File: packages/resend/emails/digest.tsx:78-83
Timestamp: 2025-07-17T04:19:57.099Z
Learning: In packages/resend/emails/digest.tsx, the DigestEmailProps type uses [key: string]: DigestItem[] | undefined | string | Date | undefined instead of intersection types like & Record<string, DigestItem[] | undefined> due to implementation constraints. This was the initial implementation approach and cannot be changed to more restrictive typing.

apps/web/utils/types.ts (10)

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-07-18T15:06:40.272Z
Learning: Applies to apps/web/utils/{ai,llms}/**/*.ts : Use TypeScript types for all parameters and return values in LLM-related code.

Learnt from: edulelis
PR: #576
File: packages/resend/emails/digest.tsx:78-83
Timestamp: 2025-07-17T04:19:57.099Z
Learning: In packages/resend/emails/digest.tsx, the DigestEmailProps type uses [key: string]: DigestItem[] | undefined | string | Date | undefined instead of intersection types like & Record<string, DigestItem[] | undefined> due to implementation constraints. This was the initial implementation approach and cannot be changed to more restrictive typing.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-07-18T15:06:40.272Z
Learning: Applies to apps/web/utils/{ai,llms}/**/*.ts : Use proper error types and logging in LLM-related code.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-07-18T15:06:40.272Z
Learning: Applies to apps/web/utils/{ai,llms}/**/*.ts : Define clear interfaces for complex input/output structures in LLM-related code.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-07-18T15:06:40.272Z
Learning: Applies to apps/web/utils/{ai,llms}/**/*.ts : Make Zod schemas as specific as possible to guide the LLM output.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-07-18T15:06:40.272Z
Learning: Applies to apps/web/utils/{ai,llms}/**/*.ts : Format data consistently across similar LLM-related functions.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-07-18T15:06:40.272Z
Learning: Applies to apps/web/utils/{ai,llms}/**/*.ts : Include relevant context in log messages for LLM-related code.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-07-18T15:06:40.272Z
Learning: Applies to apps/web/utils/{ai,llms}/**/*.ts : Use XML-like tags to structure data in LLM prompts.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-07-18T15:06:40.272Z
Learning: Applies to apps/web/utils/{ai,llms}/**/*.ts : Implement fallbacks for AI failures in LLM-related functions.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-07-18T15:06:40.272Z
Learning: Applies to apps/web/utils/{ai,llms}/**/*.ts : Extract common patterns into utility functions in LLM-related code.

⏰ 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: Analyze (javascript-typescript)
🔇 Additional comments (2)
apps/web/utils/types.ts (1)

116-120: LGTM! Well-structured attachment metadata for LLM processing.

The optional attachments property is appropriately typed with the essential metadata fields needed for LLM processing. The exclusion of implementation details like attachmentId and headers from the existing Attachment interface is sensible for this use case.

apps/web/utils/get-email-from-message.ts (1)

18-22: LGTM! Safe and type-correct attachment mapping.

The implementation correctly uses optional chaining and maps only the necessary attachment metadata fields for LLM processing. The mapping is type-safe given the Attachment interface definition.

Comment on lines +16 to +24
if (email.attachments && email.attachments.length > 0) {
const attachmentsXml = email.attachments
.map(
(att) =>
`<attachment filename="${att.filename}" type="${att.mimeType}" size="${att.size}" />`,
)
.join("\n");
emailParts.push(`<attachments>\n${attachmentsXml}\n</attachments>`);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

❓ Verification inconclusive

Fix XML attribute escaping for attachment metadata.

The attachment XML generation doesn't escape special characters in attribute values, which could break the XML structure if filenames contain quotes or other special characters.

Consider escaping the attribute values:

-          `<attachment filename="${att.filename}" type="${att.mimeType}" size="${att.size}" />`,
+          `<attachment filename="${att.filename.replace(/"/g, '&quot;')}" type="${att.mimeType.replace(/"/g, '&quot;')}" size="${att.size}" />`,

Or better yet, extract this to a utility function for proper XML attribute escaping.

Let me verify if there are existing XML escaping utilities in the codebase:


🏁 Script executed:

#!/bin/bash
# Search for XML/HTML escaping utilities in the codebase
rg -i "escape.*xml|xml.*escape|escapehtml|htmlescape" --type ts

Length of output: 65


Fix XML Attribute Escaping in stringifyEmail

The attachment serialization in apps/web/utils/stringify-email.ts does not escape special characters (e.g., quotes, ampersands) in XML attribute values. Unescaped values can break the XML structure or introduce injection risks.

Please update as follows:

• File: apps/web/utils/stringify-email.ts
Lines: ~16–24

• Introduce an xmlEscape() helper (e.g. in apps/web/utils/xml-utils.ts) that replaces &, <, >, " and ' with their XML entities.
• Use xmlEscape() when interpolating filename, mimeType, and (if string) size.

Example diff:

--- a/apps/web/utils/stringify-email.ts
+++ b/apps/web/utils/stringify-email.ts
@@ -13,8 +13,11 @@ export function stringifyEmail(email: Email): string[] {
   if (email.attachments && email.attachments.length > 0) {
     const attachmentsXml = email.attachments
       .map((att) =>
-        `<attachment filename="${att.filename}" type="${att.mimeType}" size="${att.size}" />`,
+        `<attachment ` +
+          `filename="${xmlEscape(att.filename)}" ` +
+          `type="${xmlEscape(att.mimeType)}" ` +
+          `size="${xmlEscape(String(att.size))}" ` +
+        `/>`,
       )
       .join("\n");
     emailParts.push(`<attachments>\n${attachmentsXml}\n</attachments>`);

If you’d rather not add a new file, you can place xmlEscape alongside other utilities in apps/web/utils/.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In apps/web/utils/stringify-email.ts around lines 16 to 24, the XML attribute
values for attachments are not escaped, risking broken XML or injection issues.
Create an xmlEscape() helper function that replaces &, <, >, ", and ' with their
XML entity equivalents, either in a new file apps/web/utils/xml-utils.ts or
alongside existing utilities. Then apply xmlEscape() to filename, mimeType, and
size (if it is a string) when constructing the attachment XML attributes to
ensure all special characters are properly escaped.

@elie222 elie222 merged commit 743fbec into staging Jul 28, 2025
13 checks passed
@elie222 elie222 deleted the feat/attachment-processing branch July 28, 2025 19:49
@coderabbitai coderabbitai bot mentioned this pull request Dec 21, 2025
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