What Changed

The DownloadThreatReports Azure Function in the Cofense Intelligence connector has been substantially rewritten to eliminate SSRF and credential leakage vulnerabilities. The original code accepted a caller-controlled url parameter and passed it directly to requests.get() with Cofense credentials attached – allowing any caller with Function access to direct authenticated HTTP requests to arbitrary hosts.

Vulnerability: Caller-Controlled URL (SSRF and Credential Leakage)

The original function accepted a full URL from the caller and made an authenticated request to it. A caller supplying a malicious URL would cause the Function to issue an authenticated request to an attacker-controlled host, exfiltrating COFENSE_USERNAME and COFENSE_PASSWORD via HTTP Basic Auth headers. Internal network targets (IMDS metadata service, VNet-internal services) were equally reachable via this vector.

Fix: Server-Side URL Construction with Defense-in-Depth

The function now accepts only a threat/report identifier (id, threat_id, or report_id) and an optional format (pdf/html):

  1. Server-side URL construction – the full request URL is built from the configured COFENSE_BASE_URL constant; caller input is restricted to a single path segment.
  2. Path segment encoding – threat_id is percent-encoded before interpolation, preventing path traversal via embedded /, .., ?, or # characters.
  3. Hostname allowlist – the constructed URL hostname is validated against the configured COFENSE_BASE_URL host (exact match or subdomain) before any request is made.
  4. Private/loopback address blocking – the hostname is DNS-resolved and checked against private, loopback, and link-local ranges; resolution failures are treated as disallowed (fail-closed).
  5. HTTPS enforcement – the function returns HTTP 500 if COFENSE_BASE_URL is not HTTPS.
  6. Redirect disabled – allow_redirects=False prevents a compromised or misconfigured Cofense endpoint from redirecting the authenticated request to an attacker-controlled host.
  7. Filename sanitization – the file_name used for logging and content-disposition is derived from threat_id after stripping non-alphanumeric characters, rather than from the caller-supplied URL path.

Security Impact

Deployments running the pre-patch connector version have an active SSRF and credential exfiltration exposure. Any principal with HTTP access to the Azure Function endpoint could exfiltrate Cofense API credentials or probe internal network services using the Function network identity.

Breaking change warning: The input contract changes from accepting a full URL to accepting an id and optional format. Any existing callers (workbooks, Playbooks, or other integrations) passing a url parameter will receive HTTP 400. Review all integrations before deploying.

Known open issue (per reviewer): The _is_address_private() docstring incorrectly states fail-open behavior on DNS resolution failure, while the implementation is correctly fail-closed. This is a documentation inconsistency, not a logic defect – the fail-closed path is the correct security posture.

Performance note: socket.getaddrinfo() is called synchronously per request on the fixed COFENSE_BASE_URL hostname. Under DNS latency this may increase Function execution time. Consider caching the resolved addresses at cold-start.

Affected Files

Solutions/CofenseIntelligence/Data Connectors/CofenseIntelligenceDataConnector/DownloadThreatReports/__init__.py
(packaging artefacts: CofenseIntelligenceDataConnector.zip)