Sanctions.Net 0.1.1

dotnet add package Sanctions.Net --version 0.1.1
                    
NuGet\Install-Package Sanctions.Net -Version 0.1.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Sanctions.Net" Version="0.1.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Sanctions.Net" Version="0.1.1" />
                    
Directory.Packages.props
<PackageReference Include="Sanctions.Net" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Sanctions.Net --version 0.1.1
                    
#r "nuget: Sanctions.Net, 0.1.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Sanctions.Net@0.1.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Sanctions.Net&version=0.1.1
                    
Install as a Cake Addin
#tool nuget:?package=Sanctions.Net&version=0.1.1
                    
Install as a Cake Tool

Sanctions.NET

Sanctions name-screening for .NET against the OFAC, UN and EU consolidated lists. Zero dependencies, offline-capable, built for fintech compliance teams.

There is no good open-source sanctions screening library in .NET. Compliance engineers either pay for a vendor platform or hand-roll CSV downloads and string comparisons inside their payment services. Sanctions.NET packages the boring, correctness-critical parts: tolerant feed parsers, a tested normalization pipeline and composable fuzzy matchers, behind a four-line API.

Quickstart

using Sanctions.Net;

var screener = await SanctionsScreener.CreateAsync(); // downloads the lists
ScreeningResult result = screener.Screen("Ayman al-Zawahiri");

if (result.IsMatch)
{
    foreach (var match in result.Matches) // ordered by score, best first
    {
        Console.WriteLine($"{match.Score:F1} {match.ListSource} {match.ListEntryId} {match.MatchedName}");
    }
}

Each ScreeningMatch carries ListSource, MatchedName, Score (0-100), EntityType, ListEntryId and Aliases.

List sources

List Format Default URL Update cadence
OFAC SDN CSV https://sanctionslistservice.ofac.treas.gov/api/PublicationPreview/exports/SDN.CSV As designations are made, often several times a week
OFAC SDN alternate names CSV https://sanctionslistservice.ofac.treas.gov/api/PublicationPreview/exports/ALT.CSV Published alongside SDN.CSV
OFAC Consolidated (non-SDN) CSV https://sanctionslistservice.ofac.treas.gov/api/PublicationPreview/exports/CONS_PRIM.CSV Same cadence as SDN actions
OFAC Consolidated alternate names CSV https://sanctionslistservice.ofac.treas.gov/api/PublicationPreview/exports/CONS_ALT.CSV Published alongside CONS_PRIM.CSV
UN Security Council Consolidated XML https://scsanctions.un.org/resources/xml/en/consolidated.xml When sanctions committees list or delist
EU Consolidated Financial Sanctions XML https://webgate.ec.europa.eu/fsd/fsf/public/files/xmlFullSanctionsList_1_1/content?token=... Regenerated whenever EU restrictive measures change

OFAC URLs point at the official Sanctions List Service (the retired treasury.gov/ofac/downloads paths only work through a courtesy redirect). The OFAC providers download both the primary file and the alternate names (ALT) file and join the alternate names onto each entity by entity number, so aliases come from the canonical ALT feed, not just the a.k.a. fragments in the remarks column.

The UN URL currently serves the legacy consolidated schema (the feed redirects to consolidatedLegacyByPRN.xml); the parser targets that schema. The EU default URL uses the DG FISMA public shared token, verified working against the live feed. If your organisation is registered with DG FISMA, plug in your own tokenised URL:

var options = new ScreeningOptions
{
    EuConsolidatedUrl = "https://webgate.ec.europa.eu/fsd/fsf/public/files/xmlFullSanctionsList_1_1/content?token=YOUR-TOKEN",
};

Every feed URL is overridable the same way (OfacSdnUrl, OfacSdnAltUrl, OfacConsolidatedUrl, OfacConsolidatedAltUrl, UnConsolidatedUrl), which also makes internal mirrors easy.

Parsers are tolerant at row level: malformed rows are skipped, never thrown on, and the counts are surfaced per list through screener.ParseReports. Failures fail loudly instead of silently screening nothing: a feed that cannot be downloaded, is larger than the 512 MB safety cap, or parses to zero entities throws a typed exception (SanctionsListDownloadException, EmptySanctionsListException) at construction or refresh time. Exception messages never include URL query strings, so EU tokens stay out of logs and error trackers.

