Skip to content

Open-source inventory ​

Every third-party component evaluated for MyDLP, with the decision and the evidence behind it. Nothing is adopted on the basis that its repository is public.

Verification date: 2026-09-15. Licence facts below were read from the project's own LICENSE file or the GitHub licence API on that date, not from memory or from a summary site. Re-verify before each release; see Licence policy for the CI gate that enforces this.

No permissive licence is obligation-free. MIT, BSD and Apache-2.0 all require the copyright notice and licence text to travel with any redistribution, and Apache-2.0 additionally requires preserving NOTICE content. Those obligations are discharged in Third-party notices.


1. Adopted - linked into the product ​

These are compiled into the distributed binaries. All are permissive and all appear in the generated SBOM with pinned versions and hashes.

1.1 Rust, server and agent ​

ProjectRepositoryPurposeVersionSPDXIntegrationDistributedModifiedNotice obligationStatus
tokiogithub.com/tokio-rs/tokioAsync runtime1.44.xMITstatic libraryyesnoMIT copyright + licence textApproved
axumgithub.com/tokio-rs/axumHTTP server0.8.xMITstatic libraryyesnoMIT copyright + licence textApproved
tower / tower-httpgithub.com/tower-rsMiddleware0.5.x / 0.6.xMITstatic libraryyesnoMIT copyright + licence textApproved
hypergithub.com/hyperium/hyperHTTP core1.6.xMITstatic libraryyesnoMIT copyright + licence textApproved
sqlxgithub.com/launchbadge/sqlxPostgreSQL access, migrations0.8.xMIT OR Apache-2.0static libraryyesnoApache-2.0 elected; retain NOTICEApproved
serde / serde_jsongithub.com/serde-rsSerialisation1.0.xMIT OR Apache-2.0static libraryyesnoApache-2.0 electedApproved
regexgithub.com/rust-lang/regexLinear-time pattern matching1.11.xMIT OR Apache-2.0static libraryyesnoApache-2.0 electedApproved
aho-corasickgithub.com/BurntSushi/aho-corasickMulti-keyword matching1.1.xUnlicense OR MITstatic libraryyesnoMIT electedApproved
ed25519-dalekgithub.com/dalek-cryptography/curve25519-dalekBundle and request signatures2.1.xBSD-3-Clausestatic libraryyesnoBSD-3 copyright, conditions and disclaimer; no endorsement use of contributor namesApproved
sha2 / hmac / argon2github.com/RustCryptoHashing, HMAC, password hashingsee SBOMMIT OR Apache-2.0static libraryyesnoApache-2.0 electedApproved
rustlsgithub.com/rustls/rustlsTLS0.23.xApache-2.0 OR ISC OR MITstatic libraryyesnoApache-2.0 elected; retain NOTICEApproved
reqwestgithub.com/seanmonstar/reqwestAgent HTTP client0.12.xMIT OR Apache-2.0static libraryyesnoApache-2.0 electedApproved
rustls-native-certsgithub.com/rustls/rustls-native-certsReads the platform certificate store, so an internal CA or an inspecting proxy works without configuration (DLP-59)0.8.xMIT OR Apache-2.0 OR ISCstatic libraryyesnoApache-2.0 electedApproved. Reached through reqwest's rustls-tls-native-roots feature; already resolved in the lockfile before it was enabled
rcgengithub.com/rustls/rcgenInternal device CA0.13.xMIT OR Apache-2.0static libraryyesnoApache-2.0 electedApproved
x509-parsergithub.com/rusticata/x509-parserParses the timestamp authority's certificates for audit anchoring (DLP-1185); every signature is checked with ring0.16.xMIT OR Apache-2.0static libraryyesnoApache-2.0 electedApproved. Already in the tree through rcgen at this version; declared directly by the management API
rusqlite + libsqlite3-sysgithub.com/rusqlite/rusqliteAgent event queue0.32.xMITstatic libraryyesnoMIT copyright + licence textApproved
SQLite (bundled by libsqlite3-sys)sqlite.orgEmbedded databasebundledPublic domain (blessing)static libraryyesnoNo obligation, but provenance recordedApproved
blake3github.com/BLAKE3-team/BLAKE3Content hashing, shingling1.8.xCC0-1.0 OR Apache-2.0 OR Apache-2.0-with-LLVM-exceptionstatic libraryyesnoApache-2.0 elected, because CC0 carries no express patent grantApproved
unicode-normalizationgithub.com/unicode-rsNFKC normalisation0.1.xMIT OR Apache-2.0static libraryyesnoApache-2.0 elected; Unicode data terms also applyApproved
deunicodegithub.com/kornelski/deunicodeASCII transliteration1.6.xBSD-3-Clausestatic libraryyesnoBSD-3 conditionsApproved
notifygithub.com/notify-rs/notifyFilesystem watching8.2.xCC0-1.0static libraryyesnoNo attribution required, but see §4.1 on patentsApproved with a recorded caveat
zipgithub.com/zip-rs/zip2ZIP inspection on the endpoint8.6.xMITstatic libraryyesnoMIT copyright + licence textApproved. default-features = false, features = ["deflate"]: AES, zstd and bzip2 are decoders reached by untrusted input and a scanner cannot read inside an encrypted archive anyway, so carrying them buys nothing and costs attack surface
flate2github.com/rust-lang/flate2-rsDEFLATE for PDF content streams and ZIP entries1.1.xMIT OR Apache-2.0static libraryyesnoApache-2.0 electedApproved. Already reached transitively through reqwest's gzip support; now a direct dependency because the PDF extractor needs it
typed-path, zopflivia zipPath handling and deflatesee SBOMMIT OR Apache-2.0; Apache-2.0static libraryyesnoApache-2.0 elected where there is a choiceApproved
sevenz-rust2, lzma-rust2github.com/hasenbanck/sevenz-rust27z inspection on the endpoint (DLP-1177)0.23.x, 0.21.xApache-2.0static libraryyesnoApache-2.0 licence textApproved. default-features = false: the decoder only; AES, bzip2, deflate, zstd, LZ4, Brotli and PPMd stay out. The decoder has no memory limit of its own and reserves the LZMA dictionary a file declares, so archive.rs reads every dictionary, including the compressed header's, before decoding and refuses one above 64 MiB. The encoder is a dev-dependency, for test fixtures only. Since DLP-1477 lzma-rust2's own xz feature is enabled for its XZ reader, given a 96 MiB memory limit (XzReader::new_mem_limit); the feature brings sha2 0.11 beside the tree's 0.10
bzip2-rsgithub.com/paolobarbolini/bzip2-rs.tar.bz2 and .bz2 inspection on the endpoint (DLP-1477)0.1.xMIT OR Apache-2.0static libraryyesnoMIT copyright + licence textApproved. A pure-Rust decoder only. Chosen over the bzip2 crate, whose decoder libbz2-rs-sys is under the bzip2-1.0.6 licence, which deny.toml does not admit. Every decoded byte counts against the archive budget
ruzstdgithub.com/KillingSpark/zstd-rs.tar.zst and .zst inspection on the endpoint (DLP-1477)0.9.xMITstatic libraryyesnoMIT copyright + licence textApproved. default-features = false, features = ["std"]: the decoder, without the dictionary builder or the hash. Its default 100 MiB window bound is kept; every decoded byte counts against the archive budget
chardetnggithub.com/hsivonen/chardetngGuessing the code page of an unlabelled legacy text file on the endpoint (DLP-1674)1.0.xApache-2.0 OR MITstatic libraryyesnoApache-2.0 electedApproved. Mozilla's detector, by the author of encoding_rs, on which it is built; its other dependencies as built here (memchr, cfg-if; Cargo.lock lists no others) were already in the tree. Only consulted for text that is not valid UTF-8, and only on the first 64 KiB
chrono, uuid, tracing, thiserror, anyhow, clap, walkdir, infer, encoding_rsvariousUtilitiessee SBOMMIT OR Apache-2.0 (encoding_rs: Apache-2.0 OR MIT, plus WHATWG data)static libraryyesnoApache-2.0 electedApproved
chrono-tzhttps://github.com/chronotope/chrono-tzIANA timezone resolution for policy schedules0.10.4MIT OR Apache-2.0 (crate code); the embedded IANA tz database is released by its maintainers into the public domainstatic libraryyesnoApache-2.0 elected for the crate code; see the note below for the databaseApproved

