Skip to content

SSRF Protection Manual Test Plan #452

@github-actions

Description

@github-actions

SSRF Protection Manual Test Plan

Purpose: Manual testing plan for validating SSRF protection in production-like environment.

Test Date: _____________
Tester: _____________
Environment: _____________
Charon Version: _____________


Prerequisites

Before beginning tests, ensure:

  • Charon deployed in test environment
  • Admin access to Charon configuration interface
  • Network access to test external webhooks
  • Access to test webhook receiver (e.g., https://webhook.site)
  • curl or similar HTTP client available
  • Ability to view Charon server logs

Test Environment Setup

Required Tools

  1. Webhook Testing Service:

  2. HTTP Client:

    # Verify curl is available
    curl --version
  3. Log Access:

    # View Charon logs
    docker logs charon --tail=50 --follow

Test Case Format

Each test case includes:

  • Objective: What security control is being tested
  • Steps: Detailed instructions
  • Expected Result: What should happen (✅)
  • Actual Result: Record what actually happened
  • Pass/Fail: Mark after completion
  • Notes: Any observations or issues

Test Suite 1: Valid External Webhooks

TC-001: Valid HTTPS Webhook

Objective: Verify legitimate HTTPS webhooks work correctly

Steps:

  1. Navigate to Security Settings → Notifications
  2. Configure webhook: https://webhook.site/<your-unique-id>
  3. Click Save
  4. Trigger security event (e.g., create test ACL rule)
  5. Check webhook.site for received event

Expected Result: ✅ Webhook successfully delivered, no errors in logs

Actual Result: _____________

Pass/Fail: [ ] Pass [ ] Fail

Notes:



TC-002: Valid HTTP Webhook (Non-Production)

Objective: Verify HTTP webhooks work when explicitly allowed

Steps:

  1. Navigate to Security Settings → Notifications
  2. Configure webhook: http://webhook.site/<your-unique-id>
  3. Click Save
  4. Trigger security event
  5. Check webhook receiver

Expected Result: ✅ Webhook accepted (if HTTP allowed), or ❌ Rejected with "HTTP is not allowed, use HTTPS"

Actual Result: _____________

Pass/Fail: [ ] Pass [ ] Fail

Notes:



TC-003: Slack Webhook Format

Objective: Verify production webhook services work

Steps:

  1. Create Slack incoming webhook at https://api.slack.com/messaging/webhooks
  2. Configure webhook in Charon: https://hooks.slack.com/services/T00/B00/XXX
  3. Save configuration
  4. Trigger security event
  5. Check Slack channel for notification

Expected Result: ✅ Notification appears in Slack

Actual Result: _____________

Pass/Fail: [ ] Pass [ ] Fail

Notes:



TC-004: Discord Webhook Format

Objective: Verify Discord integration works

Steps:

  1. Create Discord webhook in server settings
  2. Configure webhook in Charon: https://discord.com/api/webhooks/123456/abcdef
  3. Save configuration
  4. Trigger security event
  5. Check Discord channel

Expected Result: ✅ Notification appears in Discord

Actual Result: _____________

Pass/Fail: [ ] Pass [ ] Fail

Notes:



Test Suite 2: Private IP Rejection

TC-005: Class A Private Network (10.0.0.0/8)

Objective: Verify RFC 1918 Class A blocking

Steps:

  1. Attempt to configure webhook: http://10.0.0.1/webhook
  2. Click Save
  3. Observe error message

Expected Result: ❌ Error: "URL resolves to a private IP address (blocked for security)"

Actual Result: _____________

Pass/Fail: [ ] Pass [ ] Fail

Notes:



TC-006: Class B Private Network (172.16.0.0/12)

Objective: Verify RFC 1918 Class B blocking

Steps:

  1. Attempt to configure webhook: http://172.16.0.1/admin
  2. Click Save
  3. Observe error message

Expected Result: ❌ Error: "URL resolves to a private IP address (blocked for security)"

Actual Result: _____________

Pass/Fail: [ ] Pass [ ] Fail

Notes:



TC-007: Class C Private Network (192.168.0.0/16)

Objective: Verify RFC 1918 Class C blocking

Steps:

  1. Attempt to configure webhook: http://192.168.1.1/
  2. Click Save
  3. Observe error message

Expected Result: ❌ Error: "URL resolves to a private IP address (blocked for security)"

Actual Result: _____________

Pass/Fail: [ ] Pass [ ] Fail

Notes:



TC-008: Private IP with Port

Objective: Verify port numbers don't bypass protection

Steps:

  1. Attempt to configure webhook: http://192.168.1.100:8080/webhook
  2. Click Save
  3. Observe error message

Expected Result: ❌ Error: "URL resolves to a private IP address (blocked for security)"

Actual Result: _____________

Pass/Fail: [ ] Pass [ ] Fail

Notes:



Test Suite 3: Cloud Metadata Endpoints

TC-009: AWS Metadata Endpoint

Objective: Verify AWS metadata service is blocked

Steps:

  1. Attempt to configure webhook: http://169.254.169.254/latest/meta-data/
  2. Click Save
  3. Observe error message
  4. Check logs for HIGH severity SSRF attempt

Expected Result:

  • ❌ Configuration rejected
  • ✅ Log entry: severity=HIGH event=ssrf_blocked

Actual Result: _____________

Pass/Fail: [ ] Pass [ ] Fail

Notes:



TC-010: GCP Metadata Endpoint

Objective: Verify GCP metadata service is blocked

Steps:

  1. Attempt to configure webhook: http://metadata.google.internal/computeMetadata/v1/
  2. Click Save
  3. Observe error message

Expected Result: ❌ Error: "URL resolves to a private IP address" or "DNS lookup failed"

Actual Result: _____________

Pass/Fail: [ ] Pass [ ] Fail

Notes:



TC-011: Azure Metadata Endpoint

Objective: Verify Azure metadata service is blocked

Steps:

  1. Attempt to configure webhook: http://169.254.169.254/metadata/instance?api-version=2021-02-01
  2. Click Save
  3. Observe error message

Expected Result: ❌ Error: "URL resolves to a private IP address (blocked for security)"

Actual Result: _____________

Pass/Fail: [ ] Pass [ ] Fail

Notes:



Test Suite 4: Loopback Addresses

TC-012: IPv4 Loopback (127.0.0.1)

Objective: Verify localhost blocking (unless explicitly allowed)

Steps:

  1. Attempt to configure webhook: http://127.0.0.1:8080/internal
  2. Click Save
  3. Observe error message

Expected Result: ❌ Error: "localhost URLs are not allowed (blocked for security)"

Actual Result: _____________

Pass/Fail: [ ] Pass [ ] Fail

Notes:



TC-013: Localhost Hostname

Objective: Verify localhost keyword blocking

Steps:

  1. Attempt to configure webhook: http://localhost/admin
  2. Click Save
  3. Observe error message

Expected Result: ❌ Error: "localhost URLs are not allowed (blocked for security)"

Actual Result: _____________

Pass/Fail: [ ] Pass [ ] Fail

Notes:



TC-014: IPv6 Loopback (::1)

Objective: Verify IPv6 loopback blocking

Steps:

  1. Attempt to configure webhook: http://[::1]/webhook
  2. Click Save
  3. Observe error message

Expected Result: ❌ Error: "URL resolves to a private IP address (blocked for security)"

Actual Result: _____________

Pass/Fail: [ ] Pass [ ] Fail

Notes:



Test Suite 5: Protocol Validation

TC-015: File Protocol

Objective: Verify file:// protocol is blocked

Steps:

  1. Attempt to configure webhook: file:///etc/passwd
  2. Click Save
  3. Observe error message

Expected Result: ❌ Error: "URL must use HTTP or HTTPS"

Actual Result: _____________

Pass/Fail: [ ] Pass [ ] Fail

Notes:



TC-016: FTP Protocol

Objective: Verify ftp:// protocol is blocked

Steps:

  1. Attempt to configure webhook: ftp://internal-server.local/upload/
  2. Click Save
  3. Observe error message

Expected Result: ❌ Error: "URL must use HTTP or HTTPS"

Actual Result: _____________

Pass/Fail: [ ] Pass [ ] Fail

Notes:



TC-017: Gopher Protocol

Objective: Verify gopher:// protocol is blocked

Steps:

  1. Attempt to configure webhook: gopher://internal:70/
  2. Click Save
  3. Observe error message

Expected Result: ❌ Error: "URL must use HTTP or HTTPS"

Actual Result: _____________

Pass/Fail: [ ] Pass [ ] Fail

Notes:



TC-018: Data URL

Objective: Verify data: scheme is blocked

Steps:

  1. Attempt to configure webhook: data:text/html,<script>alert(1)</script>
  2. Click Save
  3. Observe error message

Expected Result: ❌ Error: "URL must use HTTP or HTTPS"

Actual Result: _____________

Pass/Fail: [ ] Pass [ ] Fail

Notes:



Test Suite 6: DNS Rebinding Protection

Background: DNS rebinding attacks exploit the gap between URL validation and actual connection by changing DNS records after validation passes. Charon's network.NewSafeHTTPClient() prevents this by re-validating IPs at connection time.

TC-019: DNS Rebinding Simulation (Conceptual)

Objective: Verify connection-time IP validation prevents DNS rebinding

Steps:

  1. Configure a webhook with a domain you control
  2. Initially point the domain to a public IP (passes validation)
  3. After webhook is saved, update DNS to point to 192.168.1.100
  4. Trigger a security event to send webhook notification
  5. Observe the webhook delivery failure

Expected Result:

  • ❌ Webhook delivery fails with "connection to private IP blocked"
  • ✅ Log entry shows re-validation caught the attack
  • ✅ No request reaches 192.168.1.100

Actual Result: _____________

Pass/Fail: [ ] Pass [ ] Fail

Notes:

This test requires DNS control. Alternative: use tools like rebinder.it

TC-020: Connection-Time IP Validation

Objective: Verify IPs are validated at TCP connection time (not just URL parsing)

Steps:

  1. Use a webhook receiver that logs incoming connections
  2. Configure webhook URL pointing to the receiver
  3. Check that the connection comes from Charon
  4. Verify in Charon logs that IP validation occurred during dial

Expected Result: ✅ Logs show safeDialer validated IP before connection

Actual Result: _____________

Pass/Fail: [ ] Pass [ ] Fail

Notes:

Check logs for: "Validating IP for connection"

Test Suite 7: Redirect Blocking

TC-021: Redirect to Private IP

Objective: Verify redirects to private IPs are blocked

Steps:

  1. Set up a redirect server that returns: HTTP 302 Location: http://192.168.1.100/
  2. Configure webhook pointing to the redirect server
  3. Trigger webhook delivery
  4. Observe redirect handling

Expected Result:

  • ❌ "redirect to private IP blocked"
  • ✅ Original request fails, no connection to 192.168.1.100

Actual Result: _____________

Pass/Fail: [ ] Pass [ ] Fail

Notes:

Alternative: use httpbin.org/redirect-to?url=http://192.168.1.100

TC-022: Redirect to Cloud Metadata

Objective: Verify redirects to cloud metadata endpoints are blocked

Steps:

  1. Set up redirect: HTTP 302 Location: http://169.254.169.254/latest/meta-data/
  2. Configure webhook pointing to redirect
  3. Trigger webhook delivery
  4. Verify metadata endpoint not accessed

Expected Result: ❌ "redirect to private IP blocked" (169.254.x.x is blocked)

Actual Result: _____________

Pass/Fail: [ ] Pass [ ] Fail

Notes:



TC-023: Redirect Count Limit

Objective: Verify excessive redirects are blocked

Steps:

  1. Set up chain of 5+ redirects (each to a valid public URL)
  2. Configure webhook pointing to first redirect
  3. Trigger webhook delivery
  4. Observe redirect chain handling

Expected Result: ❌ "too many redirects (max 2)" after 2 hops

Actual Result: _____________

Pass/Fail: [ ] Pass [ ] Fail

Notes:

Default max redirects is 0 (no redirects). If enabled, max is typically 2.

TC-024: Redirect to Localhost

Objective: Verify redirects to localhost are blocked

Steps:

  1. Set up redirect: HTTP 302 Location: http://127.0.0.1:8080/admin
  2. Configure webhook pointing to redirect
  3. Trigger webhook delivery
  4. Verify localhost not accessed

Expected Result: ❌ "redirect to localhost blocked"

Actual Result: _____________

Pass/Fail: [ ] Pass [ ] Fail

Notes:



Test Suite 8: URL Testing Endpoint

TC-025: Test Valid Public URL

Objective: Verify URL test endpoint works for legitimate URLs

Steps:

  1. Navigate to System SettingsURL Testing (or use API)
  2. Test URL: https://api.github.com
  3. Submit test
  4. Observe result

Expected Result: ✅ "URL is reachable" with latency in milliseconds

Actual Result: _____________

Pass/Fail: [ ] Pass [ ] Fail

Notes:



TC-026: Test Private IP via URL Testing

Objective: Verify URL test endpoint also has SSRF protection

Steps:

  1. Navigate to URL Testing
  2. Test URL: http://192.168.1.1
  3. Submit test
  4. Observe error

Expected Result: ❌ Error: "URL resolves to a private IP address (blocked for security)"

Actual Result: _____________

Pass/Fail: [ ] Pass [ ] Fail

Notes:



TC-027: Test Non-Existent Domain

Objective: Verify DNS resolution failure handling

Steps:

  1. Test URL: https://this-domain-does-not-exist-12345.com
  2. Submit test
  3. Observe error

Expected Result: ❌ Error: "DNS lookup failed" or "connection timeout"

Actual Result: _____________

Pass/Fail: [ ] Pass [ ] Fail

Notes:



Test Suite 9: CrowdSec Hub Sync

TC-028: Official CrowdSec Hub Domain

Objective: Verify CrowdSec hub sync works with official domain

Steps:

  1. Navigate to SecurityCrowdSec
  2. Enable CrowdSec (if not already enabled)
  3. Trigger hub sync (or wait for automatic sync)
  4. Check logs for hub update success

Expected Result: ✅ Hub sync completes successfully

Actual Result: _____________

Pass/Fail: [ ] Pass [ ] Fail

Notes:



TC-029: Invalid CrowdSec Hub Domain

Objective: Verify custom hub URLs are validated

Steps:

  1. Attempt to configure custom hub URL: http://malicious-hub.evil.com
  2. Trigger hub sync
  3. Observe error in logs

Expected Result: ❌ Hub sync fails with validation error

Actual Result: _____________

Pass/Fail: [ ] Pass [ ] Fail

Notes:

(This test may require configuration file modification)

Test Suite 10: Update Service

TC-030: GitHub Update Check

Objective: Verify update service uses validated GitHub URLs

Steps:

  1. Navigate to SystemUpdates (if available in UI)
  2. Click Check for Updates
  3. Observe success or error
  4. Check logs for GitHub API request

Expected Result: ✅ Update check completes (no SSRF vulnerability)

Actual Result: _____________

Pass/Fail: [ ] Pass [ ] Fail

Notes:



Test Suite 11: Error Message Validation

TC-031: Generic Error Messages

Objective: Verify error messages don't leak internal information

Steps:

  1. Attempt various blocked URLs from previous tests
  2. Record exact error messages shown to user
  3. Verify no internal IPs, hostnames, or network topology revealed

Expected Result: ✅ Generic errors like "URL resolves to a private IP address (blocked for security)"

Actual Result: _____________

Pass/Fail: [ ] Pass [ ] Fail

Notes:



TC-032: Log Detail vs User Error

Objective: Verify logs contain more detail than user-facing errors

Steps:

  1. Attempt blocked URL: http://192.168.1.100/admin
  2. Check user-facing error message
  3. Check server logs for detailed information

Expected Result:

  • User sees: "URL resolves to a private IP address (blocked for security)"
  • Logs show: severity=HIGH url=http://192.168.1.100/admin resolved_ip=192.168.1.100

Actual Result: _____________

Pass/Fail: [ ] Pass [ ] Fail

Notes:



Test Suite 12: Integration Testing

TC-033: End-to-End Webhook Flow

Objective: Verify complete webhook notification flow with SSRF protection

Steps:

  1. Configure valid webhook: https://webhook.site/<unique-id>
  2. Trigger CrowdSec block event (simulate attack)
  3. Verify notification received at webhook.site
  4. Check logs for successful webhook delivery

Expected Result:

  • ✅ Webhook configured without errors
  • ✅ Security event triggered
  • ✅ Notification delivered successfully
  • ✅ Logs show Webhook notification sent successfully

Actual Result: _____________

Pass/Fail: [ ] Pass [ ] Fail

Notes:



TC-034: Configuration Persistence

Objective: Verify webhook validation persists across restarts

Steps:

  1. Configure valid webhook: https://webhook.site/<unique-id>
  2. Restart Charon container: docker restart charon
  3. Trigger security event
  4. Verify notification still works

Expected Result: ✅ Webhook survives restart and continues to function

Actual Result: _____________

Pass/Fail: [ ] Pass [ ] Fail

Notes:



TC-035: Multiple Webhook Configurations

Objective: Verify SSRF protection applies to all webhook types

Steps:

  1. Configure security notification webhook (valid)
  2. Configure custom webhook notification (valid)
  3. Attempt to add webhook with private IP (blocked)
  4. Verify both valid webhooks work, blocked one rejected

Expected Result:

  • ✅ Valid webhooks accepted
  • ❌ Private IP webhook rejected
  • ✅ Both valid webhooks receive notifications

Actual Result: _____________

Pass/Fail: [ ] Pass [ ] Fail

Notes:



TC-036: Admin-Only Access Control

Objective: Verify URL testing requires admin privileges

Steps:

  1. Log out of admin account
  2. Log in as non-admin user (if available)
  3. Attempt to access URL testing endpoint
  4. Observe access denied error

Expected Result: ❌ 403 Forbidden: "Admin access required"

Actual Result: _____________

Pass/Fail: [ ] Pass [ ] Fail

Notes:



Test Summary

Results Overview

Test Suite Total Tests Passed Failed Skipped
Valid External Webhooks 4 ___ ___ ___
Private IP Rejection 4 ___ ___ ___
Cloud Metadata Endpoints 3 ___ ___ ___
Loopback Addresses 3 ___ ___ ___
Protocol Validation 4 ___ ___ ___
DNS Rebinding Protection 2 ___ ___ ___
Redirect Blocking 4 ___ ___ ___
URL Testing Endpoint 3 ___ ___ ___
CrowdSec Hub Sync 2 ___ ___ ___
Update Service 1 ___ ___ ___
Error Message Validation 2 ___ ___ ___
Integration Testing 4 ___ ___ ___
TOTAL 36 ___ ___ ___

Pass Criteria

Minimum Requirements:

  • All 36 test cases passed OR
  • All critical tests passed (TC-005 through TC-018, TC-021 through TC-024, TC-026) AND
  • All failures have documented justification

Critical Tests (Must Pass):

  • TC-005: Class A Private Network blocking
  • TC-006: Class B Private Network blocking
  • TC-007: Class C Private Network blocking
  • TC-009: AWS Metadata blocking
  • TC-012: IPv4 Loopback blocking
  • TC-015: File protocol blocking
  • TC-021: Redirect to Private IP blocking
  • TC-022: Redirect to Cloud Metadata blocking
  • TC-026: URL testing SSRF protection

Issues Found

Issue Template

Issue ID: _____________
Test Case: TC-___
Severity: [ ] Critical [ ] High [ ] Medium [ ] Low
Description:


Steps to Reproduce:


Expected vs Actual:


Workaround (if applicable):



Sign-Off

Tester Certification

I certify that:

  • All test cases were executed as described
  • Results are accurate and complete
  • All issues are documented
  • Test environment matches production configuration
  • SSRF protection is functioning as designed

Tester Name: _____________
Signature: _____________
Date: _____________


QA Manager Approval

  • Test plan executed completely
  • All critical tests passed
  • Issues documented and prioritized
  • SSRF remediation approved for production

QA Manager Name: _____________
Signature: _____________
Date: _____________


Document Version: 1.1
Last Updated: December 24, 2025
Status: Ready for Execution


Auto-created from ssrf_manual_test_plan.md

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    Status

    In Progress

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions