Skip to content

fix: authenticate image attachment preview urls to prevent 403 errors - #1403

Open
swarnendusahu10-dotcom wants to merge 1 commit into
RocketChat:developfrom
swarnendusahu10-dotcom:fix/issue-1229-authenticated-image-previews
Open

swarnendusahu10-dotcom wants to merge 1 commit into
RocketChat:developfrom
swarnendusahu10-dotcom:fix/issue-1229-authenticated-image-previews

Conversation

@swarnendusahu10-dotcom

Copy link
Copy Markdown
Contributor

Summary

Fixes #1229

When Rocket.Chat servers have the default "Block Unauthenticated Access" setting enabled for uploaded files under /file-upload/..., image attachment previews rendered directly via HTML <img> tags fail to load with 403 Forbidden because standard browser image requests do not carry custom HTTP headers (X-Auth-Token / X-User-Id).

This pull request introduces an authenticated media URL handler that appends Rocket.Chat's query-parameter authentication (?rc_token=<token>&rc_uid=<userId>) to internal file upload URLs while strictly safeguarding external URLs against credential leakage.


Security Architecture & Validation Boundary

To guarantee that user authentication credentials (rc_token, rc_uid) can never leak to third-party domains or external image hosts (CWE-200 prevention), URL resolution enforces a strict dual-boundary validation:

flowchart TD
    A["Incoming Media URL<br/><i>(attachment.image_url)</i>"] --> B{"Is URL falsy or empty?"}
    
    B -- "Yes" --> C["Return '' (Defensive Guard)"]
    B -- "No" --> D{"Is URL Relative or Absolute?"}
    
    D -- "Relative (/file-upload/...)" --> E{"Path starts with<br/>'/file-upload/'?"}
    D -- "Absolute (http/https)" --> F{"Origin === Rocket.Chat Host Origin?"}
    
    F -- "No (External / Attacker URL)" --> G["Return Raw External URL<br/><b>[ZERO TOKEN LEAKAGE - CWE-200 SAFE]</b>"]
    F -- "Yes (Same Origin)" --> E
    
    E -- "No (e.g. /avatar/)" --> H["Return host + path URL without tokens"]
    E -- "Yes (/file-upload/)" --> I{"Are rc_token & rc_uid available?"}
    
    I -- "No (Unauthenticated / Anonymous)" --> H
    I -- "Yes (Authenticated Session)" --> J["Append ?rc_token=...&rc_uid=... via URLSearchParams<br/><b>[PREVIEW AUTHENTICATED - 403 RESOLVED]</b>"]

    style A fill:#1f2937,stroke:#4b5563,stroke-width:2px,color:#f3f4f6
    style B fill:#374151,stroke:#6b7280,stroke-width:2px,color:#f3f4f6
    style C fill:#4b5563,stroke:#9ca3af,stroke-width:1px,color:#f3f4f6
    style D fill:#374151,stroke:#6b7280,stroke-width:2px,color:#f3f4f6
    style E fill:#1e3a8a,stroke:#3b82f6,stroke-width:2px,color:#eff6ff
    style F fill:#831843,stroke:#ec4899,stroke-width:2px,color:#fdf2f8
    style G fill:#991b1b,stroke:#ef4444,stroke-width:2px,color:#fef2f2
    style H fill:#374151,stroke:#9ca3af,stroke-width:1px,color:#f3f4f6
    style I fill:#1e3a8a,stroke:#3b82f6,stroke-width:2px,color:#eff6ff
    style J fill:#065f46,stroke:#10b981,stroke-width:2px,color:#ecfdf5
Loading

Key Changes

  1. useAuthenticatedMediaUrl Hook (packages/react/src/hooks/useAuthenticatedMediaUrl.js):
    • Eagerly evaluates current session credentials from RCInstance.auth.currentUser to prevent loading flash or broken images.
    • Asynchronously reconciles with RCInstance.auth.getCurrentUser() and reactive RCInstance.auth.onAuthChange listener subscriptions.
    • Cleanly cleans up event listeners on component unmount.
  2. Strict Boundary & Token Leakage Prevention (CWE-200):
    • Only URLs residing on the Rocket.Chat host instance AND pointing to /file-upload/ paths receive authentication query parameters.
    • External URLs (e.g., Unsplash, Giphy, custom webhooks, or third-party links) and non-upload paths are strictly returned untouched, guaranteeing zero credential leakage.
  3. ImageAttachment.js & NestedImageAttachment (packages/react/src/views/AttachmentHandler/ImageAttachment.js):
    • Authenticates both the preview <img> source and the AttachmentMetadata download URL (fixing 403 Forbidden on attachment download).
    • Extracts nested attachments into a clean NestedImageAttachment subcomponent, strictly complying with the Rules of Hooks.
    • Guards extractIdFromUrl against null/undefined URLs using optional chaining.
    • Adds full PropTypes coverage.

Verification & Testing

  • Unit & Logic Verification: Verified with automated test matrix covering relative paths, absolute host URLs, external URLs, phishing/spoofed hosts, unauthenticated sessions, and URL-encoded token characters.
  • Prettier & Formatting: Passed prettier --check.
  • Rollup Build: Clean build completed with npm run build (dist/cjs and dist/esm generated without errors).

This branch has not been deployed

No deployments
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.

Bug: Image attachment previews return 403 Forbidden (uploaded images not visible in chat)

1 participant