The timezone database inside chrono-tz. The crate's own Rust code is dual-licensed MIT OR Apache-2.0 and we elect Apache-2.0, as with the rest of the utility crates. The data it compiles in is the IANA time zone database, which its maintainers release into the public domain - the upstream files carry an explicit public-domain dedication rather than a licence grant. That is a statement about the data, and it does not remove our obligation to carry the crate's own MIT/Apache notice, which THIRD_PARTY_NOTICES.md does.

The database is embedded in full rather than filtered to a subset of zones. chrono-tz offers filter-by-regex for that, and it was measured and rejected: a tenant chooses its zone at runtime from policy data, so a build-time subset would turn an unlisted zone into a schedule that silently does not work. Reading the host's /usr/share/zoneinfo instead was also rejected - it would make a security control behave differently on a container image that ships tzdata and one that does not.

The cost of that decision, measured on the agent binary (the same build, with CHRONO_TZ_TIMEZONE_FILTER=UTC and without):

BuildSize
Single zone (UTC only)9 983 384 bytes (9.52 MB)
Full IANA database11 877 336 bytes (11.33 MB)
Difference1 893 952 bytes (1.81 MB), +19.0%

Not distributed: the SPIKE-001 prototype. spikes/fanotify-block/ takes a direct dependency on libc (MIT OR Apache-2.0), which is already in the tree transitively and already carries its notice in Third-party notices. The crate is in the workspace so CI lints it and cargo-deny sees it, and nothing that ships links it, so no new obligation arises from it. It is recorded here only so a reviewer who notices a new direct libc edge does not have to go looking for what changed.

