Skip to content

fix: prevent unbounded memory consumption in avatar URL uploads#40146

Open
soumajitgh wants to merge 7 commits intoRocketChat:developfrom
soumajitgh:soumajit/fix-avatar-url-fetch-limits
Open

fix: prevent unbounded memory consumption in avatar URL uploads#40146
soumajitgh wants to merge 7 commits intoRocketChat:developfrom
soumajitgh:soumajit/fix-avatar-url-fetch-limits

Conversation

@soumajitgh
Copy link
Copy Markdown

@soumajitgh soumajitgh commented Apr 14, 2026

Proposed changes

This PR fixes a High Severity (P1) Security Vulnerability where authenticated users could crash the server by pointing their avatar URL to an extremely large file.

Improvements:

  • Real-time Streaming Limits: Replaced arrayBuffer() with a streaming buffer that enforces size limits during download.
  • Early Abort: Immediately terminates requests if the Content-Length header is too large or if the incoming byte stream exceeds the threshold.
  • Safety & Timeouts: Added a 20-second download timeout and enforced strict image/* MIME type validation.
  • Resource Cleanup: Implemented discardResponseBody to prevent socket and memory leaks.

Issue(s)

Closes: #39450

Steps to test or reproduce

  1. Size Limit: Attempt to set an avatar URL to a file larger than FileUpload_MaxFileSize. Verify it returns error-file-too-large without OOM.
  2. Timeout: Point to a URL that hangs (e.g., httpbin.org/delay/30). Verify it fails with error-avatar-response-timeout after 20s.
  3. MIME Check: Point to a non-image URL. Verify it returns error-avatar-invalid-url.

Summary by CodeRabbit

  • Bug Fixes

    • Improved remote avatar handling: streaming-based size enforcement, request/stream timeouts, stricter image content-type validation, clearer errors for oversized or timed-out downloads, ensured response bodies are discarded on error, and fixed avatar cleanup control flow.
  • Tests

    • Added unit tests covering remote avatar download success and multiple failure modes (size limits, missing/mismatched headers, content-type issues, and timeouts).

Remote avatar URLs fetched via `setUserAvatar` loaded entire
response into memory with no size limit, enabling OOM via large
files or concurrent requests.

- Stream response with byte-limit enforcement (FileUpload_MaxFileSize)
- Early-reject on oversized Content-Length header
- Abort mid-stream when actual bytes exceed limit regardless of header
- Add 20s body-read timeout to prevent slow-body resource hold
- Destroy response body on non-200 / non-image paths to free sockets
- Add unit tests for: oversized Content-Length, missing header,
  lied header, non-image MIME, valid small image, body-read timeout
@dionisio-bot
Copy link
Copy Markdown
Contributor

dionisio-bot bot commented Apr 14, 2026

Looks like this PR is not ready to merge, because of the following issues:

  • This PR is missing the 'stat: QA assured' label
  • This PR is missing the required milestone or project

Please fix the issues and try again

If you have any trouble, please check the PR guidelines

@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Apr 14, 2026

⚠️ No Changeset found

Latest commit: c02afa3

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 14, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Stream-based avatar URL fetching replaces unbounded buffering with content-type validation, content-length checks, streaming size/time limits, unified URL error mapping, response-body discard on failures, and safer avatar cleanup checks; tests cover failure and success scenarios.

Changes

Cohort / File(s) Summary
Avatar URL download & helpers
apps/meteor/app/lib/server/functions/setUserAvatar.ts
Replace response.arrayBuffer() with streaming helpers (bufferResponseWithLimit, discardResponseBody), add media-type parsing/validation, request-timeout detection, content-length checks, max-size enforcement, and unified Meteor.Error mapping; ensure response bodies discarded on non-200/invalid responses; make avatar deletion conditional on user.username.
Unit tests (avatar URL)
apps/meteor/tests/unit/app/lib/server/functions/setUserAvatar.spec.ts
Add comprehensive tests using proxyquire with mocked fetch responses and Readable streams to cover: oversized content-length, missing content-length with streamed overflow, mismatched content-length, invalid content-type (including parameter-only matches), download timeout, negative max-size fallback, and successful storage/asserted insert behavior.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Server as setUserAvatar
    participant Fetch as RemoteServer
    participant Storage as FileUpload
    participant Users as UserService

    Client->>Server: request set avatar (service='url', url)
    Server->>Fetch: fetch(url, { signal, timeout })
    Fetch-->>Server: response (status, headers, body stream)
    alt non-200 or invalid content-type or size > max via content-length
        Server->>Fetch: discard response body
        Server-->>Client: error (mapped Meteor.Error)
    else valid response
        Server->>Server: bufferResponseWithLimit(bodyStream, maxSize, timeout)
        alt stream exceeds limit or timeout
            Server->>Fetch: abort/discard body
            Server-->>Client: error (file-too-large / download-timeout)
        else buffered within limits
            Server->>Storage: insert(buffer, metadata)
            Storage-->>Server: fileId
            Server->>Users: updateAvatar(userId, fileId)
            Server-->>Client: success
        end
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested labels

type: bug

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: preventing unbounded memory consumption in avatar URL uploads, which is the primary objective of this security fix.
Linked Issues check ✅ Passed The code changes fully implement the security requirements from issue #39450: streaming with size enforcement, Content-Length validation, max-size abort, download timeout, and proper resource cleanup.
Out of Scope Changes check ✅ Passed All changes are directly related to fixing the unbounded memory consumption vulnerability: streaming helpers, URL validation, timeout handling, and comprehensive unit tests for the avatar upload functionality.

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


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.

@soumajitgh soumajitgh marked this pull request as ready for review April 14, 2026 02:59
@soumajitgh soumajitgh requested a review from a team as a code owner April 14, 2026 02:59
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 2 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/meteor/app/lib/server/functions/setUserAvatar.ts">

<violation number="1" location="apps/meteor/app/lib/server/functions/setUserAvatar.ts:247">
P2: Avatar download timeouts are thrown but not mapped to a dedicated Meteor error, so they are returned as generic URL handling failures.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Copy link
Copy Markdown
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: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/meteor/app/lib/server/functions/setUserAvatar.ts`:
- Line 83: The timeout rejection created by setTimeout (using rejectWithError
and the AVATAR_RESPONSE_TIMEOUT constant at timeoutId) is being swallowed by the
generic error rewrite that only special-cases AVATAR_RESPONSE_TOO_LARGE and
otherwise maps everything to 'error-avatar-url-handling', making the intended
'error-avatar-response-timeout' unreachable; update the error-mapping logic (the
block that currently maps AVATAR_RESPONSE_TOO_LARGE and rewrites other avatar
errors to 'error-avatar-url-handling') to explicitly detect
AVATAR_RESPONSE_TIMEOUT and map it to 'error-avatar-response-timeout' (or let
that specific error pass through) so the timeout produced by
rejectWithError(timeoutId) is surfaced correctly. Ensure the rejectWithError
call still uses AVATAR_RESPONSE_TIMEOUT and that no later code unconditionally
replaces that error code.
- Line 179: The code currently assigns maxFileSize from
settings.get('FileUpload_MaxFileSize') and allows negative values (e.g., -1) to
flow into subsequent size checks (content-length and totalBytes), causing
uploads to be rejected; change the assignment so that only positive numeric
values from settings are used and treat non-positive/invalid values as the
DEFAULT_MAX_FILE_SIZE sentinel. Specifically, read
settings.get('FileUpload_MaxFileSize') into a local (e.g., maxFileSizeSetting),
validate with a numeric check (must be finite and > 0), and set maxFileSize to
that value only when valid; otherwise fall back to DEFAULT_MAX_FILE_SIZE so the
existing content-length and totalBytes comparisons behave correctly.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c645a426-f64c-4b08-971b-455da9b43f73

📥 Commits

Reviewing files that changed from the base of the PR and between 3c87a68 and 855a9de.

📒 Files selected for processing (2)
  • apps/meteor/app/lib/server/functions/setUserAvatar.ts
  • apps/meteor/tests/unit/app/lib/server/functions/setUserAvatar.spec.ts
📜 Review details
⏰ 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: cubic · AI code reviewer
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)

**/*.{ts,tsx,js}: Write concise, technical TypeScript/JavaScript with accurate typing in Playwright tests
Avoid code comments in the implementation

Files:

  • apps/meteor/tests/unit/app/lib/server/functions/setUserAvatar.spec.ts
  • apps/meteor/app/lib/server/functions/setUserAvatar.ts
**/*.spec.ts

📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)

**/*.spec.ts: Use descriptive test names that clearly communicate expected behavior in Playwright tests
Use .spec.ts extension for test files (e.g., login.spec.ts)

Files:

  • apps/meteor/tests/unit/app/lib/server/functions/setUserAvatar.spec.ts
🧠 Learnings (16)
📚 Learning: 2026-03-20T13:51:23.302Z
Learnt from: ggazzo
Repo: RocketChat/Rocket.Chat PR: 39553
File: apps/meteor/app/integrations/server/methods/incoming/updateIncomingIntegration.ts:179-181
Timestamp: 2026-03-20T13:51:23.302Z
Learning: In `apps/meteor/app/integrations/server/methods/incoming/updateIncomingIntegration.ts`, the truthiness guards `...(integration.avatar && { avatar })`, `...(integration.emoji && { emoji })`, `...(integration.alias && { alias })`, and `...(integration.script && { script })` in the `$set` payload of `updateIncomingIntegration` are intentional. Empty-string values for these fields should NOT overwrite the stored value — only truthy values are persisted. Do not flag these as bugs preventing explicit clears.

