Skip to content

Conversation

@Muhammad-Jay
Copy link
Collaborator

No description provided.

- Introduced ScrollArea for better content management.
- Applied text-xs for smaller font sizes in various elements.
- Refined button styles and spacing.
@Muhammad-Jay Muhammad-Jay merged commit 11ef92c into main Dec 1, 2025
1 of 3 checks passed
Comment on lines +90 to +99
const webhookResponse = await fetch(destinationUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
// --- PAYLOAD INTEGRITY DEFENSE ---
'X-Webhook-Secret': secretKey,
'User-Agent': 'AICAP-Webhook-Dispatcher/1.0',
},
body: JSON.stringify(payload),
});

Check failure

Code scanning / CodeQL

Server-side request forgery Critical

The
URL
of this request depends on a
user-provided value
.

Copilot Autofix

AI 2 months ago

To reliably fix the SSRF vulnerability, the code should restrict outgoing requests to permitted domains using a hostname/domain allow-list rather than allowing arbitrary values from user input. This approach blocks attackers from crafting payloads targeting sensitive endpoints (internal IPs, cloud metadata URLs, etc.), even if SSRF filtering (protocol, IP blocklist) is bypassed due to logic or parsing issues.

Best way to fix:

  • Implement a constant array of allowed hostnames or domains, e.g., const ALLOWED_HOSTNAMES = ['webhook.example.com', 'hooks.mydomain.app'].
  • When parsing destinationUrl, check that url.hostname is present in (or a valid subdomain below) one of these permitted hostnames.
  • If the check fails, return a 403 (Forbidden) error.
  • This change should be made in the logic before the fetch() request (after parsing the input, before SSRF defenses and network call).
  • It's important to communicate rejection with a clear error message.

Required additions:

  • Add the ALLOWED_HOSTNAMES array near the top of the file (region before POST).
  • Add logic after parsing the URL (url = new URL(...)) but before the SSRF defenses, e.g. after line 48.

Suggested changeset 1
app/api/execute-webhook/route.ts

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/app/api/execute-webhook/route.ts b/app/api/execute-webhook/route.ts
--- a/app/api/execute-webhook/route.ts
+++ b/app/api/execute-webhook/route.ts
@@ -2,6 +2,12 @@
 import { URL } from 'url';
 import { promises as dns } from 'dns';
 
+// SSRF FIX: Only allow requests to approved hostnames/domains
+const ALLOWED_HOSTNAMES = [
+  'webhook.example.com',
+  'hooks.mydomain.app',
+  // Add more allowed hostnames/domains as needed
+];
 // Helper function to resolve the IP address of a hostname
 async function resolveIP(hostname) {
   try {
@@ -46,6 +52,15 @@
     return Response.json({ success: false, error: 'Invalid destination URL format.' }, { status: 400 });
   }
 
+  // SSRF FIX: Check host against allowlist
+  const hostnameIsAllowed = ALLOWED_HOSTNAMES.some(allowed => url.hostname === allowed || url.hostname.endsWith('.' + allowed));
+  if (!hostnameIsAllowed) {
+    return Response.json({
+      success: false,
+      error: `Target hostname "${url.hostname}" is not allowed by server SSRF policy.`
+    }, { status: 403 });
+  }
+
   // 2. --- SSRF DEFENSE 1: PROTOCOL LOCK ---
   if (url.protocol !== 'https:') {
     return Response.json({ success: false, error: 'Protocol violation. Only HTTPS endpoints are permitted for security reasons.' }, { status: 403 });
EOF
@@ -2,6 +2,12 @@
import { URL } from 'url';
import { promises as dns } from 'dns';

// SSRF FIX: Only allow requests to approved hostnames/domains
const ALLOWED_HOSTNAMES = [
'webhook.example.com',
'hooks.mydomain.app',
// Add more allowed hostnames/domains as needed
];
// Helper function to resolve the IP address of a hostname
async function resolveIP(hostname) {
try {
@@ -46,6 +52,15 @@
return Response.json({ success: false, error: 'Invalid destination URL format.' }, { status: 400 });
}

// SSRF FIX: Check host against allowlist
const hostnameIsAllowed = ALLOWED_HOSTNAMES.some(allowed => url.hostname === allowed || url.hostname.endsWith('.' + allowed));
if (!hostnameIsAllowed) {
return Response.json({
success: false,
error: `Target hostname "${url.hostname}" is not allowed by server SSRF policy.`
}, { status: 403 });
}

// 2. --- SSRF DEFENSE 1: PROTOCOL LOCK ---
if (url.protocol !== 'https:') {
return Response.json({ success: false, error: 'Protocol violation. Only HTTPS endpoints are permitted for security reasons.' }, { status: 403 });
Copilot is powered by AI and may make mistakes. Always verify output.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants