Severity: MEDIUM
Summary
fetchWithSlackAuth() in src/slack/monitor/media.ts validates the initial URL is a Slack domain (*.slack.com), but follows the redirect to any HTTPS URL without SSRF validation.
Affected Code
File: src/slack/monitor/media.ts:109-115
// Only follow safe protocols (we do NOT include Authorization on redirects).
if (resolvedUrl.protocol !== "https:") {
return initialRes;
}
// Follow the redirect without the Authorization header
return fetch(resolvedUrl.toString(), { redirect: "follow" });
The redirect target is checked for HTTPS protocol but not validated against private/internal IP ranges. An open redirect on Slack infrastructure (or a compromised Slack workspace API response) could redirect to an internal IP.
Attack Scenario
- Attacker controls a Slack workspace or finds an open redirect on
*.slack.com
- A file URL resolves to
https://files.slack.com/... which redirects to http://169.254.169.254/latest/meta-data/ (blocked by HTTPS check) or https://internal-service.corp/...
- The
fetch() call with redirect: "follow" will follow further redirects from the target without any SSRF check
Contrast with Safe Path
The createSlackMediaFetch() closure (same file, line 60-77) is used through fetchRemoteMedia() → fetchWithSsrFGuard(), which correctly validates each redirect hop against private IP ranges with DNS pinning. Only fetchWithSlackAuth() bypasses this.
Recommended Fix
Route the redirect through fetchWithSsrFGuard instead of bare fetch(), or validate the redirect target hostname against isPrivateIpAddress before following.
Severity: MEDIUM
Summary
fetchWithSlackAuth()insrc/slack/monitor/media.tsvalidates the initial URL is a Slack domain (*.slack.com), but follows the redirect to any HTTPS URL without SSRF validation.Affected Code
File:
src/slack/monitor/media.ts:109-115The redirect target is checked for HTTPS protocol but not validated against private/internal IP ranges. An open redirect on Slack infrastructure (or a compromised Slack workspace API response) could redirect to an internal IP.
Attack Scenario
*.slack.comhttps://files.slack.com/...which redirects tohttp://169.254.169.254/latest/meta-data/(blocked by HTTPS check) orhttps://internal-service.corp/...fetch()call withredirect: "follow"will follow further redirects from the target without any SSRF checkContrast with Safe Path
The
createSlackMediaFetch()closure (same file, line 60-77) is used throughfetchRemoteMedia()→fetchWithSsrFGuard(), which correctly validates each redirect hop against private IP ranges with DNS pinning. OnlyfetchWithSlackAuth()bypasses this.Recommended Fix
Route the redirect through
fetchWithSsrFGuardinstead of barefetch(), or validate the redirect target hostname againstisPrivateIpAddressbefore following.