Applied to files:

  • apps/meteor/tests/unit/app/lib/server/functions/setUserAvatar.spec.ts
  • apps/meteor/app/lib/server/functions/setUserAvatar.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Utilize Playwright fixtures (`test`, `page`, `expect`) for consistency in test files

Applied to files:

  • apps/meteor/tests/unit/app/lib/server/functions/setUserAvatar.spec.ts
📚 Learning: 2026-03-16T11:57:17.987Z
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 39657
File: apps/meteor/tests/end-to-end/apps/app-resolve-visitor.ts:43-45
Timestamp: 2026-03-16T11:57:17.987Z
Learning: In `apps/meteor/tests/end-to-end/apps/app-resolve-visitor.ts`, `externalIds` lookups are namespaced per `app.id`. Because `cleanupApps()` is called before each test run and a fresh app is installed (giving a new unique `app.id`), fixed `userId` strings like `'nonexistent-id'` in null-path tests are safe and cannot collide with stale visitor records from previous runs. Do not flag these as needing unique/random values.

Applied to files:

  • apps/meteor/tests/unit/app/lib/server/functions/setUserAvatar.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : All test files must be created in `apps/meteor/tests/e2e/` directory

Applied to files:

  • apps/meteor/tests/unit/app/lib/server/functions/setUserAvatar.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Group related tests in the same file

Applied to files:

  • apps/meteor/tests/unit/app/lib/server/functions/setUserAvatar.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Ensure tests run reliably in parallel without shared state conflicts

Applied to files:

  • apps/meteor/tests/unit/app/lib/server/functions/setUserAvatar.spec.ts
📚 Learning: 2025-10-06T20:30:45.540Z
Learnt from: d-gubert
Repo: RocketChat/Rocket.Chat PR: 37152
File: packages/apps-engine/tests/test-data/storage/storage.ts:101-122
Timestamp: 2025-10-06T20:30:45.540Z
Learning: In `packages/apps-engine/tests/test-data/storage/storage.ts`, the stub methods (updatePartialAndReturnDocument, updateStatus, updateSetting, updateAppInfo, updateMarketplaceInfo) intentionally throw "Method not implemented." Tests using these methods must stub them using `SpyOn` from the test library rather than relying on actual implementations.

Applied to files:

  • apps/meteor/tests/unit/app/lib/server/functions/setUserAvatar.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Maintain test isolation between test cases in Playwright tests

Applied to files:

  • apps/meteor/tests/unit/app/lib/server/functions/setUserAvatar.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Use `test.step()` for complex test scenarios to improve organization in Playwright tests

Applied to files:

  • apps/meteor/tests/unit/app/lib/server/functions/setUserAvatar.spec.ts
📚 Learning: 2026-03-15T14:31:28.969Z
Learnt from: amitb0ra
Repo: RocketChat/Rocket.Chat PR: 39647
File: apps/meteor/app/api/server/v1/users.ts:710-757
Timestamp: 2026-03-15T14:31:28.969Z
Learning: In RocketChat/Rocket.Chat, the `UserCreateParamsPOST` type in `apps/meteor/app/api/server/v1/users.ts` (migrated from `packages/rest-typings/src/v1/users/UserCreateParamsPOST.ts`) intentionally has `fields: string` (non-optional) and `settings?: IUserSettings` without a corresponding AJV schema entry. This is a pre-existing divergence carried over verbatim from the original rest-typings source (PR `#39647`). Do not flag this type/schema misalignment during the OpenAPI migration review — it is tracked as a separate follow-up fix.

Applied to files:

  • apps/meteor/tests/unit/app/lib/server/functions/setUserAvatar.spec.ts
📚 Learning: 2026-03-19T13:59:40.678Z
Learnt from: d-gubert
Repo: RocketChat/Rocket.Chat PR: 38357
File: apps/meteor/app/apps/server/converters/uploads.ts:45-49
Timestamp: 2026-03-19T13:59:40.678Z
Learning: In `apps/meteor/app/apps/server/converters/uploads.ts`, the `room` async handler in `convertToApp` uses non-null assertions (`upload.rid!` and `result!`) intentionally. The data flow guarantees that any upload reaching this point must have a `rid`; if it does not, throwing an error is the desired behavior (fail-fast / data integrity guard). Do not flag these non-null assertions as unsafe during code review.

Applied to files:

  • apps/meteor/tests/unit/app/lib/server/functions/setUserAvatar.spec.ts
📚 Learning: 2026-02-24T19:22:48.358Z
Learnt from: juliajforesti
Repo: RocketChat/Rocket.Chat PR: 38493
File: apps/meteor/tests/e2e/omnichannel/omnichannel-send-pdf-transcript.spec.ts:66-67
Timestamp: 2026-02-24T19:22:48.358Z
Learning: In Playwright end-to-end tests (e.g., under apps/meteor/tests/e2e/...), prefer locating elements by translated text (getByText) and ARIA roles (getByRole) over data-qa attributes. If translation values change, update the corresponding test locators accordingly. Never use data-qa locators. This guideline applies to all Playwright e2e test specs in the repository and helps keep tests robust to UI text changes and accessible semantics.

Applied to files:

  • apps/meteor/tests/unit/app/lib/server/functions/setUserAvatar.spec.ts
📚 Learning: 2026-02-26T19:25:44.063Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 38778
File: packages/ui-voip/src/providers/useMediaSession.ts:192-192
Timestamp: 2026-02-26T19:25:44.063Z
Learning: In the Rocket.Chat repository, do not reference Biome lint rules in code review feedback. Biome is not used even if biome.json exists; only reference Biome rules if there is explicit, project-wide usage documented. For TypeScript files, review lint implications without Biome guidance unless the project enables Biome rules.

Applied to files:

  • apps/meteor/tests/unit/app/lib/server/functions/setUserAvatar.spec.ts
  • apps/meteor/app/lib/server/functions/setUserAvatar.ts
📚 Learning: 2026-02-26T19:25:44.063Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 38778
File: packages/ui-voip/src/providers/useMediaSession.ts:192-192
Timestamp: 2026-02-26T19:25:44.063Z
Learning: In this repository (RocketChat/Rocket.Chat), Biome lint rules are not used even if a biome.json exists. When reviewing TypeScript files (e.g., packages/ui-voip/src/providers/useMediaSession.ts), ensure lint suggestions do not reference Biome-specific rules. Rely on general ESLint/TypeScript lint rules and project conventions instead.

Applied to files:

  • apps/meteor/tests/unit/app/lib/server/functions/setUserAvatar.spec.ts
  • apps/meteor/app/lib/server/functions/setUserAvatar.ts
📚 Learning: 2026-03-06T18:10:15.268Z
Learnt from: tassoevan
Repo: RocketChat/Rocket.Chat PR: 39397
File: packages/gazzodown/src/code/CodeBlock.spec.tsx:47-68
Timestamp: 2026-03-06T18:10:15.268Z
Learning: In tests (especially those using testing-library/dom/jsdom) for Rocket.Chat components, the HTML <code> element has an implicit ARIA role of 'code'. Therefore, screen.getByRole('code') or screen.findByRole('code') will locate <code> elements even without a role attribute. Do not flag findByRole('code') as invalid in reviews; prefer using the implicit role instead of adding role="code" unless necessary for accessibility.

Applied to files:

  • apps/meteor/tests/unit/app/lib/server/functions/setUserAvatar.spec.ts
📚 Learning: 2026-04-10T22:42:03.240Z
Learnt from: dougfabris
Repo: RocketChat/Rocket.Chat PR: 40075
File: apps/meteor/client/views/room/modals/FileUploadModal/FileUploadModal.tsx:69-71
Timestamp: 2026-04-10T22:42:03.240Z
Learning: In `apps/meteor/client/views/room/modals/FileUploadModal/FileUploadModal.tsx`, the submit handler converts an empty/whitespace-only description to `undefined` (`description?.trim() || undefined`) intentionally. All downstream image-rendering components (`AttachmentImage`, `ImagePreview`, `ImageItem`, `ImageGallery`) default `undefined` alt to `''`, so the `<img alt="">` attribute is always present. Do not flag this `undefined` conversion as a bug preventing alt text from being cleared.

Applied to files:

  • apps/meteor/app/lib/server/functions/setUserAvatar.ts

…ive and handle avatar download timeout error
@coderabbitai coderabbitai bot removed the type: bug label Apr 14, 2026
Copy link
Copy Markdown
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.

Caution

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

⚠️ Outside diff range comments (2)
apps/meteor/app/lib/server/functions/setUserAvatar.ts (2)

228-245: ⚠️ Potential issue | 🟠 Major

Anchor the MIME check to the actual media type.

Line 228 accepts any header that merely contains image/, so values like text/html; x=image/png bypass the guard, and Line 245 then persists a non-image content type. That weakens the new validation the PR is trying to add.

