-
Notifications
You must be signed in to change notification settings - Fork 0
Feature/webhook integration #6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
- Introduced ScrollArea for better content management. - Applied text-xs for smaller font sizes in various elements. - Refined button styles and spacing.
| 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
URL
user-provided value
Show autofix suggestion
Hide autofix suggestion
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 thaturl.hostnameis 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_HOSTNAMESarray 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.
-
Copy modified lines R5-R10 -
Copy modified lines R55-R63
| @@ -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 }); |
No description provided.