πŸ›οΈ

OFAC Sanctions List Update Dashboard

Office of Foreign Assets Control Β· U.S. Department of the Treasury

UNCLASSIFIED
--:--:-- Loading…
Automated daily sync active β€” next scheduled pull: 02:00 UTC  Β·  Data sourced from sanctionslist.ofac.treas.gov  Β·  Snapshots retained for 90 days
Total SDN Records
12,847
SDN.CSV primary list
SDN Aliases
17,304
ALT.CSV alternate names
Consolidated Primary
15,612
CONS_PRIM.CSV
Consolidated Aliases
21,088
CONS_ALT.CSV
Net Added (7d)
+47
Across all lists
Net Removed (7d)
βˆ’12
Across all lists
Last Change Detected
2025‑07‑14
SDN.CSV updated
Snapshots Stored
284
~90 days history

πŸ“‹ Specially Designated Nationals β€” Primary List

https://sanctionslist.ofac.treas.gov/Home/SdnList β†’ SDN.CSV
Records
12,847
Last Pulled
2025-07-14 02:03 UTC
File Size
4.2 MB
SHA-256
a3f8c1…d72e
β–² 23 Added
β–Ό 5 Removed
≑ 12,829 Unchanged
Last change: 2025-07-14 02:03 UTC (vs snapshot 2025-07-13)
β–²

Newly Added Entries

23
SDN IDNameTypeProgram(s)CountryRemarks
β–Ό

Removed Entries

5
SDN IDNameTypeProgram(s)CountryRemarks

πŸ“‹ SDN Alternate Names

https://sanctionslist.ofac.treas.gov/Home/SdnList β†’ ALT.CSV
Records
17,304
Last Pulled
2025-07-14 02:03 UTC
File Size
2.1 MB
β–² 0 Added
β–Ό 0 Removed
≑ 17,304 Unchanged
Last change: 2025-07-11 02:01 UTC (3 days ago)
ℹ️

No changes detected in latest comparison

βœ…
ALT.CSV matches the previous snapshot exactly.
Last checked: 2025-07-14 02:03 UTC Β· Previous change: 2025-07-11 (added 8, removed 2)

πŸ“‹ Consolidated Sanctions β€” Primary List

https://sanctionslist.ofac.treas.gov/Home/ConsolidatedList β†’ CONS_PRIM.CSV
Records
15,612
Last Pulled
2025-07-14 02:05 UTC
File Size
5.8 MB
β–² 12 Added
β–Ό 7 Removed
≑ 15,593 Unchanged
Last change: 2025-07-14 02:05 UTC
β–²

Newly Added Entries

12
IDNameTypeProgram(s)CountryDOB
β–Ό

Removed Entries

7
IDNameTypeProgram(s)CountryDOB

πŸ“‹ Consolidated Sanctions β€” Alternate Names

https://sanctionslist.ofac.treas.gov/Home/ConsolidatedList β†’ CONS_ALT.CSV
Records
21,088
Last Pulled
2025-07-14 02:05 UTC
File Size
3.4 MB
β–² 9 Added
β–Ό 0 Removed
≑ 21,079 Unchanged
Last change: 2025-07-14 02:05 UTC
β–²

Newly Added Alternate Names

9
Alt IDLinked SDN IDAlt NameAlt TypeProgram(s)

βš™οΈ System Architecture & Setup Guide

This dashboard is served by a lightweight Python/Flask app. A systemd timer (or cron job) handles daily downloads and diff computation. Snapshots are stored as gzipped CSV files.

1. Directory Structure

# /opt/ofac-dashboard/
β”œβ”€β”€ app.py               # Flask web server
β”œβ”€β”€ fetch_and_diff.py    # Download + diff engine
β”œβ”€β”€ snapshots/
β”‚   β”œβ”€β”€ SDN/
β”‚   β”‚   β”œβ”€β”€ 2025-07-13.csv.gz
β”‚   β”‚   └── 2025-07-14.csv.gz
β”‚   β”œβ”€β”€ ALT/
β”‚   β”œβ”€β”€ CONS_PRIM/
β”‚   └── CONS_ALT/
β”œβ”€β”€ diffs/
β”‚   β”œβ”€β”€ SDN/
β”‚   β”‚   └── 2025-07-14.json   # added[], removed[]
β”‚   └── ...
└── templates/
    └── index.html

