All Docs
FeaturesCalmony Sanctions MonitorUpdated March 11, 2026

Security Deep-Dive: SSRF Prevention in the OFSI Nightly CSV Sync

Security Deep-Dive: SSRF Prevention in the OFSI Nightly CSV Sync

Release: v0.1.52
Control: SEC-10
OWASP Category: Server-Side Request Forgery (SSRF)
Affected file: src/app/api/sanctions/nightly/route.ts


Background

The sanctions platform performs a nightly sync against the UK Office of Financial Sanctions Implementation (OFSI) consolidated list. As part of this process, the discoverLatestCSVUrl() function fetches the gov.uk OFSI publications page and uses a regular expression to extract the most recent CSV download URL dynamically — avoiding hardcoded links that can go stale as OFSI publishes updated lists.

The Vulnerability

Prior to v0.1.52, the URL returned by discoverLatestCSVUrl() was passed directly into a subsequent fetch() call without any validation:

// Before — no domain validation
const csvUrl = await discoverLatestCSVUrl();
const response = await fetch(csvUrl); // ⚠️ SSRF risk

This created a Server-Side Request Forgery (SSRF) vulnerability. Two realistic attack scenarios existed:

  1. Compromised upstream page — If the gov.uk OFSI page were defaced or its content delivery network tampered with, a malicious href could be injected into the page HTML, causing the platform's server to fetch from an attacker-controlled endpoint.
  2. Regex matching an unexpected href — A broad regex could inadvertently match an unrelated link on the page pointing to an internal network address (e.g. http://169.254.169.254/ for cloud metadata endpoints), leaking environment secrets or internal service responses.

The Fix

A domain allowlist check is now applied immediately after the URL is discovered, before any network request is made:

const ALLOWED_CSV_ORIGINS = [
  'https://assets.publishing.service.gov.uk/',
  'https://ofsistorage.blob.core.windows.net/',
];

const csvUrl = await discoverLatestCSVUrl();

const isAllowed = ALLOWED_CSV_ORIGINS.some((origin) => csvUrl.startsWith(origin));

if (!isAllowed) {
  // Fall through to known hardcoded fallback URLs
  console.warn(`Discovered CSV URL failed allowlist validation: ${csvUrl}`);
  return useFallbackCsvUrls();
}

const response = await fetch(csvUrl); // ✅ Safe — origin validated

Why these two origins?

OriginPurpose
https://assets.publishing.service.gov.uk/Primary CDN for UK government publications, used by the OFSI consolidated list
https://ofsistorage.blob.core.windows.net/Azure Blob Storage endpoint used by OFSI as a secondary/legacy distribution URL

Both origins use HTTPS, meaning transport-layer integrity is enforced in addition to the domain check.

Graceful degradation

Rather than throwing an error and halting the nightly sync entirely, a failed allowlist check falls through to the platform's hardcoded fallback CSV URLs. This ensures:

  • The sync job continues to run and deliver an up-to-date sanctions list under most conditions.
  • The validation failure is logged as a warning, triggering alerting for operator review.
  • No unvalidated URL is ever fetched by the server.

Impact Assessment

FactorAssessment
ExploitabilityRequires upstream gov.uk page compromise or regex manipulation — not directly exploitable by an end user
Impact if exploitedInternal network probing, metadata endpoint access, potential credential leakage
Fix complexityLow — a single startsWith allowlist check
Regression riskLow — fallback URLs provide continuity if the allowlist ever needs updating

Keeping the Allowlist Current

If OFSI migrates to a new CDN or storage domain in future, the ALLOWED_CSV_ORIGINS array in src/app/api/sanctions/nightly/route.ts must be updated before the old URLs are decommissioned. Monitor the OFSI publications page and SSRF-related warnings in application logs to detect any domain changes early.


This post is part of the platform's ongoing OWASP-aligned security hardening programme. See the Changelog for all security releases.