Read-only Active Directory adapter (DLP-1435, reviewed 2026-10-01) ​

The management API pins ldap3 0.12.1, repository github.com/inejge/ldap3, for certificate-verified LDAPS bind and bounded object searches only. Its downloaded crate's complete LICENSE-APACHE and LICENSE-MIT were read; Apache-2.0 is elected. No NOTICE file was found in that crate. default-features = false, tls-rustls-ring reuses the existing Rustls 0.23/ring stack; native TLS, OpenSSL, NTLM and GSSAPI are not enabled. The management API now declares Rust 1.85 for Edition-2024 dependencies; the endpoint agent's declared compiler requirement is unchanged. A build on the exact minimum compiler has not been demonstrated.

Seven new resolved versions, all unmodified static server libraries:

CrateVersionUpstreamLicence electionRedistribution obligation
ldap30.12.1github.com/inejge/ldap3Apache-2.0Retain licence and any upstream NOTICE
lber0.5.1github.com/inejge/ldap3MITRetain Ivan Nejgebauer/Gregor licence and copyright notice
asn1-rs0.7.2github.com/rusticata/asn1-rsApache-2.0Retain licence and any upstream NOTICE
asn1-rs-derive0.6.0github.com/rusticata/asn1-rsApache-2.0Retain licence and any upstream NOTICE
der-parser10.0.0github.com/rusticata/der-parserApache-2.0Retain licence and any upstream NOTICE
oid-registry0.8.1github.com/rusticata/oid-registryApache-2.0Retain licence and any upstream NOTICE
x509-parser0.18.1github.com/rusticata/x509-parserApache-2.0Retain licence and any upstream NOTICE

The five rusticata crates' Apache terms were compared to the complete reviewed Apache text; their complete MIT notices (Pierre Chifflier, 2017) were read as well. lber's complete MIT licence was read separately. Lockfile versions and checksums, not an upstream branch's current contents, identify the shipped code. cargo deny --locked check --hide-inclusion-graph licenses advisories bans reported advisories ok, bans ok, licenses ok; duplicate-version warnings were retained, not waived. Generated notices and the checksum-enriched SBOM must include these entries before release. No model, ruleset or dataset is imported. LDAP 0.11.5 was considered and rejected because it would introduce an older separate TLS stack instead of the Rustls version already used here.

An AD server remains an operator-supplied service, not redistributed software. The adapter deliberately does not request or persist group memberships, and rejects unsigned/plain LDAP, referral chasing and unverified TLS. The version pin is not an assertion that the library is invulnerable: the advisory gate must run at each release, and malformed/paginated responses have additional local bounds and tests.

1.2 Dashboard ​

ProjectPurposeVersionSPDXIntegrationDistributedNotice obligationStatus
react / react-domUI runtime18.3.1MITbundledyesMIT copyright + licence textApproved
react-router-domRouting6.30.xMITbundledyesMITApproved
@tanstack/react-queryServer state5.66.xMITbundledyesMITApproved
@tanstack/react-tableTables8.21.xMITbundledyesMITApproved
react-hook-formForms7.54.xMITbundledyesMITApproved
zodRuntime schema validation3.24.xMITbundledyesMITApproved
rechartsCharts2.15.xMITbundledyesMIT (also covers its d3 sub-dependencies, ISC/BSD-3)Approved
lucide-reactIcon set1.46.0ISCbundled, tree-shakenyesISC copyright + licence textApproved
@radix-ui/colorsColour scales3.0.0MITvalues only, see belowyesMITApproved
@fontsource/ibm-plex-sansSelf-hosted font for System Health5.3.0OFL-1.1selected WOFF2 files bundled by ViteyesCopyright + full OFL text; font is not sold separatelyApproved, unmodified redistribution only
typescript, vite, vitest, eslintBuild and test onlysee SBOMApache-2.0 / MITbuild-timenoNot redistributedApproved

Deliberately not used: no UI component kit and no remotely hosted font. Most of the console keeps the operating system type stack. System Health alone bundles selected IBM Plex Sans files locally, so it makes no third-party request at runtime. Its OFL-1.1 redistribution obligation is recorded in the generated notices.

The icons and the palette were original work until #458, and are not any more. The original reasoning - that an icon set or a design system carries redistribution terms, and that for icon sets in particular the attribution requirement is easy to violate silently - was sound. The conclusion drawn from it was not: both chosen replacements are under licences already on this project's allow-list, so the obligation is an entry in THIRD_PARTY_NOTICES.md rather than a risk. Hand-drawing eleven glyphs and hand-picking a palette bought no compliance benefit that a notice entry does not also buy.