2. fetch_and_diff.py

#!/usr/bin/env python3
import requests, gzip, csv, json, hashlib
from pathlib import Path
from datetime import date

LISTS = {
  "SDN":       "https://sanctionslist.ofac.treas.gov/Home/SdnList/SDN.CSV",
  "ALT":       "https://sanctionslist.ofac.treas.gov/Home/SdnList/ALT.CSV",
  "CONS_PRIM": "https://sanctionslist.ofac.treas.gov/Home/ConsolidatedList/CONS_PRIM.CSV",
  "CONS_ALT":  "https://sanctionslist.ofac.treas.gov/Home/ConsolidatedList/CONS_ALT.CSV",
}
BASE = Path("/opt/ofac-dashboard")
today = date.today().isoformat()

for name, url in LISTS.items():
    snap_dir = BASE / "snapshots" / name
    diff_dir = BASE / "diffs" / name
    snap_dir.mkdir(parents=True, exist_ok=True)
    diff_dir.mkdir(parents=True, exist_ok=True)

    r = requests.get(url, timeout=60)
    r.raise_for_status()
    rows_new = set(r.text.splitlines())

    prev = sorted(snap_dir.glob("*.csv.gz"))
    rows_old = set()
    if prev:
        with gzip.open(prev[-1], "rt") as f:
            rows_old = set(f.read().splitlines())

    added   = rows_new - rows_old
    removed = rows_old - rows_new

    with gzip.open(snap_dir / f"{today}.csv.gz", "wt") as f:
        f.write(r.text)

    diff = {"date": today, "added": list(added), "removed": list(removed),
            "total": len(rows_new), "sha256": hashlib.sha256(r.content).hexdigest()}
    with open(diff_dir / f"{today}.json", "w") as f:
        json.dump(diff, f)
    print(f"{name}: +{len(added)} -{len(removed)}")

3. Systemd Timer (recommended)

# /etc/systemd/system/ofac-fetch.service
[Unit]
Description=OFAC List Fetch and Diff

[Service]
Type=oneshot
ExecStart=/opt/ofac-dashboard/venv/bin/python /opt/ofac-dashboard/fetch_and_diff.py
User=ofac

# /etc/systemd/system/ofac-fetch.timer
[Unit]
Description=Daily OFAC fetch at 02:00 UTC

[Timer]
OnCalendar=*-*-* 02:00:00 UTC
Persistent=true

[Install]
WantedBy=timers.target

# Enable:
systemctl enable --now ofac-fetch.timer

4. Alternative: crontab

# crontab -e
0 2 * * * /opt/ofac-dashboard/venv/bin/python /opt/ofac-dashboard/fetch_and_diff.py >> /var/log/ofac-fetch.log 2>&1

5. Flask server (app.py excerpt)

#!/usr/bin/env python3
from flask import Flask, render_template, jsonify
import json
from pathlib import Path

app = Flask(__name__)
BASE = Path("/opt/ofac-dashboard")

@app.route("/")
def index():
    data = {}
    for name in ["SDN","ALT","CONS_PRIM","CONS_ALT"]:
        diffs = sorted((BASE/"diffs"/name).glob("*.json"))
        if diffs:
            data[name] = json.loads(diffs[-1].read_text())
    return render_template("index.html", data=data)

@app.route("/api/history/<list_name>")
def history(list_name):
    diffs = sorted((BASE/"diffs"/list_name).glob("*.json"))
    return jsonify([json.loads(d.read_text()) for d in diffs[-30:]])

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8080)

πŸ“… Recent Change History (SDN.CSV β€” last 7 days)