Suggested fix
-			if (!/image\/.+/.test(response.headers.get('content-type') || '')) {
+			const contentType = response.headers.get('content-type')?.split(';', 1)[0].trim().toLowerCase() || '';
+			if (!contentType.startsWith('image/')) {
 				discardResponseBody(response);
 
 				SystemLogger.info({
 					msg: 'Not a valid content-type from the provided avatar url',
-					contentType: response.headers.get('content-type'),
+					contentType: response.headers.get('content-type'),
 					url: dataURI,
 				});
 				throw new Meteor.Error('error-avatar-invalid-url', `Invalid avatar URL: ${dataURI}`, {
 					function: 'setUserAvatar',
 					url: dataURI,
 				});
 			}
 
 			try {
 				return {
 					buffer: await bufferResponseWithLimit(response, maxFileSize, DEFAULT_AVATAR_DOWNLOAD_TIMEOUT_MS),
-					type: response.headers.get('content-type') || '',
+					type: contentType,
 				};
 			} catch (error) {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/meteor/app/lib/server/functions/setUserAvatar.ts` around lines 228 -
245, The MIME-type check currently allows headers that merely contain "image/"
anywhere; update the validation in setUserAvatar to parse the Content-Type
header's media type (trim and strip parameters by splitting on ';' or matching
^\s*([^\/]+\/[^;\s]+)) and then ensure the media type startsWith 'image/' (or
matches ^image\/[^;\s]+) before proceeding; if it fails, call
discardResponseBody(response), log via SystemLogger.info (keep existing fields),
and throw the same Meteor.Error; keep the subsequent use of
bufferResponseWithLimit and DEFAULT_AVATAR_DOWNLOAD_TIMEOUT_MS unchanged.

182-198: ⚠️ Potential issue | 🟠 Major

Map fetch-level timeouts to the timeout error code.

The fetch() call at line 182 can timeout and reject before a Response is available. This rejection is caught at line 188 and unconditionally thrown as error-avatar-invalid-url. However, timeout errors should be reported as error-avatar-download-timeout (which is only mapped for body-reading timeouts at lines 256–261). A fetch-level timeout becomes indistinguishable from a genuinely invalid URL to the client. Wrap the fetch in error-type detection to map abort/timeout errors separately.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/meteor/app/lib/server/functions/setUserAvatar.ts` around lines 182 -
198, The fetch() call in setUserAvatar currently catches all fetch rejections
and always throws 'error-avatar-invalid-url'; change the catch to distinguish
timeout/abort errors from other fetch failures by inspecting the thrown error
(e.g., e.name === 'AbortError' or e.code === 'ETIMEDOUT' or e.type ===
'request-timeout') and, if matched, throw a
Meteor.Error('error-avatar-download-timeout', ...) with the same metadata
(function: 'setUserAvatar', url: dataURI) and a clear message; otherwise keep
the existing SystemLogger.info and throw
Meteor.Error('error-avatar-invalid-url', ...) as before. Ensure this logic wraps
the same fetch(...) call and uses the same response/url variables.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@apps/meteor/app/lib/server/functions/setUserAvatar.ts`:
- Around line 228-245: The MIME-type check currently allows headers that merely
contain "image/" anywhere; update the validation in setUserAvatar to parse the
Content-Type header's media type (trim and strip parameters by splitting on ';'
or matching ^\s*([^\/]+\/[^;\s]+)) and then ensure the media type startsWith
'image/' (or matches ^image\/[^;\s]+) before proceeding; if it fails, call
discardResponseBody(response), log via SystemLogger.info (keep existing fields),
and throw the same Meteor.Error; keep the subsequent use of
bufferResponseWithLimit and DEFAULT_AVATAR_DOWNLOAD_TIMEOUT_MS unchanged.
- Around line 182-198: The fetch() call in setUserAvatar currently catches all
fetch rejections and always throws 'error-avatar-invalid-url'; change the catch
to distinguish timeout/abort errors from other fetch failures by inspecting the
thrown error (e.g., e.name === 'AbortError' or e.code === 'ETIMEDOUT' or e.type
=== 'request-timeout') and, if matched, throw a
Meteor.Error('error-avatar-download-timeout', ...) with the same metadata
(function: 'setUserAvatar', url: dataURI) and a clear message; otherwise keep
the existing SystemLogger.info and throw
Meteor.Error('error-avatar-invalid-url', ...) as before. Ensure this logic wraps
the same fetch(...) call and uses the same response/url variables.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 69385a1c-1044-44f4-bc28-6f02b2c83320

📥 Commits

Reviewing files that changed from the base of the PR and between 855a9de and edb956e.

📒 Files selected for processing (2)
  • apps/meteor/app/lib/server/functions/setUserAvatar.ts
  • apps/meteor/tests/unit/app/lib/server/functions/setUserAvatar.spec.ts
✅ Files skipped from review due to trivial changes (1)
  • apps/meteor/tests/unit/app/lib/server/functions/setUserAvatar.spec.ts
📜 Review details
⏰ 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: cubic · AI code reviewer
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)

**/*.{ts,tsx,js}: Write concise, technical TypeScript/JavaScript with accurate typing in Playwright tests
Avoid code comments in the implementation

Files:

  • apps/meteor/app/lib/server/functions/setUserAvatar.ts
🧠 Learnings (12)
📚 Learning: 2026-03-20T13:51:23.302Z
Learnt from: ggazzo
Repo: RocketChat/Rocket.Chat PR: 39553
File: apps/meteor/app/integrations/server/methods/incoming/updateIncomingIntegration.ts:179-181
Timestamp: 2026-03-20T13:51:23.302Z
Learning: In `apps/meteor/app/integrations/server/methods/incoming/updateIncomingIntegration.ts`, the truthiness guards `...(integration.avatar && { avatar })`, `...(integration.emoji && { emoji })`, `...(integration.alias && { alias })`, and `...(integration.script && { script })` in the `$set` payload of `updateIncomingIntegration` are intentional. Empty-string values for these fields should NOT overwrite the stored value — only truthy values are persisted. Do not flag these as bugs preventing explicit clears.

Applied to files:

  • apps/meteor/app/lib/server/functions/setUserAvatar.ts
📚 Learning: 2026-02-12T15:39:28.416Z
Learnt from: dougfabris
Repo: RocketChat/Rocket.Chat PR: 32703
File: apps/meteor/client/lib/chats/flows/uploadFiles.ts:52-58
Timestamp: 2026-02-12T15:39:28.416Z
Learning: In `apps/meteor/client/lib/chats/flows/uploadFiles.ts`, when E2E encryption is required but not allowed (e.g., `E2E_Enable_Encrypt_Files` setting is disabled), the function intentionally abandons the entire upload queue and displays a toast error. This fail-fast behavior prevents partial uploads when encryption requirements cannot be met and is the expected behavior, not a bug.

Applied to files:

  • apps/meteor/app/lib/server/functions/setUserAvatar.ts
📚 Learning: 2026-03-19T13:59:40.678Z
Learnt from: d-gubert
Repo: RocketChat/Rocket.Chat PR: 38357
File: apps/meteor/app/apps/server/converters/uploads.ts:45-49
Timestamp: 2026-03-19T13:59:40.678Z
Learning: In `apps/meteor/app/apps/server/converters/uploads.ts`, the `room` async handler in `convertToApp` uses non-null assertions (`upload.rid!` and `result!`) intentionally. The data flow guarantees that any upload reaching this point must have a `rid`; if it does not, throwing an error is the desired behavior (fail-fast / data integrity guard). Do not flag these non-null assertions as unsafe during code review.

Applied to files:

  • apps/meteor/app/lib/server/functions/setUserAvatar.ts
📚 Learning: 2026-03-12T17:12:49.121Z
Learnt from: dougfabris
Repo: RocketChat/Rocket.Chat PR: 39425
File: apps/meteor/client/lib/chats/flows/uploadFiles.ts:28-33
Timestamp: 2026-03-12T17:12:49.121Z
Learning: Rocket.Chat — apps/meteor/client/lib/chats/flows/uploadFiles.ts: When E2E_Enable_Encrypt_Files is disabled, plaintext file uploads are allowed in E2E rooms; this fallback is expected and should not be flagged as a security regression.

Applied to files:

  • apps/meteor/app/lib/server/functions/setUserAvatar.ts
📚 Learning: 2026-01-17T01:51:47.764Z
Learnt from: tassoevan
Repo: RocketChat/Rocket.Chat PR: 38219
File: packages/core-typings/src/cloud/Announcement.ts:5-6
Timestamp: 2026-01-17T01:51:47.764Z
Learning: In packages/core-typings/src/cloud/Announcement.ts, the AnnouncementSchema.createdBy field intentionally overrides IBannerSchema.createdBy (object with _id and optional username) with a string enum ['cloud', 'system'] to match existing runtime behavior. This is documented as technical debt with a FIXME comment at apps/meteor/app/cloud/server/functions/syncWorkspace/handleCommsSync.ts:53 and should not be flagged as an error until the runtime behavior is corrected.

Applied to files:

  • apps/meteor/app/lib/server/functions/setUserAvatar.ts
📚 Learning: 2026-04-10T22:42:03.240Z
Learnt from: dougfabris
Repo: RocketChat/Rocket.Chat PR: 40075
File: apps/meteor/client/views/room/modals/FileUploadModal/FileUploadModal.tsx:69-71
Timestamp: 2026-04-10T22:42:03.240Z
Learning: In `apps/meteor/client/views/room/modals/FileUploadModal/FileUploadModal.tsx`, the submit handler converts an empty/whitespace-only description to `undefined` (`description?.trim() || undefined`) intentionally. All downstream image-rendering components (`AttachmentImage`, `ImagePreview`, `ImageItem`, `ImageGallery`) default `undefined` alt to `''`, so the `<img alt="">` attribute is always present. Do not flag this `undefined` conversion as a bug preventing alt text from being cleared.

Applied to files:

  • apps/meteor/app/lib/server/functions/setUserAvatar.ts
📚 Learning: 2026-03-11T18:15:53.272Z
Learnt from: dougfabris
Repo: RocketChat/Rocket.Chat PR: 39425
File: apps/meteor/app/api/server/v1/rooms.ts:294-296
Timestamp: 2026-03-11T18:15:53.272Z
Learning: In Rocket.Chat's `rooms.mediaConfirm/:rid/:fileId` endpoint (apps/meteor/app/api/server/v1/rooms.ts), updating `file.name` from `bodyParams.fileName` without updating `file.path` is intentionally safe. The file path is keyed by `_id` (not by filename), so the stored path remains valid regardless of a rename. `file.name` only affects the display name in the message attachment; do not flag this as a path-divergence issue.

Applied to files:

  • apps/meteor/app/lib/server/functions/setUserAvatar.ts
📚 Learning: 2026-03-18T22:07:19.687Z
Learnt from: d-gubert
Repo: RocketChat/Rocket.Chat PR: 38357
File: apps/meteor/app/apps/server/converters/departments.ts:59-70
Timestamp: 2026-03-18T22:07:19.687Z
Learning: In `apps/meteor/app/apps/server/converters/departments.ts`, the `convertAppDepartment` method uses non-null assertions (`!`) on `department.name`, `department.email`, and `department.offlineMessageChannelName` when constructing `newDepartment: ILivechatDepartment`. These fields are optional on `IAppsDepartment`, but the App framework flow guarantees their presence at the call site. Do not flag these non-null assertions as unsafe during code review.

Applied to files:

  • apps/meteor/app/lib/server/functions/setUserAvatar.ts
📚 Learning: 2026-03-11T18:17:53.972Z
Learnt from: dougfabris
Repo: RocketChat/Rocket.Chat PR: 39425
File: apps/meteor/client/lib/chats/flows/processMessageUploads.ts:112-119
Timestamp: 2026-03-11T18:17:53.972Z
Learning: In `apps/meteor/client/lib/chats/flows/processMessageUploads.ts`, when sending multiple file uploads, each file is confirmed via its own `/rooms.mediaConfirm/${rid}/${fileId}` call and produces a separate message. Only the first file's confirm payload carries the composed message text (`msg`); all subsequent files receive `msg: ''`. This one-message-per-file behavior is intentional by design — do not flag it as a bug or suggest batching into a single message.

Applied to files:

  • apps/meteor/app/lib/server/functions/setUserAvatar.ts
📚 Learning: 2026-03-15T14:31:28.969Z
Learnt from: amitb0ra
Repo: RocketChat/Rocket.Chat PR: 39647
File: apps/meteor/app/api/server/v1/users.ts:710-757
Timestamp: 2026-03-15T14:31:28.969Z
Learning: In RocketChat/Rocket.Chat, the `UserCreateParamsPOST` type in `apps/meteor/app/api/server/v1/users.ts` (migrated from `packages/rest-typings/src/v1/users/UserCreateParamsPOST.ts`) intentionally has `fields: string` (non-optional) and `settings?: IUserSettings` without a corresponding AJV schema entry. This is a pre-existing divergence carried over verbatim from the original rest-typings source (PR `#39647`). Do not flag this type/schema misalignment during the OpenAPI migration review — it is tracked as a separate follow-up fix.

Applied to files:

  • apps/meteor/app/lib/server/functions/setUserAvatar.ts
📚 Learning: 2026-02-26T19:25:44.063Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 38778
File: packages/ui-voip/src/providers/useMediaSession.ts:192-192
Timestamp: 2026-02-26T19:25:44.063Z
Learning: In the Rocket.Chat repository, do not reference Biome lint rules in code review feedback. Biome is not used even if biome.json exists; only reference Biome rules if there is explicit, project-wide usage documented. For TypeScript files, review lint implications without Biome guidance unless the project enables Biome rules.

Applied to files:

  • apps/meteor/app/lib/server/functions/setUserAvatar.ts
📚 Learning: 2026-02-26T19:25:44.063Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 38778
File: packages/ui-voip/src/providers/useMediaSession.ts:192-192
Timestamp: 2026-02-26T19:25:44.063Z
Learning: In this repository (RocketChat/Rocket.Chat), Biome lint rules are not used even if a biome.json exists. When reviewing TypeScript files (e.g., packages/ui-voip/src/providers/useMediaSession.ts), ensure lint suggestions do not reference Biome-specific rules. Rely on general ESLint/TypeScript lint rules and project conventions instead.

Applied to files:

  • apps/meteor/app/lib/server/functions/setUserAvatar.ts

Copy link
Copy Markdown
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/meteor/app/lib/server/functions/setUserAvatar.ts (1)

156-162: Unreachable statement after never-returning function.

throwInvalidAvatarUrl has return type never, making throw error unreachable. Same pattern at line 224.

🧹 Remove unreachable throw statements
 			SystemLogger.info({
 				msg: 'Not a valid response from the avatar url',
 				url: encodeURI(dataURI),
 				err: error,
 			});
 			throwInvalidAvatarUrl(dataURI);
-			throw error;
 		}

And at line 224:

 		SystemLogger.info({
 			msg: 'Error while downloading avatar from provided url',
 			url: encodeURI(dataURI),
 			username: user.username,
 			err: error,
 		});
 		throwAvatarUrlHandling(dataURI, user.username);
-		throw error;
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/meteor/app/lib/server/functions/setUserAvatar.ts` around lines 156 -
162, The code calls throwInvalidAvatarUrl(dataURI) which is typed as never, so
the subsequent throw error; statements are unreachable; remove the redundant
`throw error` lines after the calls to throwInvalidAvatarUrl in setUserAvatar
(the occurrence around the SystemLogger.info block and the second occurrence
near line 224) so only the never-returning throwInvalidAvatarUrl is used and no
unreachable throws remain.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/meteor/app/lib/server/functions/setUserAvatar.ts`:
- Around line 179-184: In setUserAvatar, log statements use raw dataURI in some
SystemLogger.info calls which is inconsistent with other places; update the
logging to always encode the URL by replacing instances of url: dataURI with
url: encodeURI(dataURI) in the SystemLogger.info / SystemLogger.error calls
(e.g., the call before throwInvalidAvatarUrl and the later log) so all logs
consistently use encodeURI(dataURI).

---

Nitpick comments:
In `@apps/meteor/app/lib/server/functions/setUserAvatar.ts`:
- Around line 156-162: The code calls throwInvalidAvatarUrl(dataURI) which is
typed as never, so the subsequent throw error; statements are unreachable;
remove the redundant `throw error` lines after the calls to
throwInvalidAvatarUrl in setUserAvatar (the occurrence around the
SystemLogger.info block and the second occurrence near line 224) so only the
never-returning throwInvalidAvatarUrl is used and no unreachable throws remain.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a4bc6342-9560-499c-8b0c-5e721076029f

📥 Commits

Reviewing files that changed from the base of the PR and between edb956e and 942b5c0.

📒 Files selected for processing (2)
  • apps/meteor/app/lib/server/functions/setUserAvatar.ts
  • apps/meteor/tests/unit/app/lib/server/functions/setUserAvatar.spec.ts
📜 Review details
⏰ 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: cubic · AI code reviewer
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)

