Skip to content

SSRF via Multiple Admin Features — Inconsistent SsrfProtection Usage (CWE-918)

Moderate
oliverguenther published GHSA-p692-v488-c3hq Jul 1, 2026

Package

bundler openproject (RubyGems)

Affected versions

< 17.5.0

Patched versions

17.5.0

Description

Summary

Several features use OpenProject.httpx to make HTTP requests to admin-configured URLs without SSRF protection. This allows an admin user to make the server issue requests to internal network services, cloud metadata endpoints, and localhost services.

This is particularly notable because OpenProject has a dedicated OpenProject::SsrfProtection module (inheriting from the ssrf_filter gem) that properly blocks private IPs — but it is only used for outgoing webhooks. The Jira import, Nextcloud storage validation, OIDC metadata fetching, and SAML metadata fetching all use the unprotected OpenProject.httpx client directly.

Severity

CVSS 3.1: 6.5 (Medium) — CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:N/A:N

Requires admin access, but in cloud-hosted environments (AWS/GCP/Azure), SSRF to instance metadata endpoints can yield IAM credentials.

Affected Components

1. Jira Import (app/services/import/jira_client.rb:49-66)

The JiraClient sends requests with Bearer auth to any URL:

@httpx = OpenProject
           .httpx
           .plugin(:auth)
           .bearer_auth(personal_access_token)  # Token sent to ANY target

URL validation only checks scheme (URI::HTTP or URI::HTTPS), not IP range.

2. Nextcloud Storage (modules/storages/app/validator/nextcloud_compatible_host_validator.rb:45-51)

Uses OpenProject.httpx to validate Nextcloud hosts. Additionally, secure_context_uri_validator.rb:55-66 explicitly allows http://localhost and *.localhost.

3. OIDC Metadata (modules/openid_connect/app/services/openid_connect/providers/update_service.rb:62)

Fetches OIDC discovery metadata from admin-supplied URL without SSRF protection.

4. SAML Metadata (modules/auth_saml/app/services/saml/update_metadata_service.rb:74)

Fetches SAML metadata from admin-supplied URL without SSRF protection.

Contrast: Webhooks ARE protected

# modules/webhooks/app/services/webhooks/outgoing/request_webhook_service.rb:16
response = OpenProject::SsrfProtection.post(webhook.url, headers:, body:)

Proof of Concept

Verified on OpenProject v15.5.1 (Docker):

  1. Set up a listener on port 9999 on the Docker host

  2. Inside the container, ran:

    response = OpenProject.httpx.get("http://172.23.0.1:9999/ssrf-test")

    Result: HTTP 200, and the listener captured the full request including any Bearer auth headers.

  3. Port scanning confirmed via error differentiation:

    • Open port (PostgreSQL 5432): EOFError (connection accepted then closed)
    • Closed port: ConnectionError (connection refused)
  4. SsrfProtection properly blocks the same requests:

    OpenProject::SsrfProtection.post("http://172.23.0.1:9999/test")
    # => raises SsrfFilter::PrivateIPAddress

Root Cause Pattern

OpenProject.httpx is used in 15+ locations across the codebase. The SsrfProtection wrapper exists and works correctly but is only applied to webhooks. The fix is to use SsrfProtection (or equivalent IP range validation) for ALL server-side HTTP calls to admin-configured URLs.

Impact

  • Internal network reconnaissance via port scanning
  • Cloud instance metadata access (IAM credential theft on AWS/GCP/Azure)
  • Bearer token exfiltration to attacker-controlled servers (Jira import)
  • Bypass of network segmentation in multi-tier architectures

Suggested Fix

Replace OpenProject.httpx with OpenProject::SsrfProtection for all outgoing HTTP requests to user/admin-controlled URLs, or add IP range validation before making requests.

References

Best regards,
William Goodfellow

Severity

Moderate

CVSS overall score

This score calculates overall vulnerability severity from 0 to 10 and is based on the Common Vulnerability Scoring System (CVSS).
/ 10

CVSS v3 base metrics

Attack vector
Network
Attack complexity
Low
Privileges required
High
User interaction
None
Scope
Changed
Confidentiality
High
Integrity
None
Availability
None

CVSS v3 base metrics

Attack vector: More severe the more the remote (logically and physically) an attacker can be in order to exploit the vulnerability.
Attack complexity: More severe for the least complex attacks.
Privileges required: More severe if no privileges are required.
User interaction: More severe when no user interaction is required.
Scope: More severe when a scope change occurs, e.g. one vulnerable component impacts resources in components beyond its security scope.
Confidentiality: More severe when loss of data confidentiality is highest, measuring the level of data access available to an unauthorized user.
Integrity: More severe when loss of data integrity is the highest, measuring the consequence of data modification possible by an unauthorized user.
Availability: More severe when the loss of impacted component availability is highest.
CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:N/A:N

CVE ID

No known CVE

Weaknesses

Server-Side Request Forgery (SSRF)

The web server receives a URL or similar request from an upstream component and retrieves the contents of this URL, but it does not sufficiently ensure that the request is being sent to the expected destination. Learn more on MITRE.

Credits