How each is integrated, because they differ:

  • lucide-react is a normal runtime dependency, imported by name so the bundler ships only the icons actually used. Nine of roughly 1500 are referenced today; the measured cost is +7.5 kB raw, +2.1 kB gzipped on index.js. ISC requires the copyright notice and permission text to be retained, which THIRD_PARTY_NOTICES.md carries.
  • @radix-ui/colors ships CSS custom properties. Its values are transcribed into the semantic tokens in styles.css with the scale and step recorded in a comment beside each one, rather than importing its stylesheets wholesale - importing them would ship twelve steps of six scales in both themes, about 95% of which nothing references. It stays a declared dependency so the provenance of the values is checkable and the MIT notice is carried, and so a future step can be looked up rather than guessed.
  • @fontsource/ibm-plex-sans supplies the selected IBM Plex Sans WOFF2 files used only by System Health. The files are bundled locally and unmodified. OFL-1.1 requires the copyright and licence text to travel with them and forbids selling the font by itself; THIRD_PARTY_NOTICES.md records that obligation.

None is a component kit: no third-party markup, behaviour or class names enter the product, so the interface remains ours to change.

1.3 Build and CI tooling - used, not distributed ​

These never reach a customer. They are recorded because the licence policy applies to what we use as well as to what we ship, and because a reviewer should not have to guess why a tool appears in CI.

ProjectPurposeSPDXDistributedNotice obligation
Syft (anchore/syft)Generates the CycloneDX and SPDX SBOMsApache-2.0 - verified via the GitHub licence APINo - CI onlyNone, as it is not redistributed
anchore/sbom-actionInstalls Syft in CI (download-syft)Apache-2.0 - verifiedNoNone
cargo-deny, cargo-auditLicence and advisory gatesSee SBOMNoNone
cargo-fuzz, libfuzzer-sys, arbitraryFuzzing the hostile-input boundariesMIT OR Apache-2.0 (libfuzzer-sys also NCSA, from LLVM); verified via crates.ioNo - packages/detector-engine/fuzz is outside the workspace and nothing links itNone
GitleaksSecret scanning of our repositorySee §2.5 - scanning is not importing its rulesetNoNone

Syft's own output is not taken on trust: it does not carry lockfile checksums into either format, so tools/generate_sbom.py enriches and then verifies the documents, failing the build rather than emitting a partial one. The reasoning is in that script's docstring.

1.3 Deployed as separate services, not redistributed ​

ProjectPurposeVersionSPDXDistributedNotes
PostgreSQLPrimary datastore16.xPostgreSQL LicencenoOperator-supplied. Permissive; no obligation triggered because we do not redistribute it.
nginxReverse proxy, TLS termination1.24.xBSD-2-ClausenoOperator-supplied.

1.3 Build-only tooling ​

ProjectPurposeVersionSPDXIntegrationDistributedStatus
WiX ToolsetCompile the Windows MSI4.0.6MS-RLpinned local .NET tool, CI/release build onlynoApproved for build use; neither the tool nor its assemblies are shipped in the MSI

The WiX version is pinned in .config/dotnet-tools.json. The release pipeline uses it only after the executable payloads have been signed, so the MSI embeds the reviewed signed bytes rather than rebuilding product code inside the HSM trust boundary.

1.4 Vendored data - copied into the tree and compiled in ​

ProjectRepositoryPurposeVersionSPDXIntegrationDistributedModifiedNotice obligationStatus
SecLists 10k-most-common.txtgithub.com/danielmiessler/SecListsThe common-password list the management API refuses when a password is chosen (DLP-991)commit 913b3273 (2026-09-08)MITinclude_str! into the server binaryyes, in the server onlynoMIT copyright + licence textApproved

The licence text is kept beside the copy (apps/management-api/data/common-passwords.LICENSE) and read from there into Third-party notices by tools/generate_notices.py, whose VENDORED list is where a file like this is declared. Licence verified 2026-09-27 from the repository's own LICENSE. It is not in the agent: the rule lives in the API rather than in dlp-crypto, which the agent links.

2. Evaluated candidates ​

2.1 Microsoft Presidio - approved, not yet integrated ​

FieldValue
ProjectPresidio
Official repositorygithub.com/microsoft/presidio, which redirects to github.com/data-privacy-stack/presidio
PurposePII detection, context-aware recognisers, NER, anonymisation, image PII
Version consideredv0.95 (latest tag as of 2026-09-15)
LicenceMIT - verified by reading LICENSE at main: "The MIT License (MIT) - Copyright (c) Presidio Contributors."
Transitive licencesNot yet enumerated. Blocked on DLP-SPIKE-002.
Integration formIsolated internal HTTP service (never in the agent)
Distributed to customerYes, as a container image in on-premises deployments
ModifiedNo
Notice requirementMIT copyright and licence text for Presidio; separate review required for each NLP model
Commercial-use statusApproved for the code. Models require separate legal review
Security statusPython service processing untrusted text; must run network-isolated with CPU/memory/time limits and no filesystem write access
Replacement strategySits behind the DetectorKind::External { adapter: "presidio" } contract. Removing it degrades NER coverage; every other detector is unaffected