**/*.{ts,tsx,js}: Write concise, technical TypeScript/JavaScript with accurate typing in Playwright tests
Avoid code comments in the implementation

Files:

  • apps/meteor/app/lib/server/functions/setUserAvatar.ts
  • apps/meteor/tests/unit/app/lib/server/functions/setUserAvatar.spec.ts
**/*.spec.ts

📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)

**/*.spec.ts: Use descriptive test names that clearly communicate expected behavior in Playwright tests
Use .spec.ts extension for test files (e.g., login.spec.ts)

Files:

  • apps/meteor/tests/unit/app/lib/server/functions/setUserAvatar.spec.ts
🧠 Learnings (25)
📚 Learning: 2026-03-20T13:51:23.302Z
Learnt from: ggazzo
Repo: RocketChat/Rocket.Chat PR: 39553
File: apps/meteor/app/integrations/server/methods/incoming/updateIncomingIntegration.ts:179-181
Timestamp: 2026-03-20T13:51:23.302Z
Learning: In `apps/meteor/app/integrations/server/methods/incoming/updateIncomingIntegration.ts`, the truthiness guards `...(integration.avatar && { avatar })`, `...(integration.emoji && { emoji })`, `...(integration.alias && { alias })`, and `...(integration.script && { script })` in the `$set` payload of `updateIncomingIntegration` are intentional. Empty-string values for these fields should NOT overwrite the stored value — only truthy values are persisted. Do not flag these as bugs preventing explicit clears.

Applied to files:

  • apps/meteor/app/lib/server/functions/setUserAvatar.ts
  • apps/meteor/tests/unit/app/lib/server/functions/setUserAvatar.spec.ts
📚 Learning: 2026-02-12T15:39:28.416Z
Learnt from: dougfabris
Repo: RocketChat/Rocket.Chat PR: 32703
File: apps/meteor/client/lib/chats/flows/uploadFiles.ts:52-58
Timestamp: 2026-02-12T15:39:28.416Z
Learning: In `apps/meteor/client/lib/chats/flows/uploadFiles.ts`, when E2E encryption is required but not allowed (e.g., `E2E_Enable_Encrypt_Files` setting is disabled), the function intentionally abandons the entire upload queue and displays a toast error. This fail-fast behavior prevents partial uploads when encryption requirements cannot be met and is the expected behavior, not a bug.

Applied to files:

  • apps/meteor/app/lib/server/functions/setUserAvatar.ts
  • apps/meteor/tests/unit/app/lib/server/functions/setUserAvatar.spec.ts
📚 Learning: 2026-03-19T13:59:40.678Z
Learnt from: d-gubert
Repo: RocketChat/Rocket.Chat PR: 38357
File: apps/meteor/app/apps/server/converters/uploads.ts:45-49
Timestamp: 2026-03-19T13:59:40.678Z
Learning: In `apps/meteor/app/apps/server/converters/uploads.ts`, the `room` async handler in `convertToApp` uses non-null assertions (`upload.rid!` and `result!`) intentionally. The data flow guarantees that any upload reaching this point must have a `rid`; if it does not, throwing an error is the desired behavior (fail-fast / data integrity guard). Do not flag these non-null assertions as unsafe during code review.

Applied to files:

  • apps/meteor/app/lib/server/functions/setUserAvatar.ts
📚 Learning: 2026-03-12T17:12:49.121Z
Learnt from: dougfabris
Repo: RocketChat/Rocket.Chat PR: 39425
File: apps/meteor/client/lib/chats/flows/uploadFiles.ts:28-33
Timestamp: 2026-03-12T17:12:49.121Z
Learning: Rocket.Chat — apps/meteor/client/lib/chats/flows/uploadFiles.ts: When E2E_Enable_Encrypt_Files is disabled, plaintext file uploads are allowed in E2E rooms; this fallback is expected and should not be flagged as a security regression.

Applied to files:

  • apps/meteor/app/lib/server/functions/setUserAvatar.ts
📚 Learning: 2026-01-17T01:51:47.764Z
Learnt from: tassoevan
Repo: RocketChat/Rocket.Chat PR: 38219
File: packages/core-typings/src/cloud/Announcement.ts:5-6
Timestamp: 2026-01-17T01:51:47.764Z
Learning: In packages/core-typings/src/cloud/Announcement.ts, the AnnouncementSchema.createdBy field intentionally overrides IBannerSchema.createdBy (object with _id and optional username) with a string enum ['cloud', 'system'] to match existing runtime behavior. This is documented as technical debt with a FIXME comment at apps/meteor/app/cloud/server/functions/syncWorkspace/handleCommsSync.ts:53 and should not be flagged as an error until the runtime behavior is corrected.

Applied to files:

  • apps/meteor/app/lib/server/functions/setUserAvatar.ts
📚 Learning: 2026-04-10T22:42:03.240Z
Learnt from: dougfabris
Repo: RocketChat/Rocket.Chat PR: 40075
File: apps/meteor/client/views/room/modals/FileUploadModal/FileUploadModal.tsx:69-71
Timestamp: 2026-04-10T22:42:03.240Z
Learning: In `apps/meteor/client/views/room/modals/FileUploadModal/FileUploadModal.tsx`, the submit handler converts an empty/whitespace-only description to `undefined` (`description?.trim() || undefined`) intentionally. All downstream image-rendering components (`AttachmentImage`, `ImagePreview`, `ImageItem`, `ImageGallery`) default `undefined` alt to `''`, so the `<img alt="">` attribute is always present. Do not flag this `undefined` conversion as a bug preventing alt text from being cleared.

Applied to files:

  • apps/meteor/app/lib/server/functions/setUserAvatar.ts
📚 Learning: 2026-03-11T18:15:53.272Z
Learnt from: dougfabris
Repo: RocketChat/Rocket.Chat PR: 39425
File: apps/meteor/app/api/server/v1/rooms.ts:294-296
Timestamp: 2026-03-11T18:15:53.272Z
Learning: In Rocket.Chat's `rooms.mediaConfirm/:rid/:fileId` endpoint (apps/meteor/app/api/server/v1/rooms.ts), updating `file.name` from `bodyParams.fileName` without updating `file.path` is intentionally safe. The file path is keyed by `_id` (not by filename), so the stored path remains valid regardless of a rename. `file.name` only affects the display name in the message attachment; do not flag this as a path-divergence issue.

Applied to files:

  • apps/meteor/app/lib/server/functions/setUserAvatar.ts
📚 Learning: 2026-03-11T18:17:53.972Z
Learnt from: dougfabris
Repo: RocketChat/Rocket.Chat PR: 39425
File: apps/meteor/client/lib/chats/flows/processMessageUploads.ts:112-119
Timestamp: 2026-03-11T18:17:53.972Z
Learning: In `apps/meteor/client/lib/chats/flows/processMessageUploads.ts`, when sending multiple file uploads, each file is confirmed via its own `/rooms.mediaConfirm/${rid}/${fileId}` call and produces a separate message. Only the first file's confirm payload carries the composed message text (`msg`); all subsequent files receive `msg: ''`. This one-message-per-file behavior is intentional by design — do not flag it as a bug or suggest batching into a single message.

Applied to files:

  • apps/meteor/app/lib/server/functions/setUserAvatar.ts
📚 Learning: 2026-03-18T22:07:19.687Z
Learnt from: d-gubert
Repo: RocketChat/Rocket.Chat PR: 38357
File: apps/meteor/app/apps/server/converters/departments.ts:59-70
Timestamp: 2026-03-18T22:07:19.687Z
Learning: In `apps/meteor/app/apps/server/converters/departments.ts`, the `convertAppDepartment` method uses non-null assertions (`!`) on `department.name`, `department.email`, and `department.offlineMessageChannelName` when constructing `newDepartment: ILivechatDepartment`. These fields are optional on `IAppsDepartment`, but the App framework flow guarantees their presence at the call site. Do not flag these non-null assertions as unsafe during code review.

Applied to files:

  • apps/meteor/app/lib/server/functions/setUserAvatar.ts
📚 Learning: 2026-03-15T14:31:28.969Z
Learnt from: amitb0ra
Repo: RocketChat/Rocket.Chat PR: 39647
File: apps/meteor/app/api/server/v1/users.ts:710-757
Timestamp: 2026-03-15T14:31:28.969Z
Learning: In RocketChat/Rocket.Chat, the `UserCreateParamsPOST` type in `apps/meteor/app/api/server/v1/users.ts` (migrated from `packages/rest-typings/src/v1/users/UserCreateParamsPOST.ts`) intentionally has `fields: string` (non-optional) and `settings?: IUserSettings` without a corresponding AJV schema entry. This is a pre-existing divergence carried over verbatim from the original rest-typings source (PR `#39647`). Do not flag this type/schema misalignment during the OpenAPI migration review — it is tracked as a separate follow-up fix.

Applied to files:

  • apps/meteor/app/lib/server/functions/setUserAvatar.ts
  • apps/meteor/tests/unit/app/lib/server/functions/setUserAvatar.spec.ts
📚 Learning: 2026-03-14T14:58:58.834Z
Learnt from: smirk-dev
Repo: RocketChat/Rocket.Chat PR: 39625
File: apps/meteor/app/api/server/v1/push.ts:85-97
Timestamp: 2026-03-14T14:58:58.834Z
Learning: In RocketChat/Rocket.Chat, the `push.token` POST/DELETE endpoints in `apps/meteor/app/api/server/v1/push.ts` were already migrated to the chained router API pattern on `develop` prior to PR `#39625`. `cleanTokenResult` (which strips `authToken` and returns `PushTokenResult`) and `isPushTokenPOSTProps`/`isPushTokenDELETEProps` validators already exist on `develop`. PR `#39625` only migrates `push.get` and `push.info` to the chained pattern. Do not flag `cleanTokenResult` or `PushTokenResult` as newly introduced behavior-breaking changes when reviewing this PR.

Applied to files:

  • apps/meteor/app/lib/server/functions/setUserAvatar.ts
📚 Learning: 2026-02-23T17:53:18.785Z
Learnt from: ggazzo
Repo: RocketChat/Rocket.Chat PR: 35995
File: apps/meteor/app/api/server/v1/rooms.ts:1107-1112
Timestamp: 2026-02-23T17:53:18.785Z
Learning: In Rocket.Chat PR reviews, maintain strict scope boundaries—when a PR is focused on a specific endpoint (e.g., rooms.favorite), avoid reviewing or suggesting changes to other endpoints that were incidentally refactored (e.g., rooms.invite) unless explicitly requested by maintainers.

Applied to files:

  • apps/meteor/app/lib/server/functions/setUserAvatar.ts
📚 Learning: 2026-03-10T08:13:52.153Z
Learnt from: ahmed-n-abdeltwab
Repo: RocketChat/Rocket.Chat PR: 39414
File: apps/meteor/app/api/server/v1/rooms.ts:1241-1297
Timestamp: 2026-03-10T08:13:52.153Z
Learning: In the RocketChat/Rocket.Chat OpenAPI migration PRs for endpoints under apps/meteor/app/api/server/v1/rooms.ts, the pattern `ajv.compile<void>({...})` is intentionally used for the 200 response schema even when the endpoint returns `{ success: true }`. This is an established convention across all migrated endpoints (rooms.leave, rooms.favorite, rooms.delete, rooms.muteUser, rooms.unmuteUser). Do not flag this as a type mismatch during reviews of these migration PRs.

Applied to files:

  • apps/meteor/app/lib/server/functions/setUserAvatar.ts
📚 Learning: 2026-02-26T19:25:44.063Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 38778
File: packages/ui-voip/src/providers/useMediaSession.ts:192-192
Timestamp: 2026-02-26T19:25:44.063Z
Learning: In the Rocket.Chat repository, do not reference Biome lint rules in code review feedback. Biome is not used even if biome.json exists; only reference Biome rules if there is explicit, project-wide usage documented. For TypeScript files, review lint implications without Biome guidance unless the project enables Biome rules.

Applied to files:

  • apps/meteor/app/lib/server/functions/setUserAvatar.ts
  • apps/meteor/tests/unit/app/lib/server/functions/setUserAvatar.spec.ts
📚 Learning: 2026-02-26T19:25:44.063Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 38778
File: packages/ui-voip/src/providers/useMediaSession.ts:192-192
Timestamp: 2026-02-26T19:25:44.063Z
Learning: In this repository (RocketChat/Rocket.Chat), Biome lint rules are not used even if a biome.json exists. When reviewing TypeScript files (e.g., packages/ui-voip/src/providers/useMediaSession.ts), ensure lint suggestions do not reference Biome-specific rules. Rely on general ESLint/TypeScript lint rules and project conventions instead.

Applied to files:

  • apps/meteor/app/lib/server/functions/setUserAvatar.ts
  • apps/meteor/tests/unit/app/lib/server/functions/setUserAvatar.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Utilize Playwright fixtures (`test`, `page`, `expect`) for consistency in test files

Applied to files:

  • apps/meteor/tests/unit/app/lib/server/functions/setUserAvatar.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Ensure tests run reliably in parallel without shared state conflicts

Applied to files:

  • apps/meteor/tests/unit/app/lib/server/functions/setUserAvatar.spec.ts
📚 Learning: 2025-10-06T20:30:45.540Z
Learnt from: d-gubert
Repo: RocketChat/Rocket.Chat PR: 37152
File: packages/apps-engine/tests/test-data/storage/storage.ts:101-122
Timestamp: 2025-10-06T20:30:45.540Z
Learning: In `packages/apps-engine/tests/test-data/storage/storage.ts`, the stub methods (updatePartialAndReturnDocument, updateStatus, updateSetting, updateAppInfo, updateMarketplaceInfo) intentionally throw "Method not implemented." Tests using these methods must stub them using `SpyOn` from the test library rather than relying on actual implementations.

Applied to files:

  • apps/meteor/tests/unit/app/lib/server/functions/setUserAvatar.spec.ts
📚 Learning: 2026-03-06T18:09:17.867Z
Learnt from: tassoevan
Repo: RocketChat/Rocket.Chat PR: 39397
File: packages/gazzodown/src/elements/Timestamp/DateTimeFormats.spec.tsx:20-23
Timestamp: 2026-03-06T18:09:17.867Z
Learning: In the RocketChat/Rocket.Chat gazzodown package (`packages/gazzodown`), tests are intended to run under the UTC timezone, but as of PR `#39397` this is NOT yet explicitly enforced in `jest.config.ts` or the `package.json` test scripts (which just run `jest` without `TZ=UTC`). To make timezone-sensitive snapshot tests reliable across all environments, `TZ=UTC` should be added to the test scripts in `package.json` or to `jest.config.ts` via `testEnvironmentOptions.timezone`. Without explicit UTC enforcement, snapshot tests involving date-fns formatted output or `toLocaleString()` will fail for contributors in non-UTC timezones.

Applied to files:

  • apps/meteor/tests/unit/app/lib/server/functions/setUserAvatar.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Group related tests in the same file

Applied to files:

  • apps/meteor/tests/unit/app/lib/server/functions/setUserAvatar.spec.ts
📚 Learning: 2026-03-16T11:57:17.987Z
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 39657
File: apps/meteor/tests/end-to-end/apps/app-resolve-visitor.ts:43-45
Timestamp: 2026-03-16T11:57:17.987Z
Learning: In `apps/meteor/tests/end-to-end/apps/app-resolve-visitor.ts`, `externalIds` lookups are namespaced per `app.id`. Because `cleanupApps()` is called before each test run and a fresh app is installed (giving a new unique `app.id`), fixed `userId` strings like `'nonexistent-id'` in null-path tests are safe and cannot collide with stale visitor records from previous runs. Do not flag these as needing unique/random values.

Applied to files:

  • apps/meteor/tests/unit/app/lib/server/functions/setUserAvatar.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : All test files must be created in `apps/meteor/tests/e2e/` directory

Applied to files:

  • apps/meteor/tests/unit/app/lib/server/functions/setUserAvatar.spec.ts
📚 Learning: 2025-12-10T21:00:54.909Z
Learnt from: KevLehman
Repo: RocketChat/Rocket.Chat PR: 37091
File: ee/packages/abac/jest.config.ts:4-7
Timestamp: 2025-12-10T21:00:54.909Z
Learning: Rocket.Chat monorepo: Jest testMatch pattern '<rootDir>/src/**/*.spec.(ts|js|mjs)' is valid in this repo and used across multiple packages (e.g., packages/tools, ee/packages/omnichannel-services). Do not flag it as invalid in future reviews.

