Alcove compliance
This document collects the regulatory and policy framings most often raised by agency security, compliance, and privacy reviewers. It is not a certification or an attestation of compliance with any specific framework. Alcove is open-source software; the deploying agency is responsible for its own risk assessments, authority-to-operate (ATO) determinations, and any required third-party assessments under applicable federal, state, or local regulations.
Start here
This section answers a reviewer's usual questions in plain language. The sections after it are the evidence a technical assessor works through: the control mapping, the standards citations, and the FIPS 140 position.
What Alcove does, and what it protects
Both are stated in plain language in SECURITY_DESIGN.md: what two agencies get out of an exchange, who each party's records are protected from, and the three limits that protection does not cover. What the wrap over a recurring exchange covers, and what it does not, is the SC-8 row; "Alcove encrypts nothing on disk" is SC-28.
What your agency remains responsible for
Alcove is software an agency runs, not a service the project operates, so everything around the exchange stays with the deploying agency: the decision to disclose, at-rest confidentiality, the environment, the credentials, retention and disposition, and the assessment itself -- your risk assessment, your privacy impact assessment, and your ATO determination. Nothing in this document is a certification or an attestation.
The split is stated area by area, separately for the container deployment and the hosted web application, in SHARED_RESPONSIBILITY.md.
Where a reviewer's usual questions are answered
| A reviewer asks | The short answer | Where it is set out |
|---|---|---|
| Is Alcove suitable for our data class? | Designed for PII. PHI under HIPAA and education records under FERPA are conditional and rest on your own determination. CJI under CJIS and FTI under IRS Publication 1075 have not been assessed. Classified information is out of scope. | Intended use and data classification |
| Is our data encrypted at rest? | No -- the software encrypts nothing on disk. It writes its files owner-only, and at-rest confidentiality is your storage or full-disk encryption. | SC-28, Where an unqualified claim fails, and SECURITY_DESIGN.md |
| Is our data encrypted in transit? | On a recurring exchange, yes: the exchange is wrapped in AES-256-GCM on top of the channel's own encryption. A quick exchange relies on the channel alone. | SC-8 and SECURITY_DESIGN.md |
| What is our agency still responsible for? | Everything around the exchange: the decision to disclose, at-rest confidentiality, the environment, the credentials, retention, and the assessment. | What your agency remains responsible for above, and SHARED_RESPONSIBILITY.md |
| Which NIST SP 800-53 controls does it address? | The control mapping, with what each row does and does not claim. | NIST SP 800-53 |
| What happens if the shared secret leaks? | Treat it as invalid immediately, notify the partner, delete both key files, and re-invite over an uncompromised channel. | SECURITY_DESIGN.md |
| Do you use FIPS 140-validated cryptography? | A scoped claim: the default container image and the browser application embed no validated cryptographic module, and a separate -fips image embeds one, which is not the same as being one. | FIPS 140 |
| Which cryptographic algorithms does it use? | One table lists each primitive with its library, FIPS position, quantum exposure, and the check that pins it. None of Alcove's own public-key primitives is post-quantum. | Cryptographic algorithm inventory |
| Do you hold an ATO, or a FedRAMP authorization? | Neither, and neither is available to software as such: an ATO is granted to a deployment in an authorizing environment. The services the project operates for its hosted sites hold no FedRAMP or StateRAMP authorization either. | Authority to Operate and FedRAMP and StateRAMP |
| Where do we report a gap this document does not address? | A public issue for a compliance gap, the private process for a security-sensitive one. | Reporting compliance gaps |
Intended use and data classification
Alcove is designed to perform privacy-preserving record linkage between two partner agencies that have a signed data sharing agreement. The base PSI protocol exposes only the membership intersection between the parties; records that are not in the intersection are not disclosed. See SECURITY_DESIGN.md#data-handling for the data-handling guarantees and PROTOCOL.md for the cryptographic details.
What the project operates and what the deploying agency operates, per deployment, is in SHARED_RESPONSIBILITY.md.
The following table summarizes the data classifications Alcove is and is not designed for. "Suitable" does not relieve the deploying agency of its own compliance obligations.
| Data type | Suitable? | Notes |
|---|---|---|
| Personally Identifiable Information (PII) | Yes | The tool was designed for this use case. |
| Protected Health Information (PHI) under HIPAA | Conditionally | See HIPAA considerations below. |
| Educational records under FERPA | Conditionally | See FERPA considerations below. |
| Criminal Justice Information (CJI) under CJIS | Not validated | Alcove has not been assessed against the FBI CJIS Security Policy. Do not use for CJI workloads without an independent assessment. |
| Federal Tax Information (FTI) under IRS Pub 1075 | Not validated | Alcove has not been assessed against IRS Publication 1075. Do not use for FTI workloads without an independent assessment. |
| Classified information | No | The tool is not designed or evaluated for classified workloads. |
No CJIS or IRS 1075 assessment has been performed on any deployment.
Federal frameworks
NIST SP 800-53
The table below maps Alcove's design to relevant control families of NIST SP 800-53 Rev. 5, whose control identifiers and titles the rows reproduce. It is provided to assist security reviewers and is not a certification of compliance; deploying agencies remain responsible for their own authority-to-operate (ATO) assessments.
| Control | Title | Alcove implementation |
|---|---|---|
| IA-3 | Device Identification and Authentication | The explicit, role-asymmetric mutual key confirmation in the P-256 authenticated key exchange authenticates both parties before any data is exchanged. |
| IA-5 | Authenticator Management | The shared secret is a 256-bit cryptographically random credential stored in a key file with owner-only permissions; it rotates automatically after every successful exchange. |
| IA-5(1) | Authenticator Management: Password-Based Authentication | The shared secret is a 256-bit cryptographically-random value from crypto.getRandomValues, not a human-memorable password, so its full entropy authenticates the exchange and password-stretching controls do not apply. It is consumed by the P-256 authenticated key exchange (see PROTOCOL.md), not by a password-hashing path. |
| IR-4 | Incident Handling | The incident this project handles is a vulnerability reported against the software itself. INCIDENT_RESPONSE.md sequences that handling -- intake and acknowledgement, triage and the severity call, the affected-version determination, a fix developed out of public view and shipped as a hotfix release, advisory publication with CVE assignment, and close-out -- together with the message the reporter receives at each milestone and a co-owner path for a report arriving while the maintainer is unavailable. An incident inside an agency's own deployment is the agency's to detect and respond to; the operator-side procedure for a leaked shared secret is SECURITY_DESIGN.md#compromise-response, and the split is stated per deployment in SHARED_RESPONSIBILITY.md. |
| IR-8 | Incident Response Plan | The plan is INCIDENT_RESPONSE.md, published in this repository with a named review owner and a last-reviewed date: the two roles it assigns, the preconditions it confirms annually, its numbered steps, the maintainer-unavailable path, and the reporter-facing timelines that SECURITY.md is the authority on. It is walked once a year against a simulated report, and again after any change to the release or disclosure process that would alter the sequence; each walk is dated in the exercise record with the scenario it used, the findings it produced, and whether each was fixed in the runbook or referred to the maintainer. |
| RA-3 | Risk Assessment | Threat model, adversary capabilities, privacy guarantees, and known limitations are documented in SECURITY_DESIGN.md#threat-model. |
| SA-22 | Unsupported System Components | The supported-version and end-of-life policy is defined in SECURITY.md. |
| SC-8 | Transmission Confidentiality and Integrity | On a recurring (authenticated) exchange over SFTP or filedrop, everything that crosses the network after the key exchange -- protocol messages and exchange data alike -- is wrapped in AES-256-GCM AEAD keyed from the P-256 key-exchange session key. Three kinds of file reach the shared folder outside that wrap. The rendezvous hello and joining files precede the key exchange and hold the two bilateral mode flags. The key-exchange handshake frames precede the wrap and hold the ephemeral public keys and confirmation MACs; the handshake is authenticated, so tampering with a frame fails the exchange. The abort marker a failing party leaves for its partner holds a version marker and one HKDF token derived from the session key, which an administrator without that key cannot produce. None of the three holds exchange data or the identifiers used for matching, and the remaining rendezvous artifacts -- the lock file and the acknowledgment markers -- hold no payload at all. See FIPS 140 for what the wrap does and does not cover. Quick exchanges on those channels have no application-layer AEAD at all and rely on the channel's transport encryption (for SFTP, the SSH session; for filedrop, whatever protects the shared folder). Every WebRTC exchange is wrapped the same way, over DTLS, so the coordination server and any relay see ciphertext; its key-exchange handshake frames precede the wrap as on the other channels. |
| SC-12 | Cryptographic Key Establishment and Management | Session keys are established via a P-256 authenticated key exchange -- an ephemeral P-256 ECDH through crypto.subtle (the shared-secret computation of NIST SP 800-56A Rev. 3 section 5.7.1.2, over the curve SP 800-186 section 3.2.1.3 publishes), keyed with the pre-shared secret under the Noise NNpsk0 pattern, with an explicit key-confirmation round modelled on the bilateral key confirmation of SP 800-56A Rev. 3 section 5.9.2, though not conformant to it: that section specifies the feature for parties that each hold a static key-establishment key pair, this handshake holds none, and section 6.1.2.3 declines to incorporate key confirmation into that publication's ephemeral-only schemes. What is cited is the shared-secret computation rather than a scheme: the ephemeral-only scheme (section 6.1.2.2) also prescribes a key-derivation step this handshake does not perform, so no conformance to an SP 800-56A scheme is claimed. The key schedule that turns that exchange into a session key is composed in application JavaScript above primitive calls and sits outside any validated cryptographic module boundary, so key establishment claims no validation of the composition (see FIPS 140); every cryptographic operation it makes is a crypto.subtle call, so where a validated module is configured, the module performs all of them. Rotation makes the next shared secret's value independent of the current one's, so it is not the key update NIST SP 800-57 Part 1 Rev. 5 section 8.2.3.2 forbids: the next secret is derived from the handshake's key-agreement output and a random value from each party, each value transported under AES-KW (SP 800-38F) with a key derived from the session key, the initiator's in key-exchange message 3 and the responder's in terms message 2 (PROTOCOL.md). The gaps stand beside it: the wrapping keys and the next secret rest on the key establishment this row already disclaims, so the approved key-agreement scheme SP 800-57 section 8.1.5.2.3 asks for is not met; the derivation takes the hybrid shared-secret form of SP 800-56C Rev. 2 section 2 without the scheme that form presumes; and which generator the two random values come from is unmeasured: the FIPS probe's draw leg shows only that the draw completes with the default provider unreachable. An engaged transcript, Image Smoke run 40777437348, shows the AES-KW wrap and unwrap completing, and both legs gate the probe's verdict, so in the -fips image the module performs the AES-KW calls (The AES-KW row). No conformance to SP 800-57 Part 1 Rev. 5 section 8.2.3.1 re-keying is claimed. Which SP 800-56A Rev. 3 scheme could close these gaps is weighed in key-establishment-fips-boundary.md. Key-file permissions, rotation, backup, and compromise-response procedures are documented in SECURITY_DESIGN.md#key-file-security. |
| SC-13 | Cryptographic Protection | Approval at the algorithm-standard level and approval on a module certificate are different things. Algorithm standard: the operations that protect an exchange in transit use algorithms NIST publications specify -- P-256 ECDH for key establishment (SP 800-56A Rev. 3 section 5.7.1.2, over the curve SP 800-186 section 3.2.1.3 publishes; FIPS 186-5 contains no curve parameters and refers them there), ECDSA over P-256 with SHA-256 (FIPS 186-5) for receipt signing identities, SHA-256, HMAC-SHA-256, HKDF (RFC 5869 -- SP 800-56C Rev. 2 is the NIST key-derivation recommendation, but it cites RFC 5869 rather than specifying HKDF itself, and its own methods are scoped to a shared secret produced by an SP 800-56A or SP 800-56B scheme), and AES-GCM (SP 800-38D, November 2007 -- the AEAD's 96-bit IV is that publication's section 8.2.1 deterministic construction, read against the section's own requirements in CHANNEL_SECURITY.md). Each is a crypto.subtle call rather than a third-party library one, so a validated module configured beneath the platform is what performs it. Module certificate: that is not the same as a module certificate approving the operation, and neither is a claim that any module Alcove publishes is validated for the environment it runs in. What the project does and does not claim, and on what condition, is in FIPS 140; what a scoped claim may and may not say per area is in key-establishment-fips-boundary.md and receipt-signing-fips-boundary.md. The private set intersection sits outside both approvals: its masking is an elliptic-curve construction over P-256 that no NIST publication specifies and no module certificate approves as a scheme, and it runs in BoringSSL, inside a vendored WebAssembly module or the native addon the CLI loads where a prebuild ships for the platform, neither of which an OpenSSL provider can reach (fips-provider-surface.md). No validated module changes that, because what is unapproved there is the scheme rather than its implementation. |
| SC-28 | Protection of Information at Rest | The shared secret is the only persistent credential. It is stored with mode 0600 on Unix and a restricted ACL on Windows; see SECURITY_DESIGN.md#key-file-security. Alcove applies access control at rest rather than encryption: the key file, the signing identity, the exchange records, and the result CSV are written unencrypted at those same owner-only permissions, so at-rest confidentiality is the deploying agency's storage or full-disk encryption. |
| AU-12 | Audit Record Generation | Alcove does not capture PII in log output; see SECURITY_DESIGN.md#data-handling. |
| SI-2 | Flaw Remediation | Coordinated vulnerability disclosure with a 90-day fix target; CVE assignment for confirmed vulnerabilities; patch releases follow the process in RELEASES.md. |
| SI-7 | Software, Firmware, and Information Integrity | Release tags are signed with the maintainer's SSH key; container images are signed with Cosign and include a SLSA build provenance attestation over the same digest; a CycloneDX SBOM covering the npm dependency tree is attached to each GitHub Release, each image's OS packages being listed separately in the attribution lists beside NOTICE. See Release integrity. |
FedRAMP and StateRAMP
Alcove is software, not a service, so it is not in scope for FedRAMP or StateRAMP on its own. Whether an exchange relies on a service the project operates depends on how it is run:
- The container over SFTP or a shared folder uses no service the project operates. The exchange runs between the two parties' machines and the server or folder they agree on.
- A WebRTC exchange needs a coordination server, which helps the two sides find each other, and normally uses a STUN server, which tells each side its public network address. It can also use a relay. The coordination server is the one the invitation names, and the accepting party dials it from whichever deployment it uses. The container uses the STUN server and relay its configuration names, which can be the agency's own; with no STUN server named, it uses Google's public one (CLI.md).
- An agency's own copy of the web app, or its container, uses the agency's coordination server and relay for the invitations it creates (DEPLOYMENT.md). So does a browser on one of the project's hosted sites whose relay settings name the agency's coordination server (WEB_APP.md). When an agency's copy accepts an invitation naming the project's coordination server, it uses that server instead, and the reverse holds for a hosted site accepting an agency's invitation. Every copy of the web app uses Google's public STUN server only where neither the user's relay settings nor the invitation it accepted names a STUN server.
- The project's hosted sites,
psi.data-bridge.org, its staging sitestaging.data-bridge.org, and the demo sitedemo.data-bridge.org, use:- Cloudflare Pages, which delivers the app's code. That web server receives nothing about an exchange. The browser does go back to it for more of the app's code and to check for updates.
- A coordination server, which the project operates on AWS in
us-west-2, unless the invitation names another: one the inviting user set in relay settings, or the one the inviter's own deployment names. - The project's relay and the relay's registrar, on the same host, for an exchange that uses the relay, on the terms in PRIVACY.md.
- Google's public STUN server, unless the user's relay settings or the invitation the exchange accepted names a STUN server.
The project holds no FedRAMP or StateRAMP authorization for the hosted sites or for the services it operates. To keep Google's STUN server out of an exchange, the inviting party names its own STUN server, in relay settings on the web app or in stun on the command line app: the invitation names it, and the accepting party uses it in place of Google's, unless it runs an older copy of the web app, which still adds Google's beside it. On a hosted site, a party can leave the project's relay out of an exchange under Allowed relays (COMMUNICATION.md); to keep it out of the exchange, both parties leave it out. To keep the project's coordination server out of an exchange, the invitation must name your own: create it on a hosted site in a browser whose relay settings name your coordination server, on your own copy of the web app, or from your container's configuration. Only the inviting party's choice decides it, since the accepting party dials the server the invitation names.
What the project's relay, coordination server and the other services can observe is in PRIVACY.md.
An agency that relies on the project's hosted sites, or runs the web app as a hosted service of its own, decides whether FedRAMP or StateRAMP applies to that use and is responsible for any authorization it needs.
FIPS 140
The position in plain terms:
- No image Alcove publishes is FIPS 140-validated, and none is claimed to be. What the project does claim is narrower, and the scope is the whole of the answer.
- What it claims. A separate
-fipscontainer image embeds and uses a validated cryptographic module -- one CMVP validated for another vendor -- so on a host in FIPS mode that module is what performs the cryptographic operations protecting a recurring SFTP or filedrop exchange in transit. Embedding a validated module is not being one. The claim is that the module's code performs the operation -- measured at every container start for the five operations behind the wrap and its key -- and not that the operation runs in the module's approved mode, which for three of them it does not. - What it claims for the default image and the browser application. Nothing. Neither embeds such a module, and no statement here about a validated module is about either of them.
- What no image reaches. Alcove encrypts nothing on disk; the private set intersection uses a scheme no NIST publication specifies and no certificate approves; and the protocol composed above the primitive calls is attested by no certificate.
- Whether that satisfies your agency is your agency's call. A policy requiring a validated module running in an operational environment its certificate covers does not find one here: the certificate names seven operational environments, four tested on bare metal and three vendor-affirmed hardware appliances, and no container among them. See What an authorizing official is being asked to accept.
Three different statements are kept apart below:
- an algorithm is specified and approved by a NIST publication -- FIPS 186-5, FIPS 197, SP 800-38D, SP 800-56A Rev. 3, SP 800-56C Rev. 2, and SP 800-186 for the curve the elliptic-curve algorithms run over -- section 10 of FIPS 140-3 is what gives "approved" that meaning, admitting a security function specified in a FIPS, adopted in one, or listed in NIST SP 800-140C, with SP 800-140D playing that role for sensitive security parameter establishment methods;
- a module certificate approves that algorithm, so a module performing it stays in its approved mode;
- the operational environment the module runs in is one that certificate covers, which is the host plus the runtime plus the image together rather than the image alone.
The target standard is FIPS 140-3, whose sections 2 and 3 take ISO/IEC 19790:2012(E) as the technical requirements and ISO/IEC 24759:2017(E) as the test requirements, with the SP 800-140 series modifying those documents' annexes and test sections. Neither ISO standard is published free of charge; what is cited from FIPS 140-3 itself above is its section 10.
The scoped claim
- Which exchanges. Recurring (authenticated) exchanges, on either file-sync channel. File-sync callers request application-layer encryption unconditionally, so SFTP and filedrop are alike here.
- Which bytes. The protocol messages and exchange data that cross the network after the key exchange. An AES-256-GCM AEAD keyed from the key-exchange session key wraps every one of them.
- Which algorithms. P-256 ECDH for the shared-secret computation, HKDF-SHA-256 for the key schedule, AES-256-GCM for the AEAD, HMAC-SHA-256 and SHA-256 beneath both, and ECDSA over P-256 with SHA-256 for receipt signing. Each is on the approved-algorithm list of the FIPS 140-3 certificate the variant image embeds (CMVP 5438, named in full below), and each is a
crypto.subtlecall rather than a third-party library one, so a validated module configured beneath the platform is what performs it. The constructions themselves are specified in PROTOCOL.md, CHANNEL_SECURITY.md, and EXCHANGE_RECORD.md.
Performed by the validated module is not the same as performed as an approved service. The certificate this project targets states a condition on two of the three algorithms behind the AEAD and its key, in each case somewhere other than its approved-algorithm table, and Alcove's use meets neither:
- AES-256-GCM. An externally supplied IV makes the module's AES-GCM a non-approved service (security policy section 2.7.1 and Table 8), and every
crypto.subtleAES-GCM call supplies the IV by construction -- Alcove's is a deterministic value that includes the sender's sequence number, conformant to SP 800-38D section 8.2.1 (CHANNEL_SECURITY.md). What the certificate conditions is where the IV comes from, not which of the publication's two constructions produced it, so the application AEAD is not an approved service on that certificate's own terms. - P-256 ECDH. The SP 800-56A Rev. 3 section 5.6.2 assurances are conditioned on using the module together with an application that implements the TLS protocol. Alcove is not one.
- HKDF-SHA-256. This policy states no use-context restriction on the module's HKDF. What it does bound is key derivation below a 112-bit key, and this key schedule's key-derivation key is 256 bits. An unstated condition is not an approved-service claim, and none is made here.
What this document claims for all three is the dispatch -- the validated module's code performs the operation, at a parameter shape the certificate's approved-algorithm table lists -- and never that the operation runs as an approved service. No approved-service indicator is read back from the module anywhere in this project, and no claim here rests on one. Both conditions are quoted whole in fips-variant-image.md, and key establishment's claim language is in key-establishment-fips-boundary.md.
Not every byte. The key-exchange handshake frames -- the ephemeral public keys and the confirmation MACs -- precede the AEAD and are not covered by it. On filedrop they are ordinary plaintext files written into the shared folder, readable by anyone who can read that folder; on SFTP the SSH session is what protects them. They contain no linkage identifiers and no exchange data, and the handshake is authenticated, so tampering fails the exchange rather than passing unnoticed.
The condition the claim rests on
The default container image (ghcr.io/georgetown-mdi/alcove:X.Y.Z) and the browser application embed no validated cryptographic module, and this document claims none for them.
The FIPS variant image (ghcr.io/georgetown-mdi/alcove:X.Y.Z-fips) does. It builds on Amazon Linux 2023 and embeds the CMVP-validated OpenSSL FIPS provider AWS publishes for that distribution. A probe runs at every container start, and CI runs it against the built image on every change that can affect it. The probe makes the five call shapes the scoped claim names -- P-256 ECDH, AES-256-GCM, HKDF-SHA-256, HMAC-SHA-256, and SHA-256, at the parameter shapes the product passes -- and the shared-secret rotation's value draw and AES-KW wrap, and requires every one of them to complete and, in the same process, that the validated module be loaded and that two operations no FIPS provider serves both fail, so a call served by an uncertified provider cannot read as a dispatch into this one. Receipt signing's ECDSA is not among those five: what stands behind it is the certificate's approved-algorithm list and the crypto.subtle call path, not a measurement.
Which module, exactly. Ten builds share the provider package name upstream and only one of them is the certified one, so the image asserts both the certificate and the build at build time and fails the build on either mismatch.
The certificate is CMVP 5438, "Amazon Linux 2023 OpenSSL FIPS Provider" (vendor Amazon Web Services, Inc.; FIPS 140-3, Overall Security Level 1; active, validated 7/27/2026 by atsec information security corporation, sunset 7/26/2031). The module version and the certified package NVRs the image installs -- the two values the build asserts and fails on -- are pinned once in CONTAINER_IMAGES.md.
The certificate's own Caveat, verbatim: "When operated in approved mode. When installed, initialized and configured as specified in Section 11.1 of the Security Policy. No assurance of minimum security of SSPs (e.g., keys, bit strings) that are externally loaded, or of SSPs established with externally loaded SSPs." Section 11.1 requires the Amazon Linux 2023 system to be in the FIPS validated configuration, a host state the image cannot supply for itself. (An SSP is a sensitive security parameter; the Caveat's provenance and the section 11.1 procedure are in CONTAINER_IMAGES.md.) Alcove's key schedule mixes a pre-shared secret that the module did not generate: the module makes no assurance about the pre-shared secret's strength, and neither does this document. What stands behind that secret is how it was generated and exchanged (SECURITY_DESIGN.md).
Which operational environment the certificate covers. Four tested environments, all of them Amazon Linux 2023 on bare metal: EC2 c7g.metal (AWS Graviton3) and EC2 c6i.metal (Intel Xeon Platinum 8375C), each tested with the processor's cryptographic acceleration on and off -- so both architectures the variant image builds for are tested platforms. Three more environments are vendor-affirmed rather than tested: AWS Snowball with AMD EPYC 9R14, AWS Snowball with AMD EPYC 7702, and AWS Snowcone with Intel Denverton Atom C3558. The rows and their provenance are in CONTAINER_IMAGES.md. Three consequences:
- None of the seven is a container, and none is a virtual machine. Every tested row states
Hypervisor or Host OS: N/A, and the vendor-affirmed rows name hardware appliances. A container running this module is therefore not running in a tested operational environment on any host, and the vendor-affirmed rows are no fallback for it: the policy prints beneath them that CMVP "makes no statement as to the correct operation of the module or the security strengths of the generated keys when so ported if the specific operational environment is not listed on the validation certificate". An AWS Snowball platform is affirmed by the vendor, not tested by the laboratory. - The image does not put the host in FIPS mode and cannot. Supplying that host is the operator's. The variant reports what it finds -- whether its own crypto is being served by the module, and what
/proc/sys/crypto/fips_enabledsays -- at every container start, and warns rather than refusing. - What each host tier supports is set out in fips-variant-image.md: an Amazon Linux 2023 host in FIPS mode is the arrangement AWS itself documents; another Linux host in FIPS mode runs an unmodified, self-testing validated module in an environment no certificate names; a host not in FIPS mode supports no claim at all.
What stays outside the module. Publishing the variant moves nothing in Where an unqualified claim fails below: the PSI masking permanently, everything written to disk, the browser application, and the protocol composed in JavaScript above the primitive calls. One item is specific to what the variant measures -- receipt signing's ECDSA, which is on certificate 5438's approved-algorithm list and runs through the same crypto.subtle path as the five, but which no probe leg covers, so what stands behind it is a table placement rather than an observation.
Embedding a validated module is not being one. A product that embeds another vendor's validated module may say it uses one; it may not call itself validated. That is entry P-17 of the CMVP FAQ (retrieved 2026-08-10; the FAQ is a web page, with no PDF edition), quoted whole in fips-variant-image.md, which records the wording rules review holds this document to -- among them that no sentence here calls either image validated. Entry P-18 permits such a product to call itself FIPS 140-3 "compliant", meaning the vendor's own belief that its implementation meets the requirements, with no CMVP validation behind it; this project does not use that word.
In short: the algorithms the scoped claim names are on certificate 5438's approved-algorithm list, two of them under conditions this use does not meet; the dispatch of five of them into that validated module is measured, at every container start and in CI; the module is the one the certificate names, asserted at build time; and the environment it runs in is one no certificate covers unless and until CMVP tests or the vendor affirms a container. Every statement above about a validated module performing an operation is about the -fips image, deployed on a host in FIPS mode, and about nothing else Alcove publishes.
Where an unqualified claim fails
- Quick exchanges. With no pre-shared secret there is no session key, so there is no application AEAD at all and the scoped claim does not reach them. What protects them is the channel's own transport encryption.
- Data at rest. Alcove encrypts nothing on disk. The key file, the signing identity, the exchange records, and the result CSV are written unencrypted at owner-only permissions (
0600on Unix, a restricted ACL on Windows), so at-rest confidentiality is the deploying agency's storage or full-disk encryption rather than a control this software provides. See SC-28 and SECURITY_DESIGN.md#key-file-security. - The web application. Its key exchange and receipt signing run on the browser's own Web Crypto implementation and its PSI in WebAssembly. A browser offers no configurable cryptographic module, so every statement here about a validated module is about the
-fipscontainer image alone. - The PSI scheme itself. The masking is an elliptic-curve construction over P-256 that no NIST publication specifies and no module certificate approves as a scheme, and it runs in BoringSSL, inside a vendored WebAssembly module or the native addon the CLI loads where a prebuild ships for the platform, neither of which an OpenSSL provider can reach. The second half is a deployment fact; the first is permanent. What is unapproved is the scheme rather than its implementation, so no validated module and no future image makes the PSI layer approved.
- Protocol composition in JavaScript. The key schedule, the AEAD envelope and its sequence discipline, the canonical encoding, and the receipt's domain separation and per-signer binding are composed in application JavaScript above primitive calls. CMVP validates modules, not protocols: however each primitive call is served, the result is validated primitives and never a validated protocol. Recorded per area in key-establishment-fips-boundary.md and receipt-signing-fips-boundary.md.
What an authorizing official is being asked to accept
Against every party but the partner, the AEAD is the control. A transport administrator, an SFTP server operator, a file-sync provider, and anyone who can read the shared folder are not authorized recipients, and what keeps the exchange confidential from them is the AES-256-GCM wrap. The scoped claim and its condition above are the whole of the FIPS answer for that wrap.
Against the partner, it is not a FIPS-scoped question. The partner is an authorized recipient under the data sharing agreement, already entitled to receive the records the exchange concerns. The PSI layer reduces that disclosure below what the agreement permits: the partner learns the intersection instead of the file. The scheme is a privacy control layered on an authorized disclosure, not a confidentiality control against an unauthorized one.
This is an argument, not a determination. A policy requiring validated modules may be written as a property of the software rather than of the threat it addresses. An agency whose policy reads that way finds an embedded validated module in the -fips image and a tested operational environment nowhere, since certificate 5438 names no container among its four tested environments, nor among the three its vendor affirms. Whether the scoped claim plus this carve-out satisfies a given authorization is the authorizing official's call, and this document does not make it.
Constraining the SSH layer is a separate, achievable control
Restricting what an SFTP exchange's SSH transport will negotiate to approved algorithms is independent of everything above and is available today, whatever image is deployed; it is not a validated-module claim. The settings, and the default offer measured from the variant image on an Amazon Linux 2023 host in FIPS mode, are in FIPS_SFTP_PROFILE.md. A FIPS-configured image narrows that offer by itself, but not to approved algorithms alone: its key-exchange offer still includes diffie-hellman-group-exchange-sha256, whose modulus the server chooses, and the profile's kex list removes it. The host-key type is the partner server's to restrict.
Section 508 and accessibility
The CLI has no graphical interface and is not subject to Section 508's web or software accessibility requirements. The web application has not been formally evaluated against WCAG 2.1 Level AA or Section 508. A Voluntary Product Accessibility Template (VPAT) is not yet available; an accessibility assessment is targeted ahead of the 1.0 release (see ROADMAP.md).
Export control (EAR)
Alcove incorporates cryptographic software. Distribution may be subject to the U.S. Export Administration Regulations (EAR). Most open-source cryptographic software qualifies for License Exception ENC under ECCN 5D002, but the exception requires a one-time notification to the Bureau of Industry and Security (BIS) and the National Security Agency. This notification is pending and will be completed before the 1.0 release.
Cryptographic algorithm inventory
The table lists every cryptographic primitive the two parties' code uses, one row each, with the specification section that governs it. The relay services under infra/relay/ also derive proof keys with HKDF-SHA-256 and check HMAC-SHA-256 proofs, through Python's hmac and hashlib (registrar.py, websocket-pair.py), and coturn checks the TURN credential. Those services are outside the table. It adds the library, quantum exposure, and pinning check of each primitive to the scoped claim above, and does not restate that claim.
How to read the columns:
- Library.
crypto.subtleis Node's Web Crypto, backed by OpenSSL, in the CLI, and the browser's own Web Crypto in the web application. - FIPS position. "Dispatch" means what the scoped claim means by it, under that claim's bounds: in the
-fipsimage, on a host in FIPS mode, for a recurring SFTP or filedrop exchange, the validated module's code performs the operation at a parameter shape certificate 5438's approved-algorithm table lists. "Measured" means the container-start probe makes that call. Neither means the operation runs as an approved service. The default image and the browser application embed no validated module, so no row has a FIPS position for them. - Quantum exposure. Whether a cryptanalytically relevant quantum computer breaks the primitive. Shor's algorithm solves the elliptic-curve and finite-field discrete-logarithm problems and factors RSA moduli, so it breaks every classical public-key row. Grover's search only weakens a symmetric key or a hash, at most halving its strength in bits. The project's position on key establishment is in Post-quantum horizon. As measured on 2026-10-28, ML-KEM-768 and ML-DSA-65 through Web Crypto fail in the
-fipsimage's validated module, Firefox, and Safari, so a hybrid key exchange and dual signing wait until each of those supports them; the triggers that end the wait are in The dated wait. - Pinning check. The test or check that fails when the primitive's output changes. Paths are under
packages/core/test/unless they name an application. An independent known answer comes from outside Alcove's code: Node's OpenSSL-backedcrypto, theopensslcommand, or a published RFC vector.npm run check:vectorsregenerates every generated file underpackages/core/test/vectors/from its generator and fails on a difference. A row with no such check says so.
| Primitive | Purpose | Algorithm and parameters | Library | FIPS position | Quantum exposure | Pinning check | Spec |
|---|---|---|---|---|---|---|---|
| PSI group | Masks each party's linkage values so that only the intersection is revealed. | Commutative encryption in the P-256 group: each value is hashed to a curve point with SHA-256 and multiplied by a per-exchange random scalar from BoringSSL's generator (note 1). | BoringSSL inside the vendored @openmined/psi.js: WebAssembly in the browser, a native addon in the CLI with WebAssembly as its fallback. | None in any image. No NIST publication specifies the scheme, and no OpenSSL provider reaches BoringSSL (Where an unqualified claim fails). | Broken by Shor, which recovers a masking scalar from a point and its masked image. A party could then test guessed values against the partner's masked set. | No independent known answer. vectors/psi-engine-wire-vectors.json pins the engine's own bytes for fixed keys (psi/psiEngineWireVectors.test.ts, and the native addon against them in psi/psiEngineWireVectorsNative.test.ts). vectors/psi-intersection-vectors.json pins the resolved intersection (psi/psiIntersectionVectors.test.ts). | PSI base function |
| Key agreement | Authenticates both parties and derives the session key, on every recurring SFTP or filedrop exchange and every WebRTC exchange. A quick exchange runs none. | The Noise NNpsk0 pattern over ephemeral P-256 ECDH, with a 256-bit pre-shared secret as psk0, a SHA-256 handshake hash, and HMAC-SHA-256 confirmation tags. | crypto.subtle | ECDH: dispatch, measured. No approved-service claim: the certificate conditions the SP 800-56A assurances on an application that implements TLS, which Alcove is not. No certificate attests the schedule composed above it. | ECDH is broken by Shor. A recorded transcript stays confidential against an adversary who solves the Diffie-Hellman but never held the pre-shared secret, which is mixed into the chaining key. | Independent known answer: vectors/kex-vectors.json, from a Node crypto generator, checked by kex.test.ts and apps/web/test/browser/kex.test.ts. kex.test.ts also anchors the curve to the RFC 6979 section A.2.5 key pair. | P-256 authenticated key exchange |
| KDF: Noise chaining | The key schedule's mixing steps. | HKDF-SHA-256 (RFC 5869) with the chaining key as salt and an empty info string, issued as one call for each step's output blocks. | crypto.subtle | Dispatch. The container-start probe makes an HKDF call of the application KDF's shape, not this row's salt, info and output length. The certificate's policy states no use-context condition on HKDF, and no approved-service claim is made. | Weakened by Grover, not broken. | Independent known answer: kex.test.ts checks it against RFC 5869 test case 3, and the vectors/kex-vectors.json generator writes the HMAC chain out in full. | P-256 authenticated key exchange, Key schedule |
| KDF: application | Every other derived key or value: the AEAD keys, the session and confirmation keys, the rotation's wrapping keys and the next shared secret, the abort token, the receipt binder and payload-MAC keys, the WebRTC peer ids, the relay key and exchange id, the relay proof keys, and the terms-update keys. | HKDF-SHA-256 with a fixed salt and a domain-separation label as the info string. The labels form one disjoint, prefix-free space. The parties' code uses no other KDF. | crypto.subtle | Dispatch, measured, as the row above. | Weakened by Grover, not broken. An output is as exposed as the key it is derived from. | Independent known answers: the AEAD keys (vectors/aead-envelope-vectors.json), the session and confirmation keys (vectors/kex-vectors.json), the peer ids (vectors/webrtc-interop-vectors.json), the relay key and exchange id (relayCredential.test.ts, from openssl kdf), the relay proof keys (vectors/relay-proof-vectors.json), the abort token (abortToken.test.ts), and the receipt payload-MAC keys, the terms-update partnership identifier and the terms-update MAC key (vectors/receipt-terms-derivation-vectors.json, computed by its generator with node:crypto and replayed by receiptTermsDerivationVectors.test.ts; a MAC key shows only through the MAC it keys), and the next shared secret and the rotation's wrapping keys (vectors/kex-vectors.json, computed by its generator with node:crypto and checked by kex.test.ts and apps/web/test/browser/kex.test.ts; a wrapping key shows only through the values it wraps). The receipt binder is the module's own output in vectors/signed-receipt-vectors.json. labelSpace.test.ts checks that the labels are distinct and prefix-free. | The domain-separation label space |
| MAC | The key-confirmation tags, the salted record commitments, the receipt payload MACs, the terms-update MAC, the relay registrar request proof, and the WebSocket relay proof. | HMAC-SHA-256. | crypto.subtle | Dispatch, measured. | Weakened by Grover, not broken. | Independent known answers: the confirmation tags (vectors/kex-vectors.json) and the relay proofs (vectors/relay-proof-vectors.json, and the OpenSSL vector block in PROTOCOL.md that relayRegistrarProof.test.ts reads). The record commitments are the module's own output in vectors/exchange-record-vectors.json, reproduced by apps/web/test/browser/exchangeRecord.test.ts. The receipt payload MACs and the terms-update MAC are independent known answers in vectors/receipt-terms-derivation-vectors.json, computed by generate-receipt-terms-derivation-vectors.mjs with node:crypto and replayed by receiptTermsDerivationVectors.test.ts. | Commitment scheme, Receipt content |
| Digest | The key-exchange handshake hash, the agreed-terms hash, the signing-certificate fingerprint a partner pins, the invitation checksum, and the SSH host-key fingerprint. | SHA-256. | crypto.subtle | Dispatch, measured. | Weakened by Grover, not broken. | Independent known answers: the handshake hash (vectors/kex-vectors.json) and the invitation checksum (vectors/webrtc-interop-vectors.json). The certificate fingerprint and the terms hash are the module's own output in vectors/signing-cert-vectors.json and vectors/exchange-record-vectors.json, reproduced by the browser suites under apps/web/test/browser/. | The agreed-terms hash, Signing identity and certificate pinning |
| Signature: certificate | Binds a party's signing public key to its identity. The partner pins the certificate's fingerprint. | ECDSA over P-256 with SHA-256. Self-signed by the party's own key over a domain-separated canonical body, with no certificate authority. | crypto.subtle | The scoped claim names ECDSA for receipt signing only, and ECDSA is on certificate 5438's approved-algorithm list. The self-signature is the same crypto.subtle call, and the claim makes no separate statement about it. No probe leg measures ECDSA. | Broken by Shor, which lets a signature be forged from the public key. ML-DSA does not yet work in every runtime, so the post-quantum signature plan waits (The dated wait). | Verify-only: vectors/signing-cert-vectors.json contains self-signatures made by openssl, loaded by records/signingIdentity.test.ts and apps/web/test/browser/signedReceipt.test.ts, with the fingerprint and public coordinates as deterministic anchors. ECDSA signing is randomized, so no signing known answer exists. | Signing identity and certificate pinning |
| Signature: receipt | Signs the facts both parties derive after an exchange, so that a third party given the pinned fingerprints can check them. | ECDSA over P-256 with SHA-256, over the shared receipt content plus the signer's certificate fingerprint and handshake role. | crypto.subtle | Named in the scoped claim and on certificate 5438's approved-algorithm list. No probe leg measures its dispatch. | Broken by Shor, as the row above. The post-quantum signature plan waits, as the row above. | Verify-only: vectors/signed-receipt-vectors.json contains signatures made by openssl over bytes assembled from the spec, checked by records/signedReceipt.test.ts, records/signedReceiptVerification.test.ts, and apps/web/test/browser/signedReceipt.test.ts. No signing known answer exists, as the row above. | Receipt signature |
| Payload AEAD | Wraps every protocol message and all exchange data after the key exchange, on every recurring SFTP or filedrop exchange and every WebRTC exchange. A quick exchange has none. | AES-256-GCM with one key per direction from the application KDF. The 96-bit IV is built from the per-direction sequence number, the deterministic construction of SP 800-38D section 8.2.1. 128-bit tag; no associated data. | crypto.subtle | Dispatch, measured. A non-approved service on certificate 5438's own terms, because the caller supplies the IV. | Weakened by Grover, not broken: a 256-bit key keeps about 128 bits of strength. Its key derives from the session key, so the key-agreement row's exposure applies to it. | Independent known answer: vectors/aead-envelope-vectors.json, from Node's createCipheriv and hkdfSync, checked by connection/encryptedMessageConnection.test.ts, which also pins the per-direction key derivation. | Application-layer AEAD, IV construction |
| Key wrap | Sends each party's rotation value to the partner on every recurring SFTP or filedrop exchange and every WebRTC exchange: the initiator's in key-exchange message 3, the responder's in terms message 2. A quick exchange has none. | AES-KW (SP 800-38F; the RFC 3394 algorithm), crypto.subtle wrapKey and unwrapKey, under a 256-bit key the application KDF derives from the session key with a label for each sender, straight to a non-extractable key. A 32-byte value wraps to 40 bytes. | crypto.subtle | Dispatch, measured. The container-start probe makes the wrap and unwrap in its aes_kw_wrap_round_trip leg, which fails the verdict when it fails, and an engaged transcript recorded that leg completing (The AES-KW row). The scoped claim's list of algorithms does not name AES-KW. | Weakened by Grover, not broken. Its key derives from the session key, so the key-agreement row's exposure applies to it. | Independent known answers: vectors/kex-vectors.json holds both wrapped values, computed with OpenSSL's id-aes256-wrap by its generator and checked by kex.test.ts and apps/web/test/browser/kex.test.ts. kex.test.ts also checks crypto.subtle AES-KW against the RFC 3394 section 4.6 vector. | Shared-secret rotation |
| Random draw: rotation value | Each party's 32-byte contribution to the next shared secret, drawn once per authenticated run. | A 256-bit HMAC-SHA-256 key drawn with crypto.subtle.generateKey and exported raw, held as a key so that wrapKey can wrap it. | crypto.subtle | No dispatch claim. The container-start probe makes the draw in its rotation_value_draw leg, which fails the verdict when it fails, and an engaged transcript, where the default provider is unreachable, recorded that leg completing (The AES-KW row). Which generator produced the bytes is unmeasured. | Neither algorithm attacks a random draw. The next shared secret derived from it is as exposed as the application KDF row states. | No known answer: the value is random. termsRotation.test.ts checks that each run draws a fresh responder value. | Shared-secret rotation |
| TURN credential | Alcove computes coturn's time-limited TURN credential locally, in the CLI and the browser, to authorize use of a relay for a WebRTC connection. | HMAC-SHA-1, keyed with the relay key. coturn's credential format fixes the algorithm. | crypto.subtle | Outside the scoped claim. This document makes no FIPS statement about it. | Weakened by Grover, not broken. It protects nothing Alcove relies on: the spec states that the exchange's confidentiality and authentication rest on DTLS and the key exchange, not on it. | Independent known answer: relayCredential.test.ts checks a credential computed by openssl dgst -sha1 -hmac. infra/relay/verify.sh repeats the keying check against a running coturn. | Relay credential derivation |
| SSH | Encrypts and authenticates an SFTP connection. It is the only protection of a quick SFTP exchange, and the layer beneath the AEAD on a recurring one. | Negotiated with the server. Alcove sets no default list, so ssh2's defaults apply, minus every key exchange built on a primitive the process cannot perform. An operator may replace the cipher, MAC, key-exchange, and compression lists, including with algorithms outside ssh2's default offer, but not the host-key type. The lists are in FIPS_SFTP_PROFILE.md and the mechanics in EXCHANGE_REFERENCE.md. | ssh2, in the CLI | No validated-module claim. The profile constrains negotiation to approved algorithms, which is a separate control (Constraining the SSH layer). | Broken by Shor: every key exchange and host-key type the measured offer lists is a classical elliptic-curve, finite-field, or RSA construction. Its ciphers and MACs are weakened by Grover, not broken. | No known-answer check of the SSH primitives, which are ssh2's. apps/cli/test/integration/sftpKexOffer.test.ts reads the offered key exchanges off the wire and pins the narrowing. The offer inside the FIPS image is a one-time capture recorded in FIPS_SFTP_PROFILE.md. | Upgrading the SFTP stack |
| WebRTC DTLS | Encrypts the WebRTC data channel, beneath the AEAD on every WebRTC exchange. | Negotiated by the two WebRTC stacks. Alcove sets no DTLS parameter on either, and the CLI passes werift only its ICE servers, so the algorithms are werift's and the browser's defaults. This document does not list or measure them. | werift in the CLI; the browser's WebRTC stack in the web application | None. The scoped claim does not reach WebRTC. | Not measured here. A classical key exchange is broken by Shor, and exchange content stays under the AEAD, whose exposure is the key-agreement row's. | No check of the DTLS algorithms. apps/cli/test/integration/webrtc/dtlsFingerprint.test.ts checks that werift refuses a certificate whose fingerprint the session description did not name. | Upgrading the CLI WebRTC peer |
Notes:
- The P-256 group and the scalars from BoringSSL's generator are stated in PROTOCOL.md. The vendored package ships compiled code only, so the hash to the curve (SHA-256, in
ECCommutativeCipheroverprime256v1) is read from the engine's C++ source rather than measured on the shipped binary. - Each row was checked against the code at these paths:
- PSI group:
packages/core/src/psi/psiEngine.tsandpsiBackend.ts. - Key agreement and the Noise chaining KDF:
packages/core/src/kex.ts. - Application KDF, MAC, digest, and TURN credential:
hkdfDerive,hmacSha256,sha256, andhmacSha1inpackages/core/src/utils/crypto.ts. Their callers areauth.ts,nextSecret.ts,rendezvous.ts,relayCredential.ts(mintRelayCredential),relayRegistrarProof.ts,websocketRelayProof.ts,config/termsUpdate.ts,utils/canonicalHmac.ts,utils/sshHostKey.ts, andrecords/(exchangeRecord.ts,signedReceipt.ts,signingIdentity.ts), all underpackages/core/src/.config/invitation.tscallscrypto.subtle.digestdirectly for the invitation checksum, andnextSecret.tscallscrypto.subtle.deriveKeydirectly for the rotation's wrapping keys. - Key wrap and the rotation-value draw:
packages/core/src/nextSecret.ts. - Signatures:
packages/core/src/records/signingKeys.ts,signingIdentity.ts, andsignedReceipt.ts. - Payload AEAD:
packages/core/src/connection/encryptedMessageConnection.ts, keyed byderiveAeadKeyinpackages/core/src/auth.ts. - SSH: the
algorithmsfilter inpackages/core/src/connection/sftpConnect.ts, and the key-exchange narrowing inapps/cli/src/connection/sftpKexCapability.ts. - WebRTC DTLS:
apps/cli/src/connection/webrtc/weriftPeer.ts.
- PSI group:
- A WebRTC exchange that falls back to the WebSocket relay runs over TLS to the relay in place of the data channel, again beneath the AEAD (SECURITY_DESIGN.md).
- Random values Alcove's own code draws, such as shared secrets, binding nonces, and commitment salts, come from the platform generator:
crypto.getRandomValues, orrandomBytesfromnode:cryptofor the CLI's broker registration token. Key pairs and the two rotation values come fromcrypto.subtle.generateKey. - The applications also compute SHA-256 digests outside core that name local state, such as an invitation id or a lock name. They are not listed.
Sector-specific framings
HIPAA considerations
Alcove does not transmit Protected Health Information (PHI) to any third party: the coordination server, STUN/TURN relay, and any shared SFTP server see only connection metadata or opaque ciphertext, never data-channel content. Between the two partner agencies, the identifiers used for linkage (names, dates of birth, Social Security numbers, and the like) serve only to compute the intersection and are never sent to the partner. After matching, each party transmits only the payload columns it has designated for disclosure and consented to -- by default the non-identifying data columns being shared, not the identifiers used for matching -- and the output each party writes to disk pairs its own arbitrary row identifier with the matched partner records and those disclosed columns. Whether a designated payload column itself contains PHI, and the handling of the written output, are the deploying agency's determination. See SECURITY_DESIGN.md#data-handling.
For HIPAA-regulated deployments:
- The Alcove software itself is not a Business Associate. The two covered entities (or business associates) running the exchange remain responsible for any business associate agreement (BAA) between themselves under their data sharing agreement.
- Any third-party service used to support the exchange (a coordination server, STUN/TURN relay, or shared SFTP server) is operated either by one of the parties or by a third party. If a third party operates such a service, the deploying agency is responsible for assessing whether a BAA is required. Because the PSI protocol does not transmit PHI to those supporting services, most deployments treat them as conduits, but this is a determination the deploying agency must make for itself.
- The Security Rule's technical safeguards (access control, audit controls, integrity, transmission security) are addressed by the cryptographic design documented in SECURITY_DESIGN.md. The administrative and physical safeguards remain the deploying agency's responsibility.
- Each party writes a self-attested exchange record once an exchange has disclosed, whether or not that run went on to finish, and stating which of the two it was. It is a local, unsigned log of what it disclosed -- the partner, the governing data sharing agreement and the purpose of the disclosure under it, the algorithm, the categories of data exchanged, the number of records this party contributed (
recordsExposed), (when both parties learn it) the result size, and -- when configured -- a self-facing pointer to where this party filed the result and its retention/disposition schedule -- and contains no protected values. See EXCHANGE_RECORD.md. Where an accounting of disclosures applies (45 CFR 164.528):- The record is a per-exchange source an agency can retain for that accounting, and it includes the brief purpose statement 164.528 requires for each disclosure.
- The recipient is the one element it may not supply. A party's name in the linkage terms is optional, so a record for a partner that supplied none contains no
partnerIdentity, and the recipient must come from the agency's own record of who the exchange was with. An agency filing these records toward an accounting should agree on terms with a named partner -- the command line warns at terms agreement on a run that will write a record and finds the partner unnamed. - Retaining the per-run source is the operator's own step on the command line and for one-off browser exchanges. For a recurring exchange run from the web application, each run that discloses files its record in the exchange's own accounting of disclosures -- including a run cancelled or cut after its payload was sent, marked as such -- exportable as a table and deleted with the exchange (see MANAGED_EXCHANGE.md).
- The retention/disposition pointer is not itself a 164.528 accounting element; it records where the result was filed and under what schedule.
- Whether a given disclosure is accountable, and the retention and production of the accounting, remain the agency's responsibility.
No sample HIPAA conduit-exception determination memo is available; a deploying agency should have its own counsel prepare that determination. SERVICE_FACT_SHEET.md gives that counsel one page of facts about each service the project runs: what it receives, stores, and keeps, where it runs, and who operates it.
FERPA considerations
Alcove can be used to link educational records across agencies under a data sharing agreement consistent with FERPA's "studies" or "audit and evaluation" exceptions (34 CFR Part 99). The same protocol-level guarantees apply: no individual records are disclosed beyond the intersection, and supporting services see only ciphertext or connection metadata.
The decision to disclose education records under FERPA, and to whom, is the educational agency's responsibility. Alcove does not enforce FERPA-specific controls beyond the cryptographic protections described in SECURITY_DESIGN.md.
The same self-attested exchange record (see the HIPAA considerations above and EXCHANGE_RECORD.md) gives the educational agency a per-exchange log, containing no protected values, that it can retain toward FERPA's requirement to record disclosures of education records (34 CFR 99.32, subject to that section's exceptions). FERPA's studies and audit/evaluation exceptions turn on the purpose of the disclosure, which the record states explicitly. Maintaining the record of disclosures remains the agency's responsibility.
CJIS considerations
Alcove has not been assessed against the FBI CJIS Security Policy. Several CJIS requirements (advanced authentication, audit log retention, personnel security, physical access controls) are environmental controls that the deploying agency would need to satisfy independently. CJIS requires FIPS 140-validated cryptography for CJI in transit, and the position under FIPS 140 does not meet that: the -fips image embeds a validated module rather than being one, no operational environment on its certificate is a container, the default image embeds no module at all, and the PSI layer is unapproved as a scheme whatever module is beneath it.
Alcove should not be used for CJI workloads without an independent CJIS assessment.
IRS Publication 1075 considerations
Alcove has not been assessed against IRS Publication 1075. Publication 1075 inherits NIST 800-53 controls with additional FTI-specific requirements (FIPS 140-validated cryptography, audit logging, and Safeguards Computer Security Evaluation Matrix conformance). The same FIPS position applies on the same terms as for CJIS above: an embedded validated module rather than a validated product, in an environment no certificate covers, and not reaching the PSI layer at all.
Alcove should not be used for FTI workloads without an independent assessment.
State and local laws
State and local privacy laws (for example, California CCPA/CPRA, New York SHIELD Act, Texas DIR rules, Illinois BIPA where biometric identifiers are involved, and analogous statutes in other jurisdictions) impose requirements that vary by jurisdiction. Alcove does not enforce jurisdiction-specific controls; the deploying agency is responsible for assessing applicability and for any required notices, opt-outs, retention limits, or data-subject rights workflows.
No collected set of state-law guidance documents is available yet; a deploying agency should consult its own counsel on applicable state and local requirements.
Supply chain
Section 889
Alcove does not use covered telecommunications equipment or services as defined in Section 889 of the John S. McCain National Defense Authorization Act for Fiscal Year 2019. Verifying that against a published image takes two artifacts, one per layer. The CycloneDX Software Bill of Materials (SBOM) attached to each release covers the npm dependency tree, to the scope and residuals stated in RELEASES.md#software-bill-of-materials-sbom. The OS layer is covered by the attribution lists beside NOTICE, one list per image and one row per package the image's own package manager records, regenerated from the built image and compared against the committed list in CI; see CONTAINER_IMAGES.md#the-os-layer-attribution-lists. Read together, they let a downstream user verify the absence of a specific covered vendor from either layer. The Node.js runtime is in neither: both images install it as an upstream binary distribution rather than as an npm or OS package, so what identifies it is the version and digest each image pins, recorded in CONTAINER_IMAGES.md.
Dependency origins and licenses
The vendored and redistributed components of this repository's own tree, and their upstreams, are documented in the top-level NOTICE file. Per-dependency licenses for the npm tree are listed in the CycloneDX SBOM attached to each release (see RELEASES.md#software-bill-of-materials-sbom). Neither artifact reaches an OS package: each published image's OS layer is covered instead by the attribution list beside NOTICE, which records the license string each package's own manager declares rather than an audit of that package's contents (see CONTAINER_IMAGES.md#the-os-layer-attribution-lists). The dependency license-compatibility policy in CONTRIBUTING.md#dependency-policy scopes to the npm tree; the images' OS layers include packages whose declared licenses carry GPL-3.0 or LGPL-3.0 terms, as their base distributions ship them.
Software Bill of Materials
A CycloneDX SBOM covering the npm dependency tree is generated as part of the release checklist and attached to every GitHub Release; it reaches no OS package. See RELEASES.md#software-bill-of-materials-sbom for its scope and residuals, and CONTAINER_IMAGES.md#the-os-layer-attribution-lists for the lists that cover each image's OS layer.
Release integrity
- Container images are signed with Cosign keylessly through Sigstore, against the release workflow's OIDC identity rather than a project-held signing key, with every signature recorded in Rekor's public transparency log.
- Release tags are signed with the maintainer's SSH key.
- Each released image has a SLSA build provenance attestation, generated by the release workflow over the published manifest-list digest that Cosign signs, and signed through Sigstore against the same workflow identity. It attests the source repository and commit the image was built from, and the workflow that produced it. The signature is held in the registry beside the image and the attestation by GitHub.
- Limits. The build, the signature, and the attestation are all produced by a workflow in the same repository as the source, not by an isolated trusted builder, so they are trustworthy to the extent that repository's Actions configuration is. Alcove makes no claim to a specific SLSA build level.
Verification procedures are in RELEASES.md#verifying-a-release and RELEASES.md#build-provenance.
Authority to Operate
Alcove does not hold an ATO of its own; an ATO is granted to a specific deployment within a specific authorizing environment, not to open-source software. The documentation in this repository - in particular the threat model and authentication design in SECURITY_DESIGN.md, the cryptographic protocol in PROTOCOL.md, the NIST 800-53 control mapping above, and the SBOM described in RELEASES.md - is intended to support an agency's own ATO process, not to substitute for it.
Privacy review
The project's privacy posture is published as a standalone statement at PRIVACY.md: what the project collects and retains on its own behalf, how the container deployment and the hosted web application differ in what the project operates and can observe, and what each supporting service sees. A privacy review should start there. Who operates what is in SHARED_RESPONSIBILITY.md.
For the underlying detail, a reviewer will want: what data flows and what is retained (SECURITY_DESIGN.md#data-handling), how the persistent credential is protected (SECURITY_DESIGN.md#key-file-security), what third-party supporting services can observe (PRIVACY.md), and who can attack what (SECURITY_DESIGN.md#threat-model).
Privacy Impact Assessment
The project does not publish a PIA of its own, and a privacy statement is not a substitute for one. A PIA assesses a deployment, and the facts that determine its conclusions -- the system owner, the authority for collection, the populations whose records are linked, and the retention schedule applied to the output -- belong to the deploying agency, not to the software. An agency completing a PIA draws the project-side inputs from PRIVACY.md (data flows, retention, and third-party visibility) and from this document (the control mappings and sector-specific framings above). If an agency needs those inputs restated in a particular PIA template, ask through the channels in SUPPORT.md.
Reporting compliance gaps
If a reviewer identifies a compliance-relevant gap that is not addressed here, please:
- Open a GitHub issue tagged
complianceif the gap is not security-sensitive. - Follow the private reporting process in SECURITY.md if the gap is security-sensitive.
See also
- SECURITY_DESIGN.md - threat model, authentication design, channel security, NIST 800-53 mapping
- SHARED_RESPONSIBILITY.md - the deployment model and the project/agency responsibility split, per deployment
- PROTOCOL.md - PSI and key-exchange protocol specification
- FIPS_SFTP_PROFILE.md - constraining an SFTP exchange's SSH layer to approved algorithms
- RELEASES.md - release artifacts, signing, and SBOM
- SECURITY.md - vulnerability reporting and response
- INCIDENT_RESPONSE.md - the responder-side runbook behind that policy, and the dated tabletop exercise record
- PRIVACY.md - the project's privacy posture, by deployment, and what supporting services can observe
- NOTICE - attributions for vendored and redistributed components, with each image's OS packages listed beside it (see CONTAINER_IMAGES.md)