Material finding - governance change. The project has moved out of the Microsoft GitHub organisation to data-privacy-stack. The licence is unchanged, but the stewardship change is a supply-chain fact worth recording: a future relicence would come from a different governing body than the one originally assessed. Re-verify at each upgrade.

Material finding - model licensing is not the code licence. Presidio's default English pipeline uses spaCy models. en_core_web_lg is itself MIT, but its own metadata records its training source as:

json
{"name": "OntoNotes 5",
 "url": "https://catalog.ldc.upenn.edu/LDC2013T19",
 "license": "commercial (licensed by Explosion)"}

OntoNotes 5 is distributed by the Linguistic Data Consortium under a non-permissive licence. Explosion holds a commercial licence permitting them to ship the derived model; whether that permission extends to a downstream vendor redistributing the model inside a commercial product is a question for counsel, not for engineering.

Decision: the models are quarantined pending legal review (DLP-SPIKE-002). Presidio may be adopted for regex and checksum recognisers, which do not use a model, while NER remains gated. This is precisely the "models or datasets whose licensing is unclear" case the licence policy forbids shipping.

2.2 Apache Tika - not adoptable as published; four conditions to adopt ​

FieldValue
ProjectApache Tika
Official repositorygithub.com/apache/tika
PurposeFile-type detection, text and metadata extraction, embedded objects, PDF/DOCX/XLSX/PPTX, archives
Version assessed3.3.2, artefact tika-server-standard-3.3.2.jar, sha256 cdbe7fde7258…f77540. 4.0.0 is published and not assessed
LicenceApache-2.0 - verified via the GitHub licence API
Transitive licencesEnumerated: 134 artefacts, 119 allowed outright, 6 allowed by election, 7 not on the allow-list. Report: SPIKE-003, raw output SPIKE-003-tika-licence-report.txt
Integration formSandboxed container running tika-server-standard, invoked over HTTP
Distributed to customerYes, as a container image
ModifiedNo
Notice requirementApache-2.0 §4: licence copy, change notices, retained attribution, and the contents of Tika's NOTICE file reproduced in ours
Commercial-use statusNot adoptable as published. Four conditions below
Security statusDocument parsers are a large attack surface reached by untrusted input. Mandatory: container isolation, no network, read-only root filesystem, CPU/memory/time/page/recursion/decompression limits, request-id telemetry that never carries document content

Determination (DLP-SPIKE-003, 2026-09-15) ​

Two artefacts must be excluded:

ArtefactLicenceWhy
org.codelibs:jhighlight:1.1.1CDDL-1.0 OR LGPL-2.1+LGPL is forbidden, CDDL is not on the list. It syntax-highlights source into HTML; this product wants text, so nothing is lost
com.github.junrar:junrar:7.6.0UnRAR licenceIts own terms permit distribution inside other software, with a documentation statement. Excluded on cost, not legality: a non-OSI field-of-use restriction invites a question from every customer's licence review, and what it buys is RAR extraction

Five need an election recorded and the allow-list extended - all ordinary in the Java ecosystem, none a Tika peculiarity:

ArtefactsOptionsElect
jakarta.annotation-api, jakarta.websocket-api, jakarta.ws.rs-api, tyrus-standalone-clientEPL-2.0 OR GPL-2.0-with-classpath-exceptionEPL-2.0 - file-level copyleft on unmodified API jars
juniversalchardetMPL-1.1 OR GPL-3.0 OR LGPL-3.0MPL-1.1 - file-level copyleft; removing it instead would degrade charset detection on exactly the undeclared-encoding files a scanner meets
Jetty (6 artefacts)Apache-2.0 OR EPLApache-2.0

EDL 1.0 is BSD-3-Clause verbatim and clears seven more artefacts that a scanner would report as unknown.

Two further findings, independent of the licence list:

  • The artefact's own NOTICE is six lines for 134 bundled artefacts. Shading collapses META-INF, so redistributing the published jar as-is would not discharge the attribution obligations of the software inside it. The notices must be generated from the resolved dependency set.
  • Excluding a parser is not a configuration change. tika-server-standard is an uber-jar; disabling a parser in tika-config.xml stops it running but leaves the code in the bytes we distribute, and an obligation attaches to distribution rather than to execution. Dropping these needs a custom build from tika-server-core - a recurring cost that DLP-FEAT-011 must price. | Replacement strategy | Sits behind the extraction-service HTTP contract, and the native extractor covers more than this row used to say: text families, DOCX/XLSX/PPTX, PDF including Flate-compressed streams, and ZIP contents - all offline, in pure Rust, exercised end to end in packages/detector-engine/tests/office_documents.rs and packages/detector-engine/tests/archives.rs. What Tika would add is the long tail: the pre-2007 binary .doc/.xls/.ppt, ODF, and the formats behind OCR. So dropping it costs the long tail rather than office-format coverage, which is a materially smaller loss than this row previously implied and should be weighed that way when the licence decision is made |