Applied to files:

  • apps/meteor/tests/unit/app/lib/server/functions/setUserAvatar.spec.ts
📚 Learning: 2026-02-24T19:22:48.358Z
Learnt from: juliajforesti
Repo: RocketChat/Rocket.Chat PR: 38493
File: apps/meteor/tests/e2e/omnichannel/omnichannel-send-pdf-transcript.spec.ts:66-67
Timestamp: 2026-02-24T19:22:48.358Z
Learning: In Playwright end-to-end tests (e.g., under apps/meteor/tests/e2e/...), prefer locating elements by translated text (getByText) and ARIA roles (getByRole) over data-qa attributes. If translation values change, update the corresponding test locators accordingly. Never use data-qa locators. This guideline applies to all Playwright e2e test specs in the repository and helps keep tests robust to UI text changes and accessible semantics.

Applied to files:

  • apps/meteor/tests/unit/app/lib/server/functions/setUserAvatar.spec.ts
📚 Learning: 2026-03-06T18:10:15.268Z
Learnt from: tassoevan
Repo: RocketChat/Rocket.Chat PR: 39397
File: packages/gazzodown/src/code/CodeBlock.spec.tsx:47-68
Timestamp: 2026-03-06T18:10:15.268Z
Learning: In tests (especially those using testing-library/dom/jsdom) for Rocket.Chat components, the HTML <code> element has an implicit ARIA role of 'code'. Therefore, screen.getByRole('code') or screen.findByRole('code') will locate <code> elements even without a role attribute. Do not flag findByRole('code') as invalid in reviews; prefer using the implicit role instead of adding role="code" unless necessary for accessibility.

