The U.S. Treasury's Office of Foreign Assets Control (OFAC) publishes sanctioned digital currency addresses as part of its Specially Designated Nationals (SDN) list. This data is freely available — but it's buried inside a ~120MB XML file alongside thousands of non-crypto sanctions entries, with no separation by blockchain network.
Commercial services like Chainalysis charge significant fees to provide this same public data in a usable format. This tool does it for free. It downloads the official OFAC SDN Advanced XML, parses out every "Digital Currency Address" feature along with entity metadata (name, sanctions programs, listing date), infers the blockchain network from address format and ticker context, and publishes structured, per-chain JSON files — updated daily and committed directly to this repository.
Inspired by 0xB10C/ofac-sanctioned-digital-currency-addresses, which organizes addresses by ticker symbol (ETH.txt, XBT.txt, USDT.txt). This project takes a different approach: organizing by chain (ethereum.json, bitcoin.json, tron.json) — which is what compliance engines and on-chain screening tools actually need. A USDT address on Tron and a USDT address on Ethereum require different screening logic, and this tool handles that distinction automatically.
- Downloads the SDN Advanced XML (~120MB) from OFAC daily
- Extracts all digital currency addresses by scanning the XML's
FeatureTypereference table for "Digital Currency Address" entries, then matching eachFeatureon sanctioned entity profiles to its ticker and address value - Resolves multi-chain tokens like USDT and USDC (which exist on Ethereum, Tron, BSC, etc.) by inferring the correct chain from address format — a
0xprefix means EVM, aTprefix means Tron, etc. - Publishes per-chain JSON files with full entity metadata, ready for direct integration into compliance pipelines, smart contract allowlists, or monitoring dashboards
Fetch the latest sanctioned addresses for any chain:
# Ethereum addresses
curl https://raw.githubusercontent.com/cylon56/ofac-naughtylist/main/data/chains/ethereum.json
# Bitcoin addresses
curl https://raw.githubusercontent.com/cylon56/ofac-naughtylist/main/data/chains/bitcoin.json
# All addresses across all chains
curl https://raw.githubusercontent.com/cylon56/ofac-naughtylist/main/data/all_addresses.jsonLast updated: 2026-08-08 | 961 addresses across 94 sanctioned entities
| Chain | Addresses | Last Added | File |
|---|---|---|---|
| Bitcoin | 530 | 2026-08-07 | data/chains/bitcoin.json |
| Tron | 276 | 2026-08-07 | data/chains/tron.json |
| Ethereum | 104 | 2026-08-07 | data/chains/ethereum.json |
| Litecoin | 13 | 2026-07-13 | data/chains/litecoin.json |
| Monero | 11 | 2025-03-04 | data/chains/monero.json |
| Bitcoin Cash | 7 | 2022-11-09 | data/chains/bitcoin_cash.json |
| Solana | 6 | 2026-08-07 | data/chains/solana.json |
| Dash | 5 | 2026-07-13 | data/chains/dash.json |
| Zcash | 4 | 2026-07-13 | data/chains/zcash.json |
| Bitcoin Gold | 1 | 2020-09-16 | data/chains/bitcoin_gold.json |
| Bitcoin SV | 1 | 2020-09-10 | data/chains/bitcoin_sv.json |
| Ripple | 1 | 2021-11-08 | data/chains/ripple.json |
| Unknown | 1 | 2026-08-07 | data/chains/unknown.json |
| Verge | 1 | 2021-04-15 | data/chains/verge.json |
Additional supported chains (no explicit sanctions): Arbitrum, BSC, Ethereum Classic. Note that EVM addresses sanctioned on Ethereum are valid on all EVM-compatible chains — an address flagged on Ethereum should be treated as sanctioned on Arbitrum, BSC, etc. as well. Check the evm_compatible field in the output to identify these addresses.
Addresses that can't be mapped to a known chain are placed in data/chains/unknown.json.
Each per-chain JSON file contains:
{
"chain": "ethereum",
"source_list": "SDN",
"source_xml_url": "https://www.treasury.gov/ofac/downloads/sanctions/1.0/sdn_advanced.xml",
"address_count": 312,
"addresses": [
{
"address": "0x7F367cC41522cE07553e823bf3be79A889DEbe1B",
"ofac_tickers": ["ETH"],
"evm_compatible": false,
"entity_id": 39498,
"entity_name": "LAZARUS GROUP",
"programs": ["CYBER2", "DPRK3"],
"date_listed": "2022-04-14",
"source_feature_ids": [52341]
}
]
}Timestamps are centralized in data/metadata.json:
last_checked: when the OFAC source was last checked for updateslast_updated: when addresses were last added or removed from the list
See data/metadata.json for aggregate statistics and schema version.
- Daily cron (00:00 UTC) triggers the update (GitHub Actions or Railway)
- Download the SDN Advanced XML (~120MB) from OFAC
- Parse XML to extract all "Digital Currency Address" features with entity metadata
- Categorize each address by chain using ticker mapping + address format inference
- Generate per-chain JSON files, combined file, and metadata
- Refresh the snapshot table in this README from the new metadata
- Commit changes to
data/andREADME.mdif anything changed
Requires Python 3.11+.
git clone https://github.com/cylon56/ofac-naughtylist.git
cd ofac-naughtylist
pip install -r requirements.txt
# Run full pipeline (downloads ~80MB XML from OFAC, writes to data/)
python -m src.main
# Run with a local XML file (skip download)
python -m src.main --xml ./sdn_advanced.xml
# Write output to a custom directory
python -m src.main --output-dir ./my-output
# Verbose logging (shows discovered tickers, parse progress)
python -m src.main -v
# See all options
python -m src.main --helppip install -r requirements.txt -r requirements-dev.txt
pytest tests/ -vThe test suite uses a small hand-crafted XML fixture (tests/fixtures/sample_sdn_advanced.xml) covering multi-ticker deduplication, multi-chain token inference, unknown ticker fallback, and all supported address formats. No network access required.
Railway can run this as a daily cron job that automatically commits updated data back to GitHub.
-
Create a GitHub Personal Access Token with
contents: writepermission scoped to this repository. Go to GitHub Settings > Developer settings > Fine-grained personal access tokens. -
Create a new Railway project at railway.com:
- Click New Project > Deploy from GitHub repo
- Select this repository
- Railway will auto-detect the
Dockerfileandrailway.json
-
Set environment variables in the Railway service settings:
Variable Value Description GITHUB_TOKENghp_...GitHub PAT with repo write access GITHUB_REPOcylon56/ofac-naughtylistOwner/repo format GITHUB_BRANCHmainBranch to push updates to -
Verify cron schedule: Railway will read
railway.jsonand configure the service as a cron job running daily at 00:00 UTC. You can adjust the schedule in the Railway dashboard under Settings > Cron Schedule. -
Test manually: Trigger a one-off run from the Railway dashboard to verify the pipeline works end-to-end.
The scripts/railway_cron.py script:
- Clones the repo (shallow) using the GitHub token
- Runs the full OFAC pipeline (which also refreshes the README snapshot)
- Commits and pushes any
data/orREADME.mdchanges back to the repository
This runs as a cron job (not an always-on service), so you only pay for the ~2-3 minutes of compute per daily run. Railway's free tier is usually sufficient.
See CONTRIBUTING.md. The main contribution surface is config/chain_mapping.yaml for adding new chains and tickers.
See DISCLAIMER.md. This tool is NOT a substitute for a comprehensive sanctions compliance program.