Open obligation. tika-server-standard must be run through ScanCode or Syft and its transitive licences recorded before the image ships. Tracked as DLP-SPIKE-003. Until then the extraction service is contract-only.

2.3 Tesseract OCR - approved, language packs assessed separately ​

FieldValue
ProjectTesseract OCR
Official repositorygithub.com/tesseract-ocr/tesseract
PurposeText from scanned PDFs, images and screenshots
Version considered5.5.3 (released 2026-07-24)
LicenceApache-2.0 - verified via the GitHub licence API
Language packstesseract-ocr/tessdata_fast - Apache-2.0, verified by reading the repository's LICENSE. Covers aze, tur, eng, rus
Integration formSeparate container behind a pluggable OCR adapter
Distributed to customerYes, on-premises by default
ModifiedNo
Notice requirementApache-2.0 licence and NOTICE for both the engine and the trained-data repository, recorded as two separate entries
Commercial-use statusApproved, engine and the four language packs
Security statusImage decoders reached by untrusted input; run with page, image-size, resolution and time limits inside a container
Replacement strategyBehind an adapter interface. No customer document is sent to a third-party OCR service unless an operator explicitly enables it; the default is local

Note. Each language pack is licensed and recorded individually. Some community tessdata forks carry different terms; only the upstream tessdata_fast Apache-2.0 files are approved.

2.4 Pattern-matching engine - Rust regex selected ​

Benchmarked and reasoned in .

CandidateLicence (verified 2026-09-15)Decision
Rust regexMIT OR Apache-2.0Selected. Linear-time by construction: no backtracking, so catastrophic backtracking is impossible rather than merely mitigated. Pure Rust, cross-compiles, no native dependency
HyperscanBSD-3-Clause (GitHub reports NOASSERTION; the LICENSE file reads "Hyperscan is licensed under the BSD License. Copyright (c) 2015, Intel Corporation")Rejected for the MVP. x86-only with runtime CPU dispatch, a C build dependency, and awkward cross-compilation for the Windows agent. Licence is acceptable; the operational cost is not justified at current throughput
VectorscanBSD-3-Clause (Hyperscan fork; LICENSE adds VectorCamp and Arm copyrights)Rejected for the MVP, same reasoning. Recorded as the portable fallback if Hyperscan is ever needed on ARM
RE2BSD-3-ClauseRejected. Also linear-time, but adds a C++ dependency for no benefit over the Rust engine

The safety gate in packages/detector-engine/src/safe_regex.rs additionally rejects lookaround and backreferences with actionable errors, and caps compiled program size so a pathological pattern fails fast instead of exhausting memory.

2.5 Gitleaks - licence approved, ruleset NOT imported ​

FieldValue
ProjectGitleaks
Official repositorygithub.com/gitleaks/gitleaks
Version consideredv8.30.1 (2026-03-21); repository active (last push 2026-09-09)
LicenceMIT - verified via the GitHub licence API
Integration formNone
Distributed to customerNo

Decision: not imported. The licence would permit it, so this is an engineering decision rather than a legal one:

  1. Running the binary per endpoint event is the wrong execution model - it would mean a process spawn on every file write.
  2. Importing the rule file wholesale means importing hundreds of vendor-specific patterns, most irrelevant to any given customer, each a false-positive source in a product whose currency is analyst trust.
  3. A copied rule set is a derived work carrying attribution obligations for patterns we would then have to maintain without understanding their history.

MyDLP's credential detectors are written from vendor documentation of the public key prefixes (AKIA, ghp_, AIza, xoxb-), which are published facts, not expression copied from Gitleaks. If specific rules are ever adopted, each must be recorded individually here with Gitleaks attribution.

2.6 YARA / YARA-X - deferred, not in the MVP ​

FieldYARAYARA-X
Repositorygithub.com/VirusTotal/yaragithub.com/VirusTotal/yara-x
Version consideredv4.5.8 (2026-07-28)v1.20.0 (2026-08-24)
LicenceBSD-3-Clause (verified)BSD-3-Clause (verified)
MaintenanceActive (last push 2026-08-25)Active (last push 2026-09-13)
DecisionNot adoptedPreferred successor if byte-signature classification is scheduled

