TestSSRFPrevention verifies that the default SSRF-safe HTTP client blocks webpush delivery to loopback (and other non-public) addresses. This reproduces the attack vector from the original SSRF PoC: an authenticated user supplies a localhost endpoint in their webpush subscription, and the server mus
(t *testing.T)
| 569 | // user supplies a localhost endpoint in their webpush subscription, and the |
| 570 | // server must refuse to connect. |
| 571 | func TestSSRFPrevention(t *testing.T) { |
| 572 | t.Parallel() |
| 573 | |
| 574 | ctx := testutil.Context(t, testutil.WaitShort) |
| 575 | |
| 576 | // Start a server that records whether it received a request. |
| 577 | var received atomic.Bool |
| 578 | server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { |
| 579 | received.Store(true) |
| 580 | w.WriteHeader(http.StatusCreated) |
| 581 | })) |
| 582 | defer server.Close() |
| 583 | |
| 584 | // Create a dispatcher via New() WITHOUT WithHTTPClient so it |
| 585 | // uses the default SSRF-safe client that blocks loopback. |
| 586 | db, _ := dbtestutil.NewDB(t) |
| 587 | logger := slogtest.Make(t, &slogtest.Options{IgnoreErrors: true}).Leveled(slog.LevelDebug) |
| 588 | manager, err := webpush.New(ctx, &logger, db, "http://example.com") |
| 589 | require.NoError(t, err) |
| 590 | |
| 591 | // Test() calls webpushSend directly with the supplied endpoint. |
| 592 | err = manager.Test(ctx, codersdk.WebpushSubscription{ |
| 593 | Endpoint: server.URL, |
| 594 | AuthKey: validEndpointAuthKey, |
| 595 | P256DHKey: validEndpointP256dhKey, |
| 596 | }) |
| 597 | require.Error(t, err, "SSRF-safe client should reject Test() to loopback address") |
| 598 | assert.False(t, received.Load(), "Test() request should not reach the localhost server") |
| 599 | |
| 600 | // Dispatch() goes through the subscription cache → webpushSend path. |
| 601 | user := dbgen.User(t, db, database.User{}) |
| 602 | _, err = db.InsertWebpushSubscription(ctx, database.InsertWebpushSubscriptionParams{ |
| 603 | CreatedAt: dbtime.Now(), |
| 604 | UserID: user.ID, |
| 605 | Endpoint: server.URL, |
| 606 | EndpointAuthKey: validEndpointAuthKey, |
| 607 | EndpointP256dhKey: validEndpointP256dhKey, |
| 608 | }) |
| 609 | require.NoError(t, err) |
| 610 | |
| 611 | err = manager.Dispatch(ctx, user.ID, codersdk.WebpushMessage{ |
| 612 | Title: "SSRF test", |
| 613 | Body: "This should not arrive.", |
| 614 | }) |
| 615 | require.Error(t, err, "SSRF-safe client should reject Dispatch() to loopback address") |
| 616 | assert.False(t, received.Load(), "Dispatch() request should not reach the localhost server") |
| 617 | } |
nothing calls this directly
no test coverage detected