Matchers

Scoring is the best result across the enabled matchers, per name variant (primary name and every alias).

Matcher Catches Score
ExactNormalizedMatcher Casing, diacritics, punctuation and spacing differences (NÚÑEZ, José vs Nunez Jose) 100 or 0
TokenSortMatcher Reordered names (AL-ZAWAHIRI AYMAN vs Ayman al-Zawahiri) 100 or 0
JaroWinklerMatcher Misspellings and transliteration drift (Zawahiry vs Zawahiri), also on the token-sorted form 0-100

All three run by default. Compose your own set:

using Sanctions.Net;
using Sanctions.Net.Matching;

var options = new ScreeningOptions
{
    Matchers = [new ExactNormalizedMatcher(), new TokenSortMatcher()],
    Threshold = 90,
};

Normalization (shared by every matcher) lowercases, folds diacritics and combining marks, removes apostrophes, converts remaining punctuation to spaces and collapses whitespace. Invisible and format characters (zero-width spaces, joiners, the BOM, soft hyphen, word joiner, bidirectional controls and blank-rendering fillers such as the Hangul fillers) are stripped rather than treated as separators, so an evader cannot split a name with hidden characters to slip past exact or token-sort matching. Non-Latin scripts (Arabic, Cyrillic, CJK) pass through and match exactly against original-script aliases carried on the lists.

Known limitation: only Basic Multilingual Plane invisible characters are stripped. Astral-plane (supplementary) invisible code points such as the Unicode tag characters (U+E0000..U+E007F) and the variation-selector supplement (U+E0100..U+E01EF) are not yet handled; codepoint-aware normalization is planned for 0.2.

Offline / air-gapped mode

Screen from files you distribute yourself, with no network access:

var screener = await SanctionsScreener.CreateFromFilesAsync(new Dictionary<ListSource, string>
{
    [ListSource.OfacSdn] = "/data/sdn.csv",
    [ListSource.UnConsolidated] = "/data/un-consolidated.xml",
    [ListSource.EuConsolidated] = "/data/eu-consolidated.xml",
});

Offline mode takes one file per list, so OFAC aliases come from the remarks column only; the ALT join currently applies to downloaded mode. If you need full alias coverage offline, mirror the feeds internally and point the URL overrides at your mirror.

await screener.UpdateAsync() refreshes from the original source in both modes (re-downloads, or re-reads the files) and swaps the index atomically, so in-flight Screen calls are never disrupted.

HttpClient is injected via ScreeningOptions.HttpClient, so IHttpClientFactory-managed clients work naturally. Lists are downloaded once at startup and held in memory; screening itself never touches the network.

Threshold guidance

The default threshold is 85 (ScreeningDefaults.DefaultThreshold).

  • 85 is a sensible onboarding/KYC default: it catches one-character misspellings and transliteration variants of multi-token names.
  • 90-95 suits high-volume payment screening where analysts review every hit and false positives are costly.
  • 100 means exact-after-normalization only (including reordering via token sort). Use it only when you accept missing misspellings.
  • Short queries deserve care: Jaro-Winkler rewards shared prefixes, so a single-token query can score in the high 80s against short list names. If you screen single tokens, consider a higher threshold or an exact/token-sort-only matcher set.
  • Query length is not capped by the library. If you screen user-supplied input in a server context, bound the input length at your API boundary before calling Screen.

Screen both directions of doubt: a false negative is a regulatory breach, a false positive is an analyst review. Tune toward the cheaper failure.

Disclaimer

Sanctions.NET is a screening aid, not legal or compliance advice. Matching a name is not a sanctions determination, and not matching is not clearance. Screening programs need qualified compliance oversight, list-update monitoring and documented review procedures.

Roadmap

  • Fuzzy date-of-birth matching to cut false positives on common names
  • PEP (politically exposed persons) feed support
  • Delta updates with ETag / If-Modified-Since instead of full re-downloads
  • Phonetic matchers (Soundex/Metaphone) and candidate indexing/blocking for large-scale throughput
  • Codepoint-aware Jaro-Winkler and full-width (FormKD) folding for CJK inputs
  • ALT-file support in offline mode and IAsyncDisposable

License

MIT, copyright Israel Iyonsi.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net8.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.1.1 98 8/7/2026
0.1.0 100 8/3/2026