Not required for the MVP and deliberately excluded. If adopted: YARA-X, because it is the actively developed Rust successor and avoids a C dependency in the agent. Preconditions - rule bundles signed and version-pinned by the server, executed under memory and time limits, community rule packs never fetched automatically, and each imported pack licence-assessed separately.

2.7 spaCy - code approved; models not adopted, alternative preferred ​

FieldValue
Repositorygithub.com/explosion/spaCy
Version consideredv3.8.16 (2026-08-24)
Licence (library)MIT - verified
Licence (models)Model packages are MIT, but en_core_web_lg metadata declares its training data as OntoNotes 5 under "commercial (licensed by Explosion)"
DecisionLibrary acceptable. Models not adopted - see the determination below

Reached transitively through Presidio; assessed separately because a dependency-of-a-dependency with encumbered training data is exactly the risk the licence policy exists to catch.

Determination (DLP-SPIKE-002, 2026-09-15) ​

Full working: SPIKE-002. In short, the licence chain was traced to primary documents and it holds on its face, which is the opposite of what the ticket feared:

  • OntoNotes 5 reaches Explosion under the LDC User Agreement, which restricts the party receiving the corpus - Explosion, not us - and prohibits redistributing the corpus, not something trained on it.
  • The LDC For-Profit Membership Agreement §1(b) permits a member to "incorporate portions of the LDC Databases into its own work products, including for commercial purposes".
  • We receive model weights under MIT and never receive the corpus.

It is nonetheless not adopted, and the reason is about the cost of being wrong rather than the odds of it. Relying on that chain needs legal to construe a training-data grant, to take an unverified vendor self-declaration on trust, and to accept a residual memorisation question - and winning all three yields a general-purpose NER model that fits a DLP product worse than the permissively licensed alternative.

Preferred at the time: urchade/gliner_multi_pii-v1 - Apache-2.0 model, Apache-2.0 code, trained on an Apache-2.0 synthetic PII dataset. No LDC anywhere in the chain, and a PII-specific label set rather than OntoNotes categories. Adoption was gated on an accuracy benchmark, because a licence result is not a quality result.

Closing the determination (DLP-SEC-021, 2026-09-17) ​

The benchmark ran, and it removed the question rather than answering it. SPIKE-008 measured both candidates on 1,580 documents and recommends adopting neither; GLiNER is the better model and still runs at 0.21 KB/s against dlp-detector-engine's 13.9 MiB/s, with person precision no threshold lifts past 0.78. ADR-0011 had already refused the service shape.

So the position of this section is now simple, and it is worth being precise about what is and is not settled:

  • Nothing is redistributed. No NER model ships in any artefact. There is no redistribution question to approve, because there is no redistribution - not of en_core_web_lg, not of GLiNER, not of anything trained on OntoNotes.
  • The spaCy characterisation stands, and it matters for the record even though it changes nothing today: the chain is available but not worth the construction risk, not prohibited. Recording it as prohibited would be wrong on the evidence and would make a future revisit harder than it needs to be. If it is ever revisited, written confirmation from Explosion is the first step, not the metadata field.
  • The customer-supplied model is the remaining live path, and it carries one condition, below.

This determination is an engineering determination. It is evidence and a recommendation, and it is not a legal opinion. No legal approval has been obtained and none is recorded here. What has changed is that nothing now depends on one: the approval the spike ticket wanted was a precondition for shipping a model, and no model is being shipped. If that ever changes, this section becomes a blocking question again and should be re-opened, not assumed.

The condition on a customer-supplied model ​

If a customer supplies their own model, we are not a distributor and this section does not apply to them - they obtain it themselves under the same MIT grant, and the risk moves to them rather than disappearing.

That is only true while one thing stays true, so it is written down rather than left to be rediscovered:

The product must never fetch a model on the customer's behalf. Not the agent, not the console, not an installer, not a "download the recommended model" convenience in the UI.

An automatic download is not a shortcut around the licence chain, it is the licence chain: fetching an artefact and handing it to a customer makes us a distributor of it, in substance whatever the UI calls it, and every question this section spent two spikes retiring comes back at once - with the added difficulty that it would arrive as a support convenience nobody reviewed.

The DetectorKind::External contract is the integration point and it stays unused in what we ship. A customer configures a model they already have, on a path they already control.


3. Explicitly rejected ​

ProjectReason
OpenDLPHistorical feature comparison only. GPL-family licensing would impose copyleft obligations on a proprietary product, and its architecture predates modern endpoint security expectations. No code, schema or rule content copied.
MyDLP (the historical GPL project)Same. The product name is the customer's own; there is no code lineage. A clean-room feature comparison is in Known limitations §7, written from public documentation only
Elasticsearch / KibanaElastic Licence 2.0 / SSPL - forbidden by the licence policy. OpenSearch (Apache-2.0) is the approved alternative if search is ever required; it is not needed for the MVP
MongoDBSSPL - forbidden
Any dependency with a missing, ambiguous or non-commercial licenceForbidden by policy