Applied to files:

  • apps/meteor/tests/unit/app/lib/server/functions/setUserAvatar.spec.ts
🔇 Additional comments (4)
apps/meteor/app/lib/server/functions/setUserAvatar.ts (3)

78-137: Streaming buffer implementation with size and timeout limits looks solid.

The bufferResponseWithLimit function properly:

  • Validates Content-Length upfront before streaming
  • Enforces byte limit during streaming with early abort
  • Implements timeout for hanging downloads
  • Cleans up event listeners and destroys the stream on rejection

This addresses the P1 vulnerability by preventing unbounded memory consumption.


139-226: URL fetching with SSRF protection, content-type validation, and proper error mapping.

The getAvatarFromUrl function correctly:

  • Uses ignoreSsrfValidation: false with the allowlist
  • Validates response is image/* content-type
  • Discards response body on non-200 and invalid content-type to prevent leaks
  • Maps errors to appropriate Meteor.Error codes for timeout, size limit, and invalid URL

345-347: Good defensive guard before deleteByName.

The explicit if (user.username) check prevents calling deleteByName with undefined, which aligns with the type narrowing needed here.

apps/meteor/tests/unit/app/lib/server/functions/setUserAvatar.spec.ts (1)

102-258: Comprehensive test coverage for the security fix.

The test suite thoroughly validates:

  • Size limit enforcement via Content-Length and streaming byte count
  • Content-type validation including bypass attempts (text/plain; note=image/png)
  • Timeout handling with fake timers and AbortError mapping
  • Fallback behavior when FileUpload_MaxFileSize is negative
  • Success path verifying buffer content and file metadata

All assertions correctly verify that fileStore.insert is not called on rejection paths.

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

2 issues found across 2 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/meteor/app/lib/server/functions/setUserAvatar.ts">

<violation number="1" location="apps/meteor/app/lib/server/functions/setUserAvatar.ts:51">
P3: Inconsistent URL encoding in log statements. Other `SystemLogger.info` calls in this function encode the URL with `encodeURI(dataURI)`, but this one (and the content-type log below) pass it raw. Use `encodeURI(dataURI)` here for consistency and to prevent log injection from crafted URLs.</violation>

<violation number="2" location="apps/meteor/app/lib/server/functions/setUserAvatar.ts:162">
P3: Unreachable `throw error` remains after a `never`-returning helper call, leaving dead code in error paths.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

@coderabbitai coderabbitai bot removed the type: bug label Apr 14, 2026
Copy link
Copy Markdown
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: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/meteor/app/lib/server/functions/setUserAvatar.ts`:
- Around line 156-160: The logs in setUserAvatar.ts leak sensitive data by
logging encodeURI(dataURI); update the logging to redact sensitive parts of the
avatar URL before passing to SystemLogger (e.g., remove username/password, mask
or drop query strings, and hide any token-like path/query values). Add or call a
small helper (e.g., redactUrl or normalizeAvatarUrl) and use it wherever
SystemLogger.info/error currently logs encodeURI(dataURI) (references: the
SystemLogger.info calls around dataURI and the function setUserAvatar). Ensure
all other instances noted (lines near 170-175, 179-183, 191-195, 217-222) use
the redaction helper so no raw credentials or signed query params are logged.
- Around line 125-128: In the bufferResponseWithLimit catch handler (the handler
used to read response.body), detect stream-level timeout errors using the
existing isRequestTimeoutError(error) helper (same pattern used in the
fetch-level timeout handler) and map those errors to the
'error-avatar-download-timeout' code instead of letting them fall through to
throwAvatarUrlHandling; adjust the catch branch that currently only checks
AVATAR_RESPONSE_TIMEOUT so that when isRequestTimeoutError(error) is true you
call reject/create the timeout error with 'error-avatar-download-timeout'
(referencing bufferResponseWithLimit, AVATAR_RESPONSE_TIMEOUT,
isRequestTimeoutError, and throwAvatarUrlHandling to locate the logic).
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b6b172dd-718c-4a6d-8415-8d8e0d0ff244

📥 Commits

Reviewing files that changed from the base of the PR and between 942b5c0 and cef0dda.

📒 Files selected for processing (1)
  • apps/meteor/app/lib/server/functions/setUserAvatar.ts
📜 Review details
⏰ 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: cubic · AI code reviewer
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)

**/*.{ts,tsx,js}: Write concise, technical TypeScript/JavaScript with accurate typing in Playwright tests
Avoid code comments in the implementation

