fix(security): resolve CWE-918 SSRF vulnerability in notification service

- Apply URL validation using security.ValidateWebhookURL() to all webhook
  HTTP request paths in notification_service.go
- Block private IPs (RFC 1918), cloud metadata endpoints, and loopback
- Add comprehensive SSRF test coverage
- Add CodeQL VS Code tasks for local security scanning
- Update Definition of Done to include CodeQL scans
- Clean up stale SARIF files from repo root

Resolves CI security gate failure for CWE-918.
This commit is contained in:
GitHub Actions
2025-12-24 03:53:35 +00:00
parent a9faf882f4
commit 323b2aa637
14 changed files with 1472 additions and 586 deletions

View File

@@ -2,3 +2,49 @@ export const isValidEmail = (email: string): boolean => {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
return emailRegex.test(email)
}
/**
* Checks if a string is a valid IPv4 address
*/
export const isIPv4 = (value: string): boolean => {
const ipv4Regex = /^(\d{1,3}\.){3}\d{1,3}$/
if (!ipv4Regex.test(value)) return false
const parts = value.split('.')
return parts.every(part => {
const num = parseInt(part, 10)
return num >= 0 && num <= 255
})
}
/**
* Checks if an IP is in a private/Docker range that may change on restart
*/
export const isPrivateOrDockerIP = (ip: string): boolean => {
if (!isIPv4(ip)) return false
const parts = ip.split('.').map(p => parseInt(p, 10))
// 10.0.0.0/8
if (parts[0] === 10) return true
// 172.16.0.0/12 (172.16.x.x - 172.31.x.x) - includes Docker bridge networks
if (parts[0] === 172 && parts[1] >= 16 && parts[1] <= 31) return true
// 192.168.0.0/16
if (parts[0] === 192 && parts[1] === 168) return true
return false
}
/**
* Checks if the value looks like a raw IP that could be a Docker container IP
*/
export const isLikelyDockerContainerIP = (value: string): boolean => {
if (!isIPv4(value)) return false
const parts = value.split('.').map(p => parseInt(p, 10))
// Docker default bridge: 172.17.x.x
// Docker user-defined: 172.18.x.x - 172.31.x.x
if (parts[0] === 172 && parts[1] >= 17 && parts[1] <= 31) return true
return false
}