← Back to PRs

#20913: fix: intercept Discord embed images to enforce mediaMaxMb

by MumuTW open 2026-02-19 12:35 View on GitHub →
channel: discord size: S
## Summary Fixes #20906 - **Problem**: Discord inline/pasted screenshots arrive as embed `image`/`thumbnail` fields, not as file attachments. The `mediaMaxMb` check only gates file attachments via `resolveMediaList()`, so embed images bypass size limits entirely and enter the LLM context unchecked — bricking sessions permanently. - **Why it matters**: A single large screenshot pasted into Discord can inject 5-10MB of data into context, causing permanent API failures with no user-visible error and no recovery path. - **What changed**: Added `resolveEmbedMediaList()` to intercept images from Discord embed objects, routing them through the same `fetchRemoteMedia → saveMediaBuffer(maxBytes)` pipeline that file attachments use. - **What did NOT change**: Attachment handling, forwarded message handling, outbound embed behavior, session history compaction. ## Change Type (select all) - [x] Bug fix - [ ] Feature - [ ] Refactor - [ ] Docs - [ ] Security hardening - [ ] Chore/infra ## Scope (select all touched areas) - [ ] Gateway / orchestration - [ ] Skills / tool execution - [ ] Auth / tokens - [ ] Memory / storage - [x] Integrations - [ ] API / contracts - [ ] UI / DX - [ ] CI/CD / infra ## Linked Issue/PR Fixes https://github.com/openclaw/openclaw/issues/20906 Related: #1210, #19622, #15638, #15045, #12838 ## User-visible / Behavior Changes - Discord embed images (inline pastes, link preview images) are now downloaded and size-checked against `mediaMaxMb` before entering context - Oversized embed images are rejected with a log message instead of silently bricking the session - No change for messages with only file attachments (existing path unchanged) ## Security Impact (required) - New permissions/capabilities? No - Secrets/tokens handling changed? No - New/changed network calls? Yes — embed image URLs are now fetched via the existing `fetchRemoteMedia` pipeline (same SSRF protections apply) - Command/tool execution surface changed? No - Data access scope changed? No - If any Yes, explain risk + mitigation: Embed image downloads use the same `fetchRemoteMedia()` function as attachments, which already has SSRF guards (`resolvePinnedHostname`), redirect limits, and size caps. ## Repro + Verification ### Environment - OS: Any - Runtime/container: N/A - Model/provider: Anthropic (Claude) - Integration/channel: Discord - Relevant config: `channels.discord.mediaMaxMb: 2` ### Steps 1. Configure `channels.discord.mediaMaxMb: 2` 2. In Discord, paste a large screenshot (>5MB) directly into the message 3. **Before fix**: Image bypasses size check, enters context as base64, session bricks 4. **After fix**: Image is intercepted by `resolveEmbedMediaList`, `saveMediaBuffer` rejects it with "Media exceeds NMB limit", session continues normally ### Expected - Oversized embed images are rejected; session remains functional ### Actual - Oversized embed images are rejected; session remains functional ## Evidence - [x] Unit tests for `resolveEmbedMediaList` covering: empty embeds, image download, proxy_url preference, attachment deduplication, image+thumbnail combo, download failure handling ## Verification (required) - Verified scenarios: All 6 unit test cases pass - Edge cases checked: Duplicate URL deduplication (attachment URL == embed URL), missing embeds, both image and thumbnail present, proxy_url preference - What you did NOT verify: Live Discord integration test (requires Discord bot token + test server). I did not do the E2E test. ## Compatibility / Migration - Backward compatible? Yes - Config/env changes? No - Migration needed? No ## Failure Recovery (if this breaks) - How to disable/revert: Revert this commit - Files/config to restore: `src/discord/monitor/message-utils.ts`, `src/discord/monitor/message-handler.process.ts` - Known bad symptoms: If embed image fetching fails silently, behavior degrades gracefully to pre-fix state (images just won't be processed) ## Risks and Mitigations - Risk: Link preview embeds (YouTube, Twitter, etc.) may have thumbnails that get downloaded unnecessarily - Mitigation: These are small (typically <100KB) and go through the same maxBytes guard. The deduplication logic also prevents double-fetching when Discord includes the same URL in both attachments and embeds. <!-- greptile_comment --> <h3>Greptile Summary</h3> Intercepts Discord embed images (inline pastes, link previews) and routes them through the same `mediaMaxMb` validation pipeline as file attachments, preventing oversized images from bypassing limits and bricking sessions. - Fixed critical bug where Discord embed images bypassed `mediaMaxMb` limits - Added `resolveEmbedMediaList()` to download and validate embed images before they enter LLM context - Implemented deduplication to avoid re-fetching URLs that are already in attachments - Comprehensive test coverage with 6 test cases covering empty embeds, downloads, deduplication, and error handling - Graceful error handling: failed downloads are logged and skipped rather than blocking the message **Issue found:** The `proxy_url`/`url` handling will fetch both URLs when both are present, resulting in duplicate downloads of the same image. <h3>Confidence Score: 3/5</h3> - Safe to merge after fixing the proxy_url/url duplicate fetch issue - The PR addresses a critical bug and includes solid test coverage, but contains a logic error where both `proxy_url` and `url` are fetched when both exist, causing unnecessary duplicate downloads. This won't cause correctness issues but creates inefficiency. Once fixed, this is a well-structured addition. - src/discord/monitor/message-utils.ts needs the proxy_url/url handling fixed (lines 181-186) <sub>Last reviewed commit: 1fc95ad</sub> <!-- greptile_other_comments_section --> <sub>(2/5) Greptile learns from your feedback when you react with thumbs up/down!</sub> <!-- /greptile_comment -->

Most Similar PRs