From 268d16d30a6ee48cb9cd17f47c3465075c2dcde5 Mon Sep 17 00:00:00 2001 From: Isaac Vetter Date: Tue, 7 Oct 2025 10:24:10 -0500 Subject: [PATCH 01/10] Update best-practices.md --- docs/best-practices.md | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/docs/best-practices.md b/docs/best-practices.md index 55ed4f44..cf31beeb 100644 --- a/docs/best-practices.md +++ b/docs/best-practices.md @@ -1,6 +1,42 @@ # Implementation Best Practices -This page serves as best practice guidance for CDS Hooks implementers. The best practices outlined here are not mandatory implementation rules; rather, they are suggested guidance. This is a living, in progress document and the best practices outlined here should not be considered absolute or complete. +The Clinical Decision Support Hooks standard aims to provide real-time, actionable support to clinicians with minimal intrusion. Including [existing security and safety recommendations]([url](https://cds-hooks.hl7.org/2.0/#security-and-safety)), this living document outlines best practices to support secure, minimally intrusive decision support. These best practices are not a substitute for the security and legal review conducted by a health system before integrating 3rd party software. + +## CDS Service Developers: +* CDS Services must be _fast_. + * Expect to invest resources into optimizing the speed of your service. CDS Client FHIR APIs may be a limiting factor in service performance. + * CDS Services should return guidance on the order of 500 ms. + * Use & optimize **prefetch**. (If prefetch is not supported by an EHR, the HL7 "[CRMI Module Configuration Library]([url](https://hl7.org/fhir/uv/crmi/StructureDefinition-crmi-moduleconfigurationlibrary.html))" pattern provides similar benefits). + * Use supported search parameters to **limit** the data returned. Test and analyze a variety of requests and parameters to optimize response time. + * Make use of date search parameters whenever possible. + * Use `_include` and `_revinclude` to minimize the number of queries performed. For example: `MedicationRequest?subject=test-1&date=ge2024-12-01&status=active,completed,stopped&category=community&intent=order&_include=MedicationRequest:medication`. + * Often non-production test data does not accurately represent real-world data, e.g. longterm inpatient stays. Consider pilots and be prepared for performance differences in production. + * Implement parallelization. + * Leverage caching. + * Virtually never should a CDS Service query for all Observation vitals. +* CDS Services should provide only actionable feedback to the clinician, for example: discrete suggestions instead of info cards. +* Carefully target known CDS Client capabilities such as specific hooks, widely supported FHIR profiles and search parameters. Confirm capabilities at the site-level, and be prepared with configuration points to support site-specific customizations. + +### Implementation Considerations for CDS Service Developers +* Provide your CDS Service in a containerized form to facilitate local implementation. +* Site-specific middleware may cause differences in EHR capabilities and impact security, performance, and communication. +* Implementation of a CDS Service requires representatives from the local site, including IT (sysadmins, security, network, EHR analysts, interop, LIS) as well as users (clinicians). +* Consider initial deployment in "silent mode" to validate service performance with actual patient records. +* Coding systems and identifies may be organization specific. Validate. + +## CDS Clients (such as EHRs) +* Support pre-fetch via your pre-existing RESTful FHIR capabilities. +* Don't create new clinical workflows for hooks; rather, trigger a CDS Hooks from appropriate pre-existing clinical workflows. +* Integrate CDS Hooks into any pre-existing CDS rule engine; thereby supporting both local and external cds criteria together to improve performance. +* $lastn can improve performance. + +## Health Systems and Other CDS Hook Users: +* Follow the CDS 5 Rights; including right time, and person. +* Use the right hook during the right workflow. For example, it may be more appropriate to use the order-select or order-sign hooks for facilitating decision support regarding the order of a specific medication, rather than the patient-view +* Avoid calling the CDS Service unnecessarily. Use native EHR rule engine capabilities to limit calls. For example, a CDS Hook service should never be invoked at every patient-view. +* Use non-interruptive alerts integrated into clinician workflows when reasonable, rather than blocking workflow. +* Utilize natively supported client alert feedback and tracking capabilities, when available, to better evaluate the CDS service’s impact and utilization. +* To preserve clinical user experience, CDS Hooks should be considered only for actionable clinical decision support and not as an event notification framework. ## Security From 32d35b1ddc6eaf36dcc52f392194538c3f354d5d Mon Sep 17 00:00:00 2001 From: Isaac Vetter Date: Tue, 7 Oct 2025 10:26:47 -0500 Subject: [PATCH 02/10] remove security content from best practices --- docs/best-practices.md | 58 ------------------------------------------ 1 file changed, 58 deletions(-) diff --git a/docs/best-practices.md b/docs/best-practices.md index cf31beeb..918ed5bd 100644 --- a/docs/best-practices.md +++ b/docs/best-practices.md @@ -37,61 +37,3 @@ The Clinical Decision Support Hooks standard aims to provide real-time, actionab * Use non-interruptive alerts integrated into clinician workflows when reasonable, rather than blocking workflow. * Utilize natively supported client alert feedback and tracking capabilities, when available, to better evaluate the CDS service’s impact and utilization. * To preserve clinical user experience, CDS Hooks should be considered only for actionable clinical decision support and not as an event notification framework. - -## Security - -The CDS Hooks security model requires thought and consideration from implementers. Security topics are never binary, are often complex, and robust implementations should factor in concepts such as risk and usability. Implementers should approach their security related development with thoughtful care. - -The CDS Hooks specifications already provides some guidance in this space. The information here is supplemental to the existing specification documentation. - -The CDS Hooks security model leverages several existing RFCs. These should be read and fully understood by all implementers. - -- [rfc7519: JSON Web Tokens (JWT)](https://tools.ietf.org/html/rfc7519) -- [rfc7517: JSON Web Key (JWK)](https://tools.ietf.org/html/rfc7517) -- [rfc7515: JSON Web Signature (JWS)](https://tools.ietf.org/html/rfc7515) -- [rfc7518: JSON Web Algorithms (JWA)](https://tools.ietf.org/html/rfc7518) - -### CDS Clients - -Implementers of CDS Clients should: - -**Maintain an allowlist of CDS Service endpoints that may be invoked.** - -Only endpoints on the allowlist can be invoked. This ensures that CDS Clients invoke only trusted CDS Services. This is especially important since CDS Clients may send an authorization token that allows the CDS Service temporary access to the FHIR server. - -**Issue secure FHIR access tokens.** - -*If* a CDS Client generates access tokens to its FHIR server, the tokens should: - -- Be unique for each CDS Service endpoint. -- Be very short-lived. -- Provide the minimum necessary access for the CDS Service. This includes both SMART scopes as well as the patient(s)/data that can be accessed. - -**Audit CDS Service's access to data** - -Regardless of the use of prefetch or more typical FHIR RESTful APIs, CDS Clients should audit and report on data access. - -### CDS Services - -#### JWT - -Upon being invoked by a CDS Client, the CDS Service should first process the given JWT to determine whether to process the given request. In processing the JWT, CDS Services should: - -1. Ensure that the `iss` value exists in the CDS Service's allowlist of trusted CDS Clients. -2. Ensure that the `aud` value matches the CDS Service endpoint currently processing the request. -3. Ensure that the `exp` value is not before the current date/time. -4. Ensure that the `tenant` value exists in the CDS Service's allowlist of trusted tenants (may not be applicable to all CDS Services). -5. Ensure that the JWT signature matches the public key on record with the CDS Service. See additional notes below. -6. Ensure that the `jti` value doesn't exist in the short-term storage of JWTs previously processed by this CDS Service. - -Once the JWT has been deemed to be valid, the `jti` value should be stored in the short-term storage of processed JWTs. Values in this storage only need to be kept for the maximum duration of all JWTs processed by this CDS Service. If the CDS Clients are adhering to best practices, this should be no more than an hour. - -Verifying the JWT signature is a critical step in establishing trust of the caller of the CDS Service. As part of the allowlist of trusted CDS Clients, information on the public key(s) used by the CDS Client should also be stored. In some cases, this public key may be shared out-of-band. In other cases, the public key may be available at a remote endpoint and cycled on a regular basis. It is this latter case in which CDS Services should maintain their own rotating cache of public keys for the CDS Client. - -CDS Services should never store, share, or log JWTs to minimize the risk of theft and replay attacks. Information within the JWT (for instance, `iss`, `tenant`, `jti`) can be logged safely and is especially useful for analytics. - -If a CDS Service deems a JWT to be invalid for any reason, it should not leak the details of why the JWT failed validation back to the caller. If the caller were a malicious threat actor, leaking detailed information as to what was invalid may give the threat actor guidance on how to shape future attacks. Instead, responding to the request with a HTTP 401 Unauthorized response status code without any additional information is recommended. - -#### FHIR Access - -CDS Services should never store, share, or log the FHIR access token (`fhirAuthorization.access_token`) given to it by the CDS Client. The access token should be treated as an extremely sensitive, transient piece of data. From f479f9231891f9b160677f59edd86f30a7fccf5d Mon Sep 17 00:00:00 2001 From: Isaac Vetter Date: Tue, 7 Oct 2025 10:27:21 -0500 Subject: [PATCH 03/10] Create security-considerations.md --- docs/security-considerations.md | 61 +++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 docs/security-considerations.md diff --git a/docs/security-considerations.md b/docs/security-considerations.md new file mode 100644 index 00000000..815d1fb8 --- /dev/null +++ b/docs/security-considerations.md @@ -0,0 +1,61 @@ +# Security Considerations + +This page serves as best practice guidance for CDS Hooks implementers. The best practices outlined here are not mandatory implementation rules; rather, they are suggested guidance. This is a living, in progress document and the best practices outlined here should not be considered absolute or complete. + +## Security + +The CDS Hooks security model requires thought and consideration from implementers. Security topics are never binary, are often complex, and robust implementations should factor in concepts such as risk and usability. Implementers should approach their security related development with thoughtful care. + +The CDS Hooks specifications already provides some guidance in this space. The information here is supplemental to the existing specification documentation. + +The CDS Hooks security model leverages several existing RFCs. These should be read and fully understood by all implementers. + +- [rfc7519: JSON Web Tokens (JWT)](https://tools.ietf.org/html/rfc7519) +- [rfc7517: JSON Web Key (JWK)](https://tools.ietf.org/html/rfc7517) +- [rfc7515: JSON Web Signature (JWS)](https://tools.ietf.org/html/rfc7515) +- [rfc7518: JSON Web Algorithms (JWA)](https://tools.ietf.org/html/rfc7518) + +### CDS Clients + +Implementers of CDS Clients should: + +**Maintain an allowlist of CDS Service endpoints that may be invoked.** + +Only endpoints on the allowlist can be invoked. This ensures that CDS Clients invoke only trusted CDS Services. This is especially important since CDS Clients may send an authorization token that allows the CDS Service temporary access to the FHIR server. + +**Issue secure FHIR access tokens.** + +*If* a CDS Client generates access tokens to its FHIR server, the tokens should: + +- Be unique for each CDS Service endpoint. +- Be very short-lived. +- Provide the minimum necessary access for the CDS Service. This includes both SMART scopes as well as the patient(s)/data that can be accessed. + +**Audit CDS Service's access to data** + +Regardless of the use of prefetch or more typical FHIR RESTful APIs, CDS Clients should audit and report on data access. + +### CDS Services + +#### JWT + +Upon being invoked by a CDS Client, the CDS Service should first process the given JWT to determine whether to process the given request. In processing the JWT, CDS Services should: + +1. Ensure that the `iss` value exists in the CDS Service's allowlist of trusted CDS Clients. +2. Ensure that the `aud` value matches the CDS Service endpoint currently processing the request. +3. Ensure that the `exp` value is not before the current date/time. +4. Ensure that the `tenant` value exists in the CDS Service's allowlist of trusted tenants (may not be applicable to all CDS Services). +5. Ensure that the JWT signature matches the public key on record with the CDS Service. See additional notes below. +6. Ensure that the `jti` value doesn't exist in the short-term storage of JWTs previously processed by this CDS Service. + +Once the JWT has been deemed to be valid, the `jti` value should be stored in the short-term storage of processed JWTs. Values in this storage only need to be kept for the maximum duration of all JWTs processed by this CDS Service. If the CDS Clients are adhering to best practices, this should be no more than an hour. + +Verifying the JWT signature is a critical step in establishing trust of the caller of the CDS Service. As part of the allowlist of trusted CDS Clients, information on the public key(s) used by the CDS Client should also be stored. In some cases, this public key may be shared out-of-band. In other cases, the public key may be available at a remote endpoint and cycled on a regular basis. It is this latter case in which CDS Services should maintain their own rotating cache of public keys for the CDS Client. + +CDS Services should never store, share, or log JWTs to minimize the risk of theft and replay attacks. Information within the JWT (for instance, `iss`, `tenant`, `jti`) can be logged safely and is especially useful for analytics. + +If a CDS Service deems a JWT to be invalid for any reason, it should not leak the details of why the JWT failed validation back to the caller. If the caller were a malicious threat actor, leaking detailed information as to what was invalid may give the threat actor guidance on how to shape future attacks. Instead, responding to the request with a HTTP 401 Unauthorized response status code without any additional information is recommended. + +#### FHIR Access + +CDS Services should never store, share, or log the FHIR access token (`fhirAuthorization.access_token`) given to it by the CDS Client. The access token should be treated as an extremely sensitive, transient piece of data. From 862236d04f1d549a8816c914f287f0939f7a4b2e Mon Sep 17 00:00:00 2001 From: Isaac Vetter Date: Tue, 7 Oct 2025 10:28:59 -0500 Subject: [PATCH 04/10] add security considerations to menu --- mkdocs.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/mkdocs.yml b/mkdocs.yml index 35cc7d78..74609eb2 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -17,6 +17,7 @@ nav: - Quick Start: 'quickstart.md' - Cheat Sheet: 'cheat-sheet/Cheat Sheet - Sept 2019.pdf' - Best Practices: 'best-practices.md' +- Security Considerations: 'security-considerations.md' - Examples: 'examples.md' - Community: 'community.md' - Logo Use: 'logo-use.md' From d177468e41b2496eeeadd58d4afbd468848fa1ed Mon Sep 17 00:00:00 2001 From: Isaac Vetter Date: Tue, 7 Oct 2025 10:32:22 -0500 Subject: [PATCH 05/10] ubuntu-20.04 to latest instead GH deprecated ubuntu 20.04 this spring. --- .github/workflows/publish-docs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish-docs.yml b/.github/workflows/publish-docs.yml index df98dae2..ec9b6fe3 100644 --- a/.github/workflows/publish-docs.yml +++ b/.github/workflows/publish-docs.yml @@ -10,7 +10,7 @@ on: jobs: build: - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 From 66dffdbabd81b18461cc8705e32f375133d9821f Mon Sep 17 00:00:00 2001 From: Isaac Vetter Date: Tue, 7 Oct 2025 10:35:19 -0500 Subject: [PATCH 06/10] python 3.6 -> 3.13 --- .github/workflows/publish-docs.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish-docs.yml b/.github/workflows/publish-docs.yml index ec9b6fe3..6a908582 100644 --- a/.github/workflows/publish-docs.yml +++ b/.github/workflows/publish-docs.yml @@ -15,10 +15,10 @@ jobs: steps: - uses: actions/checkout@v2 - - name: Set up Python 3.6 + - name: Set up Python 3.13 uses: actions/setup-python@v2 with: - python-version: 3.6 + python-version: 3.13 - name: Setup dependencies run: pip install -r requirements.txt From 38cb58fbcc7b632cd5ad805fa89aa68cba42b62b Mon Sep 17 00:00:00 2001 From: Isaac Vetter Date: Tue, 7 Oct 2025 10:36:07 -0500 Subject: [PATCH 07/10] python-3.13.7 --- runtime.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime.txt b/runtime.txt index fc81e755..54b1bdcd 100644 --- a/runtime.txt +++ b/runtime.txt @@ -1 +1 @@ -python-3.6.2 \ No newline at end of file +python-3.13.7 From 722fc8bc1370a48576288718e2172e1073c409fd Mon Sep 17 00:00:00 2001 From: Isaac Vetter Date: Tue, 7 Oct 2025 10:44:15 -0500 Subject: [PATCH 08/10] Update dependencies to latest --- requirements.txt | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/requirements.txt b/requirements.txt index e8e564b8..426e26ca 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,13 +1,13 @@ -backports-abc==0.5 -certifi==2019.11.28 -click==7.1.1 -Jinja2==2.11.3 -livereload==2.6.1 -Markdown==3.2.1 -MarkupSafe==1.1.1 -mkdocs==1.1 -PyYAML==5.4 -singledispatch==3.4.0.3 -six==1.14.0 -tornado==6.0.4 -mkdocs-material==4.6.3 +#backports-abc==0.5 +certifi==2025.10.05 +click==8.3.0 +Jinja2==3.1.6 +livereload==2.7.1 +Markdown==3.9 +MarkupSafe==3.0.3 +mkdocs==1.6.1 +PyYAML==6.0.2 +singledispatch==4.1.2 +six==1.17.0 +tornado==6.5.2 +mkdocs-material==9.6.21 From 0de9455f4ac62c9f274811f4dc95959a9f9d3eff Mon Sep 17 00:00:00 2001 From: graham-stig <150635732+graham-stig@users.noreply.github.com> Date: Mon, 13 Oct 2025 12:25:50 -0500 Subject: [PATCH 09/10] Trying to fix build. Merge into best-practices and retry completing the PR --- mkdocs.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mkdocs.yml b/mkdocs.yml index 74609eb2..635b943d 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -7,8 +7,8 @@ theme: extra: social: - - type: 'github' - link: 'https://github.com/cds-hooks' + - icon: fontawesome/brands/github + link: https://github.com/cds-hooks nav: - Overview: 'index.md' From ebcd160c52463bb805f1e9ab7814253779736d14 Mon Sep 17 00:00:00 2001 From: graham-stig <150635732+graham-stig@users.noreply.github.com> Date: Thu, 16 Oct 2025 11:59:34 -0500 Subject: [PATCH 10/10] Fix link formatting in best-practices.md --- docs/best-practices.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/best-practices.md b/docs/best-practices.md index 918ed5bd..29ad90de 100644 --- a/docs/best-practices.md +++ b/docs/best-practices.md @@ -6,7 +6,7 @@ The Clinical Decision Support Hooks standard aims to provide real-time, actionab * CDS Services must be _fast_. * Expect to invest resources into optimizing the speed of your service. CDS Client FHIR APIs may be a limiting factor in service performance. * CDS Services should return guidance on the order of 500 ms. - * Use & optimize **prefetch**. (If prefetch is not supported by an EHR, the HL7 "[CRMI Module Configuration Library]([url](https://hl7.org/fhir/uv/crmi/StructureDefinition-crmi-moduleconfigurationlibrary.html))" pattern provides similar benefits). + * Use & optimize **prefetch**. (If prefetch is not supported by an EHR, the HL7 [CRMI Module Configuration Library](https://www.hl7.org/fhir/uv/crmi/StructureDefinition-crmi-moduleconfigurationlibrary.html) pattern provides similar benefits). * Use supported search parameters to **limit** the data returned. Test and analyze a variety of requests and parameters to optimize response time. * Make use of date search parameters whenever possible. * Use `_include` and `_revinclude` to minimize the number of queries performed. For example: `MedicationRequest?subject=test-1&date=ge2024-12-01&status=active,completed,stopped&category=community&intent=order&_include=MedicationRequest:medication`.