Appearance
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
NOTICEcontent. 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
| Project | Repository | Purpose | Version | SPDX | Integration | Distributed | Modified | Notice obligation | Status |
|---|---|---|---|---|---|---|---|---|---|
| tokio | github.com/tokio-rs/tokio | Async runtime | 1.44.x | MIT | static library | yes | no | MIT copyright + licence text | Approved |
| axum | github.com/tokio-rs/axum | HTTP server | 0.8.x | MIT | static library | yes | no | MIT copyright + licence text | Approved |
| tower / tower-http | github.com/tower-rs | Middleware | 0.5.x / 0.6.x | MIT | static library | yes | no | MIT copyright + licence text | Approved |
| hyper | github.com/hyperium/hyper | HTTP core | 1.6.x | MIT | static library | yes | no | MIT copyright + licence text | Approved |
| sqlx | github.com/launchbadge/sqlx | PostgreSQL access, migrations | 0.8.x | MIT OR Apache-2.0 | static library | yes | no | Apache-2.0 elected; retain NOTICE | Approved |
| serde / serde_json | github.com/serde-rs | Serialisation | 1.0.x | MIT OR Apache-2.0 | static library | yes | no | Apache-2.0 elected | Approved |
| regex | github.com/rust-lang/regex | Linear-time pattern matching | 1.11.x | MIT OR Apache-2.0 | static library | yes | no | Apache-2.0 elected | Approved |
| aho-corasick | github.com/BurntSushi/aho-corasick | Multi-keyword matching | 1.1.x | Unlicense OR MIT | static library | yes | no | MIT elected | Approved |
| ed25519-dalek | github.com/dalek-cryptography/curve25519-dalek | Bundle and request signatures | 2.1.x | BSD-3-Clause | static library | yes | no | BSD-3 copyright, conditions and disclaimer; no endorsement use of contributor names | Approved |
| sha2 / hmac / argon2 | github.com/RustCrypto | Hashing, HMAC, password hashing | see SBOM | MIT OR Apache-2.0 | static library | yes | no | Apache-2.0 elected | Approved |
| rustls | github.com/rustls/rustls | TLS | 0.23.x | Apache-2.0 OR ISC OR MIT | static library | yes | no | Apache-2.0 elected; retain NOTICE | Approved |
| reqwest | github.com/seanmonstar/reqwest | Agent HTTP client | 0.12.x | MIT OR Apache-2.0 | static library | yes | no | Apache-2.0 elected | Approved |
| rustls-native-certs | github.com/rustls/rustls-native-certs | Reads the platform certificate store, so an internal CA or an inspecting proxy works without configuration (DLP-59) | 0.8.x | MIT OR Apache-2.0 OR ISC | static library | yes | no | Apache-2.0 elected | Approved. Reached through reqwest's rustls-tls-native-roots feature; already resolved in the lockfile before it was enabled |
| rcgen | github.com/rustls/rcgen | Internal device CA | 0.13.x | MIT OR Apache-2.0 | static library | yes | no | Apache-2.0 elected | Approved |
| x509-parser | github.com/rusticata/x509-parser | Parses the timestamp authority's certificates for audit anchoring (DLP-1185); every signature is checked with ring | 0.16.x | MIT OR Apache-2.0 | static library | yes | no | Apache-2.0 elected | Approved. Already in the tree through rcgen at this version; declared directly by the management API |
| rusqlite + libsqlite3-sys | github.com/rusqlite/rusqlite | Agent event queue | 0.32.x | MIT | static library | yes | no | MIT copyright + licence text | Approved |
| SQLite (bundled by libsqlite3-sys) | sqlite.org | Embedded database | bundled | Public domain (blessing) | static library | yes | no | No obligation, but provenance recorded | Approved |
| blake3 | github.com/BLAKE3-team/BLAKE3 | Content hashing, shingling | 1.8.x | CC0-1.0 OR Apache-2.0 OR Apache-2.0-with-LLVM-exception | static library | yes | no | Apache-2.0 elected, because CC0 carries no express patent grant | Approved |
| unicode-normalization | github.com/unicode-rs | NFKC normalisation | 0.1.x | MIT OR Apache-2.0 | static library | yes | no | Apache-2.0 elected; Unicode data terms also apply | Approved |
| deunicode | github.com/kornelski/deunicode | ASCII transliteration | 1.6.x | BSD-3-Clause | static library | yes | no | BSD-3 conditions | Approved |
| notify | github.com/notify-rs/notify | Filesystem watching | 8.2.x | CC0-1.0 | static library | yes | no | No attribution required, but see §4.1 on patents | Approved with a recorded caveat |
| zip | github.com/zip-rs/zip2 | ZIP inspection on the endpoint | 8.6.x | MIT | static library | yes | no | MIT copyright + licence text | Approved. 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 |
| flate2 | github.com/rust-lang/flate2-rs | DEFLATE for PDF content streams and ZIP entries | 1.1.x | MIT OR Apache-2.0 | static library | yes | no | Apache-2.0 elected | Approved. Already reached transitively through reqwest's gzip support; now a direct dependency because the PDF extractor needs it |
| typed-path, zopfli | via zip | Path handling and deflate | see SBOM | MIT OR Apache-2.0; Apache-2.0 | static library | yes | no | Apache-2.0 elected where there is a choice | Approved |
| sevenz-rust2, lzma-rust2 | github.com/hasenbanck/sevenz-rust2 | 7z inspection on the endpoint (DLP-1177) | 0.23.x, 0.21.x | Apache-2.0 | static library | yes | no | Apache-2.0 licence text | Approved. 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-rs | github.com/paolobarbolini/bzip2-rs | .tar.bz2 and .bz2 inspection on the endpoint (DLP-1477) | 0.1.x | MIT OR Apache-2.0 | static library | yes | no | MIT copyright + licence text | Approved. 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 |
| ruzstd | github.com/KillingSpark/zstd-rs | .tar.zst and .zst inspection on the endpoint (DLP-1477) | 0.9.x | MIT | static library | yes | no | MIT copyright + licence text | Approved. 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 |
| chardetng | github.com/hsivonen/chardetng | Guessing the code page of an unlabelled legacy text file on the endpoint (DLP-1674) | 1.0.x | Apache-2.0 OR MIT | static library | yes | no | Apache-2.0 elected | Approved. 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_rs | various | Utilities | see SBOM | MIT OR Apache-2.0 (encoding_rs: Apache-2.0 OR MIT, plus WHATWG data) | static library | yes | no | Apache-2.0 elected | Approved |
| chrono-tz | https://github.com/chronotope/chrono-tz | IANA timezone resolution for policy schedules | 0.10.4 | MIT OR Apache-2.0 (crate code); the embedded IANA tz database is released by its maintainers into the public domain | static library | yes | no | Apache-2.0 elected for the crate code; see the note below for the database | Approved |
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):
| Build | Size |
|---|---|
Single zone (UTC only) | 9 983 384 bytes (9.52 MB) |
| Full IANA database | 11 877 336 bytes (11.33 MB) |
| Difference | 1 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:
| Crate | Version | Upstream | Licence election | Redistribution obligation |
|---|---|---|---|---|
| ldap3 | 0.12.1 | github.com/inejge/ldap3 | Apache-2.0 | Retain licence and any upstream NOTICE |
| lber | 0.5.1 | github.com/inejge/ldap3 | MIT | Retain Ivan Nejgebauer/Gregor licence and copyright notice |
| asn1-rs | 0.7.2 | github.com/rusticata/asn1-rs | Apache-2.0 | Retain licence and any upstream NOTICE |
| asn1-rs-derive | 0.6.0 | github.com/rusticata/asn1-rs | Apache-2.0 | Retain licence and any upstream NOTICE |
| der-parser | 10.0.0 | github.com/rusticata/der-parser | Apache-2.0 | Retain licence and any upstream NOTICE |
| oid-registry | 0.8.1 | github.com/rusticata/oid-registry | Apache-2.0 | Retain licence and any upstream NOTICE |
| x509-parser | 0.18.1 | github.com/rusticata/x509-parser | Apache-2.0 | Retain 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
| Project | Purpose | Version | SPDX | Integration | Distributed | Notice obligation | Status |
|---|---|---|---|---|---|---|---|
| react / react-dom | UI runtime | 18.3.1 | MIT | bundled | yes | MIT copyright + licence text | Approved |
| react-router-dom | Routing | 6.30.x | MIT | bundled | yes | MIT | Approved |
| @tanstack/react-query | Server state | 5.66.x | MIT | bundled | yes | MIT | Approved |
| @tanstack/react-table | Tables | 8.21.x | MIT | bundled | yes | MIT | Approved |
| react-hook-form | Forms | 7.54.x | MIT | bundled | yes | MIT | Approved |
| zod | Runtime schema validation | 3.24.x | MIT | bundled | yes | MIT | Approved |
| recharts | Charts | 2.15.x | MIT | bundled | yes | MIT (also covers its d3 sub-dependencies, ISC/BSD-3) | Approved |
| lucide-react | Icon set | 1.46.0 | ISC | bundled, tree-shaken | yes | ISC copyright + licence text | Approved |
| @radix-ui/colors | Colour scales | 3.0.0 | MIT | values only, see below | yes | MIT | Approved |
| @fontsource/ibm-plex-sans | Self-hosted font for System Health | 5.3.0 | OFL-1.1 | selected WOFF2 files bundled by Vite | yes | Copyright + full OFL text; font is not sold separately | Approved, unmodified redistribution only |
| typescript, vite, vitest, eslint | Build and test only | see SBOM | Apache-2.0 / MIT | build-time | no | Not redistributed | Approved |
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, whichTHIRD_PARTY_NOTICES.mdcarries. - @radix-ui/colors ships CSS custom properties. Its values are transcribed into the semantic tokens in
styles.csswith 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.mdrecords 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.
| Project | Purpose | SPDX | Distributed | Notice obligation |
|---|---|---|---|---|
Syft (anchore/syft) | Generates the CycloneDX and SPDX SBOMs | Apache-2.0 - verified via the GitHub licence API | No - CI only | None, as it is not redistributed |
anchore/sbom-action | Installs Syft in CI (download-syft) | Apache-2.0 - verified | No | None |
| cargo-deny, cargo-audit | Licence and advisory gates | See SBOM | No | None |
| cargo-fuzz, libfuzzer-sys, arbitrary | Fuzzing the hostile-input boundaries | MIT OR Apache-2.0 (libfuzzer-sys also NCSA, from LLVM); verified via crates.io | No - packages/detector-engine/fuzz is outside the workspace and nothing links it | None |
| Gitleaks | Secret scanning of our repository | See §2.5 - scanning is not importing its ruleset | No | None |
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
| Project | Purpose | Version | SPDX | Distributed | Notes |
|---|---|---|---|---|---|
| PostgreSQL | Primary datastore | 16.x | PostgreSQL Licence | no | Operator-supplied. Permissive; no obligation triggered because we do not redistribute it. |
| nginx | Reverse proxy, TLS termination | 1.24.x | BSD-2-Clause | no | Operator-supplied. |
1.3 Build-only tooling
| Project | Purpose | Version | SPDX | Integration | Distributed | Status |
|---|---|---|---|---|---|---|
| WiX Toolset | Compile the Windows MSI | 4.0.6 | MS-RL | pinned local .NET tool, CI/release build only | no | Approved 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
| Project | Repository | Purpose | Version | SPDX | Integration | Distributed | Modified | Notice obligation | Status |
|---|---|---|---|---|---|---|---|---|---|
SecLists 10k-most-common.txt | github.com/danielmiessler/SecLists | The common-password list the management API refuses when a password is chosen (DLP-991) | commit 913b3273 (2026-09-08) | MIT | include_str! into the server binary | yes, in the server only | no | MIT copyright + licence text | Approved |
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
| Field | Value |
|---|---|
| Project | Presidio |
| Official repository | github.com/microsoft/presidio, which redirects to github.com/data-privacy-stack/presidio |
| Purpose | PII detection, context-aware recognisers, NER, anonymisation, image PII |
| Version considered | v0.95 (latest tag as of 2026-09-15) |
| Licence | MIT - verified by reading LICENSE at main: "The MIT License (MIT) - Copyright (c) Presidio Contributors." |
| Transitive licences | Not yet enumerated. Blocked on DLP-SPIKE-002. |
| Integration form | Isolated internal HTTP service (never in the agent) |
| Distributed to customer | Yes, as a container image in on-premises deployments |
| Modified | No |
| Notice requirement | MIT copyright and licence text for Presidio; separate review required for each NLP model |
| Commercial-use status | Approved for the code. Models require separate legal review |
| Security status | Python service processing untrusted text; must run network-isolated with CPU/memory/time limits and no filesystem write access |
| Replacement strategy | Sits 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
| Field | Value |
|---|---|
| Project | Apache Tika |
| Official repository | github.com/apache/tika |
| Purpose | File-type detection, text and metadata extraction, embedded objects, PDF/DOCX/XLSX/PPTX, archives |
| Version assessed | 3.3.2, artefact tika-server-standard-3.3.2.jar, sha256 cdbe7fde7258…f77540. 4.0.0 is published and not assessed |
| Licence | Apache-2.0 - verified via the GitHub licence API |
| Transitive licences | Enumerated: 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 form | Sandboxed container running tika-server-standard, invoked over HTTP |
| Distributed to customer | Yes, as a container image |
| Modified | No |
| Notice requirement | Apache-2.0 §4: licence copy, change notices, retained attribution, and the contents of Tika's NOTICE file reproduced in ours |
| Commercial-use status | Not adoptable as published. Four conditions below |
| Security status | Document 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:
| Artefact | Licence | Why |
|---|---|---|
org.codelibs:jhighlight:1.1.1 | CDDL-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.0 | UnRAR licence | Its 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:
| Artefacts | Options | Elect |
|---|---|---|
jakarta.annotation-api, jakarta.websocket-api, jakarta.ws.rs-api, tyrus-standalone-client | EPL-2.0 OR GPL-2.0-with-classpath-exception | EPL-2.0 - file-level copyleft on unmodified API jars |
juniversalchardet | MPL-1.1 OR GPL-3.0 OR LGPL-3.0 | MPL-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 EPL | Apache-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
NOTICEis six lines for 134 bundled artefacts. Shading collapsesMETA-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-standardis an uber-jar; disabling a parser intika-config.xmlstops 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 fromtika-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 inpackages/detector-engine/tests/office_documents.rsandpackages/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
| Field | Value |
|---|---|
| Project | Tesseract OCR |
| Official repository | github.com/tesseract-ocr/tesseract |
| Purpose | Text from scanned PDFs, images and screenshots |
| Version considered | 5.5.3 (released 2026-07-24) |
| Licence | Apache-2.0 - verified via the GitHub licence API |
| Language packs | tesseract-ocr/tessdata_fast - Apache-2.0, verified by reading the repository's LICENSE. Covers aze, tur, eng, rus |
| Integration form | Separate container behind a pluggable OCR adapter |
| Distributed to customer | Yes, on-premises by default |
| Modified | No |
| Notice requirement | Apache-2.0 licence and NOTICE for both the engine and the trained-data repository, recorded as two separate entries |
| Commercial-use status | Approved, engine and the four language packs |
| Security status | Image decoders reached by untrusted input; run with page, image-size, resolution and time limits inside a container |
| Replacement strategy | Behind 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 .
| Candidate | Licence (verified 2026-09-15) | Decision |
|---|---|---|
Rust regex | MIT OR Apache-2.0 | Selected. Linear-time by construction: no backtracking, so catastrophic backtracking is impossible rather than merely mitigated. Pure Rust, cross-compiles, no native dependency |
| Hyperscan | BSD-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 |
| Vectorscan | BSD-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 |
| RE2 | BSD-3-Clause | Rejected. 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
| Field | Value |
|---|---|
| Project | Gitleaks |
| Official repository | github.com/gitleaks/gitleaks |
| Version considered | v8.30.1 (2026-03-21); repository active (last push 2026-09-09) |
| Licence | MIT - verified via the GitHub licence API |
| Integration form | None |
| Distributed to customer | No |
Decision: not imported. The licence would permit it, so this is an engineering decision rather than a legal one:
- Running the binary per endpoint event is the wrong execution model - it would mean a process spawn on every file write.
- 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.
- 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
| Field | YARA | YARA-X |
|---|---|---|
| Repository | github.com/VirusTotal/yara | github.com/VirusTotal/yara-x |
| Version considered | v4.5.8 (2026-07-28) | v1.20.0 (2026-08-24) |
| Licence | BSD-3-Clause (verified) | BSD-3-Clause (verified) |
| Maintenance | Active (last push 2026-08-25) | Active (last push 2026-09-13) |
| Decision | Not adopted | Preferred 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
| Field | Value |
|---|---|
| Repository | github.com/explosion/spaCy |
| Version considered | v3.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)" |
| Decision | Library 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
| Project | Reason |
|---|---|
| OpenDLP | Historical 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 / Kibana | Elastic 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 |
| MongoDB | SSPL - forbidden |
| Any dependency with a missing, ambiguous or non-commercial licence | Forbidden 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.mdis voluntary and records provenance rather than discharging an obligation. - Patent risk: accepted.
notifyis a thin wrapper overinotify(ISC) andReadDirectoryChangesW; 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
notifybehindmonitor::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
| Dependency | Licence | Note |
|---|---|---|
ring | Apache-2.0 AND ISC | Conjunctive, not a choice. Both sets of terms apply and both notices must be retained |
encoding_rs | (Apache-2.0 OR MIT) AND BSD-3-Clause | Conjunctive with the BSD-3 component; the no-endorsement clause applies |
matchit | MIT AND BSD-3-Clause | Conjunctive |
webpki-roots | CDLA-Permissive-2.0 | A 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.0 | Unicode data licence; retain the notice. Reached transitively through idna/url |
foldhash | Zlib | Permissive; retain the notice and do not misrepresent origin |
ryu, whoami | Apache-2.0 OR BSL-1.0 | Boost Software License. Apache-2.0 elected for consistency |
constant_time_eq | CC0-1.0 OR MIT-0 OR Apache-2.0 | Apache-2.0 elected, for the patent grant |
4.3 Open items before general availability
| Item | Ticket | Blocking |
|---|---|---|
| Enumerate Tika's transitive parser licences | DLP-SPIKE-003 | Shipping the extraction service |
| DLP-SEC-021 | Closed, not approved - nothing depends on it. §2.7 records why: no NER model is shipped, so there is no redistribution to review | |
| DLP-SPIKE-002 | Closed. ADR-0011 refuses the detection service, so there is no Python dependency tree to enumerate | |
| Generate and publish CycloneDX SBOMs in CI | DLP-TASK-007 | Release gate |
cargo-deny and cargo-audit in CI | DLP-TASK-008 | Release 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:
- Read the actual
LICENSEandNOTICEfiles in the repository at the exact tag being adopted. Not a summary site, not a package-manager field. - Record the exact version or commit.
- Enumerate transitive licences with
cargo deny/license-checker/ Syft. - Separately assess any bundled model, dataset, rule pack or language pack.
- Check repository activity, latest release and open security advisories.
- Determine the integration form and whether it is redistributed.
- Record the notice obligation in
THIRD_PARTY_NOTICES.md. - Add a row here with the approval decision and the reviewer.
A dependency that cannot complete every step is not adopted.