#20913: fix: intercept Discord embed images to enforce mediaMaxMb
channel: discord
size: S
Cluster:
Discord and MS Teams Fixes
## 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
#21463: fix(discord): prevent WebSocket death spiral + fix numeric channel ID…
by akropp · 2026-02-20
81.7%
#21230: Fix [Bug]: Discord attachments silently missing (Fixes #19956)
by vasujain00 · 2026-02-19
81.4%
#20479: fix(slack): keep replies flowing for oversized file uploads
by olyashok · 2026-02-19
80.5%
#10902: fix(msteams): fix inline pasted image downloads
by jlian · 2026-02-07
79.8%
#2958: fix(media): wire tools.media.image.maxBytes config to image processin…
by shamsulalam1114 · 2026-01-27
79.7%
#20488: fix(discord): pass mediaLocalRoots to sendMessageDiscord
by olyashok · 2026-02-19
79.7%
#17316: fix: ack reaction not removed when block streaming is enabled (Tele...
by czmathew · 2026-02-15
79.3%
#9598: fix(agents): check base64 string length against 5MB API limit
by BlockBB · 2026-02-05
78.7%
#19399: telegram: fix MEDIA false positives and partial final drop
by HOYALIM · 2026-02-17
78.6%
#20735: fix: skip auto-attaching tool MEDIA: paths already sent via message t…
by anillBhoi · 2026-02-19
78.1%