feat: add Input validation to prevent ssrf in Notification Client
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:
- 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.
- Validate URL format: Use built-in URL parsing (e.g., the
URLclass) to ensure the provided string is a valid URL and to extract/validate its hostname. - Enforce via code: In
notification-client.ts, before performing the HTTP request, verify thatnotificationDetails.urlpoints 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 anotificationDetailsargument is passed in, and itsurlproperty 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
sendFrameNotificationto parse and checknotificationDetails.url. - Import the built-in
URLclass (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
🟡 Heimdall Review Status
| Requirement | Status | More Info | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Reviews |
🟡
0/1
|
Denominator calculation
|
@ptrgits is attempting to deploy a commit to the Coinbase Team on Vercel.
A member of the Team first needs to authorize it.