Skip to content

fix(webhooks): validate organisation and integration URLs against SSRF - #8220

Open
bardock-2393 wants to merge 2 commits into
Flagsmith:mainfrom
bardock-2393:fix/webhook-integration-url-ssrf
Open

fix(webhooks): validate organisation and integration URLs against SSRF#8220
bardock-2393 wants to merge 2 commits into
Flagsmith:mainfrom
bardock-2393:fix/webhook-integration-url-ssrf

Conversation

@bardock-2393

Copy link
Copy Markdown
Contributor

Changes

Extends the existing SSRF-safe URL field (previously added for environment webhooks only) to OrganisationWebhookSerializer, the GitLab/Sentry/generic webhook integration serializers, and every integration built on the shared IntegrationsModel.base_url (Dynatrace, Datadog, New Relic, Grafana, Amplitude, Heap, Mixpanel, Rudderstack). These previously accepted any syntactically valid URL, including ones resolving to private/internal network ranges. Also tightens the shared validator to reject non-http(s) schemes (it previously allowed ftp/ftps via Django's default URLValidator).

Contributes to #8218 — coverage is limited to fields confirmed to be used for outbound server-side requests (verified via call-site grep against every app under api/integrations/). Fields that only build display links (not fetched server-side) were left untouched.

Note: this removes the ability for self-hosted deployments to point webhooks/integrations at localhost or internal Docker-network hosts, even intentionally in dev/test setups — consistent with the existing environment-webhook precedent, now applied repo-wide. Happy to follow up with a settings-driven allowlist if that's needed for dev workflows.

How did you test this code?

Added private-IP-rejection, DNS-rebind-rejection, and scheme-rejection tests across the touched serializers' existing test files. All 302 tests in the touched integration/webhook/organisation suites pass against real Postgres. Confirmed old-vs-new by reverting just the validator change: 2 tests fail (ftp/ftps accepted) on old code, pass on new code. Ran mypy (full project, clean) and the project's pre-commit hooks (all clean).

Review effort: 4/5

OrganisationWebhookSerializer, the GitLab/Sentry/generic webhook
integrations, and every integration sharing IntegrationsModel.base_url
(Dynatrace, Datadog, New Relic, Grafana, Amplitude, Heap, Mixpanel,
Rudderstack) accepted arbitrary URLs with only format validation. Apply
the existing NoSSRFURLField, used by environment webhooks, to these
fields so they're resolved and checked against internal/private address
ranges too. Also restrict NoSSRFURLField itself to http/https schemes,
closing an ftp/ftps gap in the existing validator.
@bardock-2393
bardock-2393 requested a review from a team as a code owner August 5, 2026 11:55
@bardock-2393
bardock-2393 requested review from emyller and removed request for a team August 5, 2026 11:55
@vercel

vercel Bot commented Aug 5, 2026

Copy link
Copy Markdown

@bardock-2393 is attempting to deploy a commit to the Flagsmith Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 7b7874cd-f1b8-498a-b02c-2fafa02a6678

📥 Commits

Reviewing files that changed from the base of the PR and between 0a15477 and c506236.

📒 Files selected for processing (4)
  • api/integrations/gitlab/serializers.py
  • api/integrations/sentry/serializers.py
  • api/integrations/webhook/serializers.py
  • api/webhooks/fields.py

📝 Walkthrough

Walkthrough

The change applies NoSSRFURLField to integration and organisation webhook URL serializers. NoSSRFURLField now accepts only HTTP(S) schemes and retains private-address checks. Integration serializers preserve generated field options for base_url. Tests cover private IP addresses, private DNS targets, unsupported schemes, valid public URLs, HTTP 400 responses, and prevented persistence.

Estimated code review effort: 3 (Moderate) | ~25 minutes

✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added the api Issue related to the REST API label Aug 5, 2026
@codecov

codecov Bot commented Aug 5, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.57%. Comparing base (d6da2ff) to head (c506236).
⚠️ Report is 5 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #8220      +/-   ##
==========================================
- Coverage   98.71%   98.57%   -0.14%     
==========================================
  Files        1535     1536       +1     
  Lines       61329    61411      +82     
==========================================
- Hits        60541    60536       -5     
- Misses        788      875      +87     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 1f70df97-6c85-42b5-a27c-5428f9459f4b

📥 Commits

Reviewing files that changed from the base of the PR and between fb78687 and 0a15477.

📒 Files selected for processing (14)
  • api/integrations/common/serializers.py
  • api/integrations/gitlab/serializers.py
  • api/integrations/sentry/serializers.py
  • api/integrations/webhook/serializers.py
  • api/organisations/serializers.py
  • api/tests/unit/integrations/datadog/test_unit_datadog_views.py
  • api/tests/unit/integrations/dynatrace/test_unit_dynatrace_views.py
  • api/tests/unit/integrations/gitlab/test_configuration.py
  • api/tests/unit/integrations/new_relic/test_unit_new_relic_views.py
  • api/tests/unit/integrations/sentry/test_unit_sentry_views.py
  • api/tests/unit/integrations/webhook/test_unit_webhook_views.py
  • api/tests/unit/organisations/test_unit_organisations_serializers.py
  • api/tests/unit/webhooks/test_webhooks_fields.py
  • api/webhooks/fields.py

Comment thread api/integrations/sentry/serializers.py Outdated
Comment thread api/webhooks/fields.py
…r message

Explicit NoSSRFURLField() declarations dropped the model's max_length=200
constraint. Also update the internal-address error message since the field
is now shared by non-webhook integrations (Sentry, GitLab).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

api Issue related to the REST API

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant