x402 icon indicating copy to clipboard operation
x402 copied to clipboard

feat: add Input validation to prevent ssrf in Notification Client

Open ptrgits opened this issue 1 month ago • 2 comments

Pull Request Description

I have identified a Server-Side Request Forgery (SSRF) vulnerability in the notification client implementation where user-supplied input is directly incorporated into outgoing HTTP requests without proper validation. This allows attackers to manipulate requests to target unintended API endpoints or internal resources.

const NOTIFICATION_SERVICE_URL = process.env.NOTIFICATION_SERVICE_URL || 'http://localhost:3000';

export interface NotificationDetails {
  url: string;
  title?: string;
  body?: string;
  icon?: string;
}
export async function sendFrameNotification(
  frameId: string,
  notificationDetails?: NotificationDetails
): Promise<void> {
  try {
    const response = await fetch(`${NOTIFICATION_SERVICE_URL}/api/notify`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        frameId,
        notification: notificationDetails,
      }),
    });
  } catch (error) {
    console.error('Failed to send notification:', error);
  }
}

Root Cause

The notificationDetails.url parameter

fix this SSRF issue need to ensure that the URL used for outbound requests is strictly controlled:

  1. Allow-list hostnames or domains: Only allow requests to URLs that match a list of safe, known hosts/domains. User input should not select an arbitrary URL.
  2. Validate URL format: Use built-in URL parsing (e.g., the URL class) to ensure the provided string is a valid URL and to extract/validate its hostname.
  3. Enforce via code: In notification-client.ts, before performing the HTTP request, verify that notificationDetails.url points to an allowed host/domain, otherwise reject with an error.

Required changes:

  • Define an allow-list of permitted hostnames (as a constant).
  • In sendFrameNotification, if a notificationDetails argument is passed in, and its url property is present, parse and check its hostname against the allow-list.
  • If not allowed, return an error and do NOT send the HTTP request.
  • Consider whether additional path or scheme constraints are necessary.

No changes are needed in app/api/notify/route.ts, since all validation will be managed server-side.

What is needed:

  • A new constant array for allowed hostnames.
  • Additional logic in sendFrameNotification to parse and check notificationDetails.url.
  • Import the built-in URL class (globally available in Node/Edge runtimes, so no new import required unless wanting to explicitly import).

Checklist

  • [x] I have formatted and linted my code
  • [x] All new and existing tests pass
  • [x] My commits are signed (required for merge) -- you may need to rebase if you initially pushed unsigned commits

ptrgits avatar Nov 22 '25 09:11 ptrgits

🟡 Heimdall Review Status

Requirement Status More Info
Reviews 🟡 0/1
Denominator calculation
Show calculation
1 if user is bot 0
1 if user is external 0
2 if repo is sensitive 0
From .codeflow.yml 1
Additional review requirements
Show calculation
Max 0
0
From CODEOWNERS 0
Global minimum 0
Max 1
1
1 if commit is unverified 0
Sum 1

cb-heimdall avatar Nov 22 '25 09:11 cb-heimdall

@ptrgits is attempting to deploy a commit to the Coinbase Team on Vercel.

A member of the Team first needs to authorize it.

vercel[bot] avatar Nov 22 '25 09:11 vercel[bot]