Files:

  • apps/meteor/app/lib/server/functions/setUserAvatar.ts
🧠 Learnings (19)
📚 Learning: 2026-03-20T13:51:23.302Z
Learnt from: ggazzo
Repo: RocketChat/Rocket.Chat PR: 39553
File: apps/meteor/app/integrations/server/methods/incoming/updateIncomingIntegration.ts:179-181
Timestamp: 2026-03-20T13:51:23.302Z
Learning: In `apps/meteor/app/integrations/server/methods/incoming/updateIncomingIntegration.ts`, the truthiness guards `...(integration.avatar && { avatar })`, `...(integration.emoji && { emoji })`, `...(integration.alias && { alias })`, and `...(integration.script && { script })` in the `$set` payload of `updateIncomingIntegration` are intentional. Empty-string values for these fields should NOT overwrite the stored value — only truthy values are persisted. Do not flag these as bugs preventing explicit clears.

Applied to files:

  • apps/meteor/app/lib/server/functions/setUserAvatar.ts
📚 Learning: 2026-04-10T22:42:03.240Z
Learnt from: dougfabris
Repo: RocketChat/Rocket.Chat PR: 40075
File: apps/meteor/client/views/room/modals/FileUploadModal/FileUploadModal.tsx:69-71
Timestamp: 2026-04-10T22:42:03.240Z
Learning: In `apps/meteor/client/views/room/modals/FileUploadModal/FileUploadModal.tsx`, the submit handler converts an empty/whitespace-only description to `undefined` (`description?.trim() || undefined`) intentionally. All downstream image-rendering components (`AttachmentImage`, `ImagePreview`, `ImageItem`, `ImageGallery`) default `undefined` alt to `''`, so the `<img alt="">` attribute is always present. Do not flag this `undefined` conversion as a bug preventing alt text from being cleared.

Applied to files:

  • apps/meteor/app/lib/server/functions/setUserAvatar.ts
📚 Learning: 2026-02-12T15:39:28.416Z
Learnt from: dougfabris
Repo: RocketChat/Rocket.Chat PR: 32703
File: apps/meteor/client/lib/chats/flows/uploadFiles.ts:52-58
Timestamp: 2026-02-12T15:39:28.416Z
Learning: In `apps/meteor/client/lib/chats/flows/uploadFiles.ts`, when E2E encryption is required but not allowed (e.g., `E2E_Enable_Encrypt_Files` setting is disabled), the function intentionally abandons the entire upload queue and displays a toast error. This fail-fast behavior prevents partial uploads when encryption requirements cannot be met and is the expected behavior, not a bug.

Applied to files:

  • apps/meteor/app/lib/server/functions/setUserAvatar.ts
📚 Learning: 2026-03-19T13:59:40.678Z
Learnt from: d-gubert
Repo: RocketChat/Rocket.Chat PR: 38357
File: apps/meteor/app/apps/server/converters/uploads.ts:45-49
Timestamp: 2026-03-19T13:59:40.678Z
Learning: In `apps/meteor/app/apps/server/converters/uploads.ts`, the `room` async handler in `convertToApp` uses non-null assertions (`upload.rid!` and `result!`) intentionally. The data flow guarantees that any upload reaching this point must have a `rid`; if it does not, throwing an error is the desired behavior (fail-fast / data integrity guard). Do not flag these non-null assertions as unsafe during code review.

Applied to files:

  • apps/meteor/app/lib/server/functions/setUserAvatar.ts
📚 Learning: 2026-03-12T17:12:49.121Z
Learnt from: dougfabris
Repo: RocketChat/Rocket.Chat PR: 39425
File: apps/meteor/client/lib/chats/flows/uploadFiles.ts:28-33
Timestamp: 2026-03-12T17:12:49.121Z
Learning: Rocket.Chat — apps/meteor/client/lib/chats/flows/uploadFiles.ts: When E2E_Enable_Encrypt_Files is disabled, plaintext file uploads are allowed in E2E rooms; this fallback is expected and should not be flagged as a security regression.

Applied to files:

  • apps/meteor/app/lib/server/functions/setUserAvatar.ts
📚 Learning: 2026-01-17T01:51:47.764Z
Learnt from: tassoevan
Repo: RocketChat/Rocket.Chat PR: 38219
File: packages/core-typings/src/cloud/Announcement.ts:5-6
Timestamp: 2026-01-17T01:51:47.764Z
Learning: In packages/core-typings/src/cloud/Announcement.ts, the AnnouncementSchema.createdBy field intentionally overrides IBannerSchema.createdBy (object with _id and optional username) with a string enum ['cloud', 'system'] to match existing runtime behavior. This is documented as technical debt with a FIXME comment at apps/meteor/app/cloud/server/functions/syncWorkspace/handleCommsSync.ts:53 and should not be flagged as an error until the runtime behavior is corrected.

Applied to files:

  • apps/meteor/app/lib/server/functions/setUserAvatar.ts
📚 Learning: 2026-03-11T18:15:53.272Z
Learnt from: dougfabris
Repo: RocketChat/Rocket.Chat PR: 39425
File: apps/meteor/app/api/server/v1/rooms.ts:294-296
Timestamp: 2026-03-11T18:15:53.272Z
Learning: In Rocket.Chat's `rooms.mediaConfirm/:rid/:fileId` endpoint (apps/meteor/app/api/server/v1/rooms.ts), updating `file.name` from `bodyParams.fileName` without updating `file.path` is intentionally safe. The file path is keyed by `_id` (not by filename), so the stored path remains valid regardless of a rename. `file.name` only affects the display name in the message attachment; do not flag this as a path-divergence issue.

Applied to files:

  • apps/meteor/app/lib/server/functions/setUserAvatar.ts
📚 Learning: 2026-03-11T18:17:53.972Z
Learnt from: dougfabris
Repo: RocketChat/Rocket.Chat PR: 39425
File: apps/meteor/client/lib/chats/flows/processMessageUploads.ts:112-119
Timestamp: 2026-03-11T18:17:53.972Z
Learning: In `apps/meteor/client/lib/chats/flows/processMessageUploads.ts`, when sending multiple file uploads, each file is confirmed via its own `/rooms.mediaConfirm/${rid}/${fileId}` call and produces a separate message. Only the first file's confirm payload carries the composed message text (`msg`); all subsequent files receive `msg: ''`. This one-message-per-file behavior is intentional by design — do not flag it as a bug or suggest batching into a single message.

Applied to files:

  • apps/meteor/app/lib/server/functions/setUserAvatar.ts
📚 Learning: 2026-03-18T22:07:19.687Z
Learnt from: d-gubert
Repo: RocketChat/Rocket.Chat PR: 38357
File: apps/meteor/app/apps/server/converters/departments.ts:59-70
Timestamp: 2026-03-18T22:07:19.687Z
Learning: In `apps/meteor/app/apps/server/converters/departments.ts`, the `convertAppDepartment` method uses non-null assertions (`!`) on `department.name`, `department.email`, and `department.offlineMessageChannelName` when constructing `newDepartment: ILivechatDepartment`. These fields are optional on `IAppsDepartment`, but the App framework flow guarantees their presence at the call site. Do not flag these non-null assertions as unsafe during code review.