4. Conditions and open items ​

4.1 notify - CC0-1.0, with no alternative to elect ​

Correction. An earlier revision of this document recorded notify as CC0-1.0 OR Artistic-2.0 and elected Artistic-2.0. That was wrong for the version actually in the tree: cargo tree reports notify v8.2.0 as CC0-1.0 only. The dual licence applied to older releases.

This matters because CC0-1.0 is the one licence in the tree with a characteristic worth stating: §4(a) explicitly declines to grant patent rights.

"No trademark or patent rights held by Affirmer are waived, abandoned, surrendered, licensed or otherwise affected by this document."

There is no alternative option to elect, so the position is:

  • Attribution: none required. The notice in THIRD_PARTY_NOTICES.md is voluntary and records provenance rather than discharging an obligation.
  • Patent risk: accepted. notify is a thin wrapper over inotify (ISC) and ReadDirectoryChangesW; the surface for a patent claim is small, and the platform APIs it calls are the customer's own operating system.
  • Replacement: the agent uses notify behind monitor::FileMonitor. Replacing it means reimplementing two platform calls, which is bounded work.

Recorded rather than glossed, because "permissive" and "grants patent rights" are not the same statement.

4.2 Licences worth naming explicitly ​

DependencyLicenceNote
ringApache-2.0 AND ISCConjunctive, not a choice. Both sets of terms apply and both notices must be retained
encoding_rs(Apache-2.0 OR MIT) AND BSD-3-ClauseConjunctive with the BSD-3 component; the no-endorsement clause applies
matchitMIT AND BSD-3-ClauseConjunctive
webpki-rootsCDLA-Permissive-2.0A dataset, not code - Mozilla's CA root store. Permissive, but it is exactly the "bundled dataset" category §3 of the licence policy requires to be assessed separately. Assessed: redistribution permitted, no attribution condition beyond retaining the notice
icu_*, litemap, zerovec, tinystr (19 crates)Unicode-3.0Unicode data licence; retain the notice. Reached transitively through idna/url
foldhashZlibPermissive; retain the notice and do not misrepresent origin
ryu, whoamiApache-2.0 OR BSL-1.0Boost Software License. Apache-2.0 elected for consistency
constant_time_eqCC0-1.0 OR MIT-0 OR Apache-2.0Apache-2.0 elected, for the patent grant

4.3 Open items before general availability ​

ItemTicketBlocking
Enumerate Tika's transitive parser licencesDLP-SPIKE-003Shipping the extraction service
Legal review of spaCy/OntoNotes model redistributionDLP-SEC-021Closed, not approved - nothing depends on it. §2.7 records why: no NER model is shipped, so there is no redistribution to review
Enumerate Presidio's Python transitive licencesDLP-SPIKE-002Closed. ADR-0011 refuses the detection service, so there is no Python dependency tree to enumerate
Generate and publish CycloneDX SBOMs in CIDLP-TASK-007Release gate
cargo-deny and cargo-audit in CIDLP-TASK-008Release gate

Container images are scanned (DLP-228) ​

The licence and SBOM gates cover the Rust and npm dependency trees. They say nothing about the base image, which is where a container's CVEs usually live: debian:bookworm-slim under the API, nginxinc/nginx-unprivileged:alpine under the dashboard.

Trivy scans both images on every CI run and fails the build on a HIGH or CRITICAL vulnerability that has a fix available. It does not fail on one with no fix, and that is deliberate: a gate that cannot be satisfied is one somebody turns off, after which nothing is scanned at all.

Suppressions live in deploy/docker/.trivyignore.yaml and each one needs a reason and an expiry. tools/check_vuln_allowlist.py refuses an entry with neither, or with an expiry more than ninety days out, and Trivy stops honouring an entry once its expiry passes - so an abandoned suppression starts failing the build rather than quietly outliving whoever added it. The file is currently empty.

What this does not cover: the images are scanned as CI builds them, not as they sit in a registry weeks later. A vulnerability disclosed after a release is not found until the next build, and nothing here rebuilds on a schedule.

None of the open items affects what is currently implemented: the agent, the management API and the dashboard depend only on components in §1, all approved.


5. Review procedure ​

Before adopting any new dependency:

  1. Read the actual LICENSE and NOTICE files in the repository at the exact tag being adopted. Not a summary site, not a package-manager field.
  2. Record the exact version or commit.
  3. Enumerate transitive licences with cargo deny / license-checker / Syft.
  4. Separately assess any bundled model, dataset, rule pack or language pack.
  5. Check repository activity, latest release and open security advisories.
  6. Determine the integration form and whether it is redistributed.
  7. Record the notice obligation in THIRD_PARTY_NOTICES.md.
  8. Add a row here with the approval decision and the reviewer.

A dependency that cannot complete every step is not adopted.

Statements here describe what is built and tested; planned work is marked as planned.