Webhook validation bypass via DNS rebinding attack
completed
medium
manu
supervisor
2026-04-01 21:01
Location
src/supervisor/notifications.py:76
Description
notifications.py lines 76-86 validates webhook URLs by resolving DNS once at configuration time, but doesn't re-validate at send time. An attacker can: (1) Register a domain that initially resolves to a public IP (passes validation), (2) Change DNS to point to internal IPs (169.254.169.254 AWS metadata, 127.0.0.1, 10.x.x.x), (3) When the webhook fires, it will connect to the internal IP, bypassing SSRF protection. The validate_webhook_url() is only called in WebhookChannel.__init__ (line 283) but SlackChannel (line 204) doesn't validate at all, allowing slack_webhook config to be set to internal IPs via the dashboard. Should re-validate DNS on every send attempt and add validation to SlackChannel.
Evaluation
●
Agent analyzing code...
Verdict: feasible
Reasoning: This is a clearly defined and critical DNS rebinding SSRF vulnerability. The code shows that validate_webhook_url() performs DNS resolution at configuration time (lines 76-86) but doesn't re-validate at send time. WebhookChannel validates in __init__ (line 283), but SlackChannel (line 204-205) doesn't validate at all, allowing internal IPs to be set via the dashboard at dashboard.py:384-398. The vulnerability path is well-documented: an attacker can pass initial validation with a public IP, then change DNS to point to AWS metadata (169.254.169.254) or internal IPs before the webhook fires.
Fix approach: 1. Add DNS re-validation in WebhookChannel.send() before every HTTP request (lines 285-306) - validate the URL each time, not just in __init__
2. Add SSRF validation to SlackChannel.__init__() (line 204) - currently no validation exists for Slack webhooks
3. Add validation in dashboard.py update_notifications() (lines 384-398) when slack_webhook is set via the web form
4. Add validation in cli.py for slack_webhook flag (line 381) - currently only webhook_url is validated (line 387)
5. Update _post_with_retry() to perform final IP validation before connection - resolve DNS immediately before the httpx.post() call and block private IPs
6. Add tests covering: (a) DNS rebinding scenario with changing resolution, (b) SlackChannel with internal IPs, (c) dashboard form submission with private IPs
7. Consider adding rate limiting or DNS cache TTL enforcement to prevent rapid DNS changes during validation window
Effort: medium
Implementation
●
Agent implementing changes...
Agent result:
[Agent completed]
Perfect! Now let me create a summary of all the changes made. Let me check the git status to see what files were modified:
## Summary
I've successfully fixed the critical DNS rebinding SSRF vulnerability in the supervisor notification system. Here's what was implemented:
### Vulnerability Fixed
The original code validated webhook URLs only at configuration time, allowing an attacker to:
1. Register a domain resolving to a public IP (passes validation)
2. Change DNS to point to internal IPs (AWS metadata 169.254.169.254, localhost, private networks)
3. Exploit the webhook to access internal resources when it fires
### Changes Made
#### 1. **src/supervisor/notifications.py** (lines 140-150, 215)
- **_post_with_retry()**: Added DNS re-validation immediately before every HTTP POST request to prevent DNS rebinding attacks
- **SlackChannel.__init__()**: Added `validate_webhook_url()` call (previously had NO validation at all)
- **WebhookChannel.send()**: Removed redundant ValueError catch since _post_with_retry now handles validation
#### 2. **src/supervisor/web/dashboard.py** (lines 210-220, 384-404)
- **resource_new_submit()**: Added webhook URL validation when creating resources with slack_webhook via the web dashboard
- **update_notifications()**: Added webhook URL validation when updating slack_webhook configuration via the settings form
#### 3. **src/supervisor/cli.py** (lines 379-387)
- **cmd_notify_configure()**: Added validation for `--slack-webhook` flag (previously only validated `--webhook-url`)
#### 4. **tests/test_notifications.py** (lines 100-161, 264-286)
Added comprehensive tests covering:
- DNS rebinding attack scenarios with changing DNS resolution
- SlackChannel validation on initialization
- SlackChannel blocking of all internal IP ranges
- _post_with_retry DNS re-validation at send time
- WebhookChannel end-to-end DNS rebinding protection
### Security Impact
**Before**:
- SlackChannel: ❌ NO validation (lines 204-205)
- WebhookChannel:
Job History (2)
| Type | Status | Started | Duration | Error | |
|---|---|---|---|---|---|
| implement | completed | 2026-04-02 02:53 | 230s | - | |
| evaluate | completed | 2026-04-02 02:52 | 38s | - |