Applied to files:

  • apps/meteor/app/lib/server/functions/setUserAvatar.ts
📚 Learning: 2026-03-15T14:31:28.969Z
Learnt from: amitb0ra
Repo: RocketChat/Rocket.Chat PR: 39647
File: apps/meteor/app/api/server/v1/users.ts:710-757
Timestamp: 2026-03-15T14:31:28.969Z
Learning: In RocketChat/Rocket.Chat, the `UserCreateParamsPOST` type in `apps/meteor/app/api/server/v1/users.ts` (migrated from `packages/rest-typings/src/v1/users/UserCreateParamsPOST.ts`) intentionally has `fields: string` (non-optional) and `settings?: IUserSettings` without a corresponding AJV schema entry. This is a pre-existing divergence carried over verbatim from the original rest-typings source (PR `#39647`). Do not flag this type/schema misalignment during the OpenAPI migration review — it is tracked as a separate follow-up fix.

Applied to files:

  • apps/meteor/app/lib/server/functions/setUserAvatar.ts
📚 Learning: 2026-03-14T14:58:58.834Z
Learnt from: smirk-dev
Repo: RocketChat/Rocket.Chat PR: 39625
File: apps/meteor/app/api/server/v1/push.ts:85-97
Timestamp: 2026-03-14T14:58:58.834Z
Learning: In RocketChat/Rocket.Chat, the `push.token` POST/DELETE endpoints in `apps/meteor/app/api/server/v1/push.ts` were already migrated to the chained router API pattern on `develop` prior to PR `#39625`. `cleanTokenResult` (which strips `authToken` and returns `PushTokenResult`) and `isPushTokenPOSTProps`/`isPushTokenDELETEProps` validators already exist on `develop`. PR `#39625` only migrates `push.get` and `push.info` to the chained pattern. Do not flag `cleanTokenResult` or `PushTokenResult` as newly introduced behavior-breaking changes when reviewing this PR.

Applied to files:

  • apps/meteor/app/lib/server/functions/setUserAvatar.ts
📚 Learning: 2026-02-23T17:53:18.785Z
Learnt from: ggazzo
Repo: RocketChat/Rocket.Chat PR: 35995
File: apps/meteor/app/api/server/v1/rooms.ts:1107-1112
Timestamp: 2026-02-23T17:53:18.785Z
Learning: In Rocket.Chat PR reviews, maintain strict scope boundaries—when a PR is focused on a specific endpoint (e.g., rooms.favorite), avoid reviewing or suggesting changes to other endpoints that were incidentally refactored (e.g., rooms.invite) unless explicitly requested by maintainers.

Applied to files:

  • apps/meteor/app/lib/server/functions/setUserAvatar.ts
📚 Learning: 2026-03-10T08:13:52.153Z
Learnt from: ahmed-n-abdeltwab
Repo: RocketChat/Rocket.Chat PR: 39414
File: apps/meteor/app/api/server/v1/rooms.ts:1241-1297
Timestamp: 2026-03-10T08:13:52.153Z
Learning: In the RocketChat/Rocket.Chat OpenAPI migration PRs for endpoints under apps/meteor/app/api/server/v1/rooms.ts, the pattern `ajv.compile<void>({...})` is intentionally used for the 200 response schema even when the endpoint returns `{ success: true }`. This is an established convention across all migrated endpoints (rooms.leave, rooms.favorite, rooms.delete, rooms.muteUser, rooms.unmuteUser). Do not flag this as a type mismatch during reviews of these migration PRs.

Applied to files:

  • apps/meteor/app/lib/server/functions/setUserAvatar.ts
📚 Learning: 2026-02-24T19:09:09.561Z
Learnt from: ahmed-n-abdeltwab
Repo: RocketChat/Rocket.Chat PR: 38974
File: apps/meteor/app/api/server/v1/im.ts:220-221
Timestamp: 2026-02-24T19:09:09.561Z
Learning: In RocketChat/Rocket.Chat OpenAPI migration PRs for apps/meteor/app/api/server/v1 endpoints, maintainers prefer to avoid any logic changes; style-only cleanups (like removing inline comments) may be deferred to follow-ups to keep scope tight.

Applied to files:

  • apps/meteor/app/lib/server/functions/setUserAvatar.ts
📚 Learning: 2026-03-06T18:10:23.330Z
Learnt from: tassoevan
Repo: RocketChat/Rocket.Chat PR: 39397
File: packages/gazzodown/src/code/CodeBlock.spec.tsx:47-68
Timestamp: 2026-03-06T18:10:23.330Z
Learning: In the RocketChat/Rocket.Chat `packages/gazzodown` package and more broadly, the HTML `<code>` element has an implicit ARIA role of `code` per WAI-ARIA 1.3, and `testing-library/dom` / jsdom supports it. Therefore, `screen.getByRole('code')` / `screen.findByRole('code')` correctly locates `<code>` elements without needing an explicit `role="code"` attribute. Do NOT flag `findByRole('code')` as invalid in future reviews.

Applied to files:

  • apps/meteor/app/lib/server/functions/setUserAvatar.ts
📚 Learning: 2026-04-10T21:17:19.306Z
Learnt from: d-gubert
Repo: RocketChat/Rocket.Chat PR: 40096
File: apps/meteor/ee/server/apps/lib/redactor.ts:3-17
Timestamp: 2026-04-10T21:17:19.306Z
Learning: In RocketChat/Rocket.Chat, `X-User-Id` / `x-user-id` headers must NOT be added to redaction paths in apps log redaction (e.g., `apps/meteor/ee/server/apps/lib/redactor.ts`). The maintainer (d-gubert) has confirmed that X-User-Id is an identifier, not a credential — its presence in logs is useful for diagnostics, and `X-Auth-Token` is the only header that constitutes a real secret. Do not suggest redacting X-User-Id in future reviews of this area.

Applied to files:

  • apps/meteor/app/lib/server/functions/setUserAvatar.ts
📚 Learning: 2026-01-16T22:56:30.299Z
Learnt from: dougfabris
Repo: RocketChat/Rocket.Chat PR: 38224
File: apps/meteor/client/views/admin/viewLogs/AnalyticsReports.tsx:15-20
Timestamp: 2026-01-16T22:56:30.299Z
Learning: For the logs documentation link in apps/meteor/client/lib/links.ts, the correct URL slug is `/i/logs-docs` (plural), not `/i/logs-doc` (singular).

Applied to files:

  • apps/meteor/app/lib/server/functions/setUserAvatar.ts
📚 Learning: 2026-02-26T19:25:44.063Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 38778
File: packages/ui-voip/src/providers/useMediaSession.ts:192-192
Timestamp: 2026-02-26T19:25:44.063Z
Learning: In the Rocket.Chat repository, do not reference Biome lint rules in code review feedback. Biome is not used even if biome.json exists; only reference Biome rules if there is explicit, project-wide usage documented. For TypeScript files, review lint implications without Biome guidance unless the project enables Biome rules.

Applied to files:

  • apps/meteor/app/lib/server/functions/setUserAvatar.ts
📚 Learning: 2026-02-26T19:25:44.063Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 38778
File: packages/ui-voip/src/providers/useMediaSession.ts:192-192
Timestamp: 2026-02-26T19:25:44.063Z
Learning: In this repository (RocketChat/Rocket.Chat), Biome lint rules are not used even if a biome.json exists. When reviewing TypeScript files (e.g., packages/ui-voip/src/providers/useMediaSession.ts), ensure lint suggestions do not reference Biome-specific rules. Rely on general ESLint/TypeScript lint rules and project conventions instead.

Applied to files:

  • apps/meteor/app/lib/server/functions/setUserAvatar.ts
🔇 Additional comments (1)
apps/meteor/app/lib/server/functions/setUserAvatar.ts (1)

42-46: Nice max-size fallback.

The finite/positive guard keeps the limiter predictable even when the setting is unset or non-positive.

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 1 file (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/meteor/app/lib/server/functions/setUserAvatar.ts">

<violation number="1" location="apps/meteor/app/lib/server/functions/setUserAvatar.ts:55">
P2: `redactUrl` returns raw input on URL-parse failure, so malformed user-supplied avatar URLs are logged unsanitized in the new logging paths.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.


return parsed.toString();
} catch {
return url;
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot Apr 14, 2026

Choose a reason for hiding this comment

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

P2: redactUrl returns raw input on URL-parse failure, so malformed user-supplied avatar URLs are logged unsanitized in the new logging paths.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/meteor/app/lib/server/functions/setUserAvatar.ts, line 55:

<comment>`redactUrl` returns raw input on URL-parse failure, so malformed user-supplied avatar URLs are logged unsanitized in the new logging paths.</comment>

<file context>
@@ -39,6 +39,23 @@ const isRequestTimeoutError = (error: unknown): boolean => {
+
+		return parsed.toString();
+	} catch {
+		return url;
+	}
+};
</file context>
Fix with Cubic

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unbounded Memory Consumption in Avatar URL Uploads (P1)

1 participant