On this page

Validate it · docs/validation/risk-assessment.md

Functional risk assessment

Document id CS-VAL-04
Title Functional risk assessment
Version 1.0
Applies to Countersign 1.0.0
Status Template supplied with the software; to be completed, reviewed and approved by the regulated user

Approval of the completed document:

Role Name Signature Date
Prepared by
Reviewed by
Approved by (quality assurance)

1. Purpose and method

This assessment lists what can go wrong in the use of Countersign, what the software does about it, and what the organisation must do about it. It follows the failure mode and effects pattern: hazard, cause, effect, rating, controls, residual risk. The ratings are a proposal for a typical use (GxP master data and configuration records with approvals used as electronic signatures). You must re-rate every row for your intended use, add rows for your process, and approve the result. The outcome decides the depth of testing in the OQ and PQ and the procedures you need (SOP templates).

Functional requirement ids (FR-…) refer to requirements.json and the functional specification.

2. Scales

Rating Severity (S): effect if it happens Probability (P): likelihood without the controls listed Detectability (D): chance that it is noticed before harm
H Wrong or unauthorised data in effect, or loss of the ability to trust the audit trail, with possible impact on product quality, patient safety or a regulatory decision Expected to occur in normal operation or easily done by one person Detected automatically and at once, or prevented (high detectability is good)
M Records wrong or unavailable for a time, corrected through the workflow; evidence weakened Could occur occasionally, or needs unusual circumstances or privileges Detected by a routine review or check
L Inconvenience; no effect on records in effect or on evidence Unlikely; needs several independent failures or collusion Detected only by chance or by a targeted investigation

Risk class from severity and probability, then priority from class and detectability:

P = L P = M P = H
S = H 2 1 1
S = M 3 2 1
S = L 3 3 2
D = H D = M D = L
Class 1 Medium High High
Class 2 Low Medium High
Class 3 Low Low Medium

Columns S, P, D give the rating with the technical controls of the software in place and before your procedural controls. "Residual" is the proposed priority once the procedural controls in the row are effective. A residual risk above Low needs a documented acceptance.

3. Assessment

3.1 Workflow and authority

Id Hazard Cause Effect S P D Technical controls in the software Procedural controls needed Residual
R-01 A person approves their own change Intent or habit Change in effect without independent review H L H The engine refuses approval by the author or confirmer of the version: FR-WF-04; applies to every record type and to retire and remove (FR-LIFE-01, FR-LIFE-02); same code on server and replay, so a forged self-approval fails verification (FR-INT-03) One account per person; no shared accounts; identity provider must not let one person hold two accounts with roles Low
R-02 A person changes records they have no authority over Curiosity, error, intent Unauthorised draft or pending change M L H Author permission per record type and option level: FR-ACC-01; no role, no change: FR-ACC-02; the actor comes only from the session: FR-SIG-08; nothing takes effect without approval: FR-WF-05, FR-WF-06 Approved role matrix in the configuration; access review Low
R-03 Approval by someone not qualified to judge the change, or two people colluding Roles granted too widely; a role such as * in approve; collusion Formally approved but unreviewed change H M L Approve permission per type and level: FR-WF-05; signer's name, roles and stated meaning recorded per signature: FR-WF-06, FR-AUD-01 Grant approve permissions narrowly; training on the meaning of a signature; audit trail review looks for pairs who always approve each other and for approvals seconds after confirmation Medium
R-04 A change is approved without being read Routine; time pressure Error in effect H M L The signature panel shows the change, its author and the meaning before signing: FR-UI-02; data is re-validated at approval: FR-VAL-07 Training; accountability policy for signatures; review of time between confirm and approve Medium
R-05 A change is made without a meaningful reason The reason is optional when creating and when editing a draft; the minimum for mandatory reasons is three characters History cannot explain why M M M Reason mandatory for step back, retire, remove, configuration change and changing an approved record: FR-WF-09; the dialog cannot be submitted empty: FR-UI-08 Procedure states when a reason is required and what a good reason contains; approvers reject changes with empty reasons; audit trail review samples reasons Low
R-06 An approved record is edited, retired or removed by mistake Wrong record selected Wrong pending version M M H The edit only opens a new Confirmed version, the approved one stays in effect: FR-VER-01; a second person must approve: FR-LIFE-01, FR-LIFE-02; records with live references are protected: FR-LIFE-04; step back with reason: FR-WF-08 Training Low
R-07 An approval is revoked without authority or reason Misuse of step back A previous version is in effect again, or none M L H Only an approver can revoke; reason mandatory; one audit entry: FR-WF-08, FR-WF-09, FR-VER-03 Procedure for revoking approvals; note that revoking does not require a second person Low

3.2 Identity, sessions and signatures

Id Hazard Cause Effect S P D Technical controls in the software Procedural controls needed Residual
R-08 Actions attributed to the wrong person, or one person appears under two ids COUNTERSIGN_ID_CLAIM points at a claim that is not unique, not stable or reassigned; the provider reuses identifiers Four eyes can be passed by one person; wrong attribution H L M The id comes from the verified ID token, and a token without the configured id claim is refused: FR-SIG-02, FR-SIG-03; the id, name and roles are written into every entry: FR-AUD-01, FR-AUD-04 IQ step confirming the id claim is the provider's immutable unique identifier (oid for Entra ID); the provider never reassigns identifiers; test with two real accounts Low
R-09 A person gets a role they should not have Error in COUNTERSIGN_ROLE_MAP; a provider group whose name equals a role id (values not in the map are used unchanged); wrong group membership Unauthorised authoring or approving H M M Roles come from token claims through the map: FR-SIG-04; unknown roles grant nothing: FR-ACC-02; the roles held at the time are in every entry: FR-AUD-01 Role map under change control; group names in the provider chosen so that none equals a role id unintentionally; access request and approval; periodic access review against the audit trail's actorRoles Low
R-10 A person keeps acting after their role or account was withdrawn The session cookie carries the roles until it expires (default 8 hours); there is no server-side revocation Changes by a person no longer authorised H L M Session expiry: FR-SIG-01; approvals need a recent sign-in with Entra ID or OpenID Connect, at which the provider issues current roles: FR-SIG-05 Set COUNTERSIGN_SESSION_HOURS to the shortest workable value; for urgent withdrawal rotate COUNTERSIGN_SESSION_SECRET (ends every session); leaver process Low
R-11 Someone signs on another person's unattended, signed-in workstation No inactivity time-out in the application; an approval within the sign-in window needs no credential Signature by the wrong person H M L Approval refused when the sign-in is older than COUNTERSIGN_SIGN_MAX_AGE_MINUTES (default 15), then the provider is asked to authenticate again (max_age=0, prompt=login): FR-SIG-05; sign-out: FR-SIG-06 Screen lock policy; choose the maximum age deliberately (a small value forces authentication for practically every signature); training; accountability policy Medium
R-12 The recent-sign-in rule does not prove recent authentication The provider does not send auth_time (the application then uses the token's issue time, and cannot tell whether the provider really asked again) and ignores max_age and prompt=login; or sign-in method is proxy, where the rule is not enforced A signature with an old authentication is accepted H L L When the provider sends auth_time, a requested fresh sign-in that returns an authentication older than 5 minutes is refused: FR-SIG-05; auth.authTime and auth.method are recorded in every entry: FR-AUD-04 IQ step: confirm that the provider's ID token contains auth_time and that a fresh sign-in really prompts; OQ case B-15; do not rely on the rule with proxy sign-in Low
R-13 Session forged or stolen Weak or leaked session secret; cookie copied from a device; sign-out only clears the cookie in that browser Impersonation until the session expires H L L HMAC-SHA256 cookie, constant-time comparison, minimum secret length 32, HttpOnly, SameSite=Lax, Secure over https: FR-SIG-01, FR-OPS-05 Secret generated randomly and kept in a secret store; TLS everywhere; rotate on suspicion; managed devices Low
R-14 Cross-site request forgery A user visits a hostile page while signed in Command issued in the user's name H L H Writes need a custom header and a matching origin; cookie is SameSite=Lax: FR-SIG-07 Set COUNTERSIGN_PUBLIC_URL so the origin check does not depend on forwarded headers Low
R-15 Identity headers spoofed behind a reverse proxy The application is reachable without passing the proxy; the proxy forwards client-supplied identity headers; the shared secret leaks Full impersonation of any person and role H M L Headers count only with the shared secret (at least 16 characters, constant-time comparison): FR-SIG-09 Network rules so that only the proxy reaches the application; the proxy strips incoming identity and secret headers; secret in a secret store; prefer OpenID Connect Medium
R-16 Demo sign-in left on in a server installation COUNTERSIGN_AUTH=demo set for evaluation and never changed Anyone can act as any demo person H L H Demo sign-in exists only when switched on explicitly: FR-SIG-10; /api/health and every entry show auth method demo: FR-OPS-06, FR-AUD-04 IQ step checks auth in /api/health; monitoring alerts on auth not being the approved method; audit trail review filters for auth_method other than the approved one Low
R-17 Secrets leak Secrets in files under version control, logs, shell history, backups Impersonation (session or proxy secret), token misuse (client secret), direct database writes (database password) H M L Secrets are read from the environment only; none is written to the audit trail Secret store; least-privilege database role; rotation schedule and on suspicion; IQ records that secrets are set, never their values Medium
R-18 Unauthorised attempts go unnoticed Refused commands write nothing; failed sign-ins happen at the provider Probing is not seen M M L Refusals are answered with status 401, 403 or 422: FR-OPS-07, FR-SIG-06 Keep and review web-server access logs for 401, 403 and 422 on /api/act; review the provider's sign-in logs Low
R-19 Confidential data read by people without a need Every signed-in person can read all records and the whole trail Disclosure M M L Nothing is readable without signing in: FR-SIG-06 Decide whether the data may be held here; restrict who can sign in at the provider (assignment required); no personal or confidential data in free-text fields Medium

3.3 Administration: command-line tool, configuration, migration

Id Hazard Cause Effect S P D Technical controls in the software Procedural controls needed Residual
R-20 The command-line tool is run under a false identity --actor-id, --actor-name and --actor-roles are stated by the operator and not verified Configuration change or import attributed to someone else, or done with a role the person does not hold H L M The web interface cannot import or configure: FR-SIG-08; import and configure are separate permissions: FR-ACC-03; the entry records method cli and the operating-system account and host: FR-AUD-04 Restrict who holds database credentials with INSERT; run the tool only under change control with a witness; personal operating-system accounts; review every cli entry against a change record Low
R-21 A configuration change is not really reviewed With config apply the reviewer is named by the operator and does not sign in Wrong permissions or fields in effect H L M In the application a change is proposed by one signed-in person and takes effect only when a second one with the configure permission approves it, with a fresh sign-in: FR-CFG-07, FR-CFG-08, FR-CFG-13; the approver sees the changes and their effect on existing records: FR-UI-12. From the command line in one step: the permission, a reason and a reviewer with a different id: FR-CFG-03. The entry holds the full document and its hash: FR-CFG-02; the document is checked: FR-CFG-01 Make changes in the application, or with config propose and config approve by two operators; keep config apply for emergencies under a signed change record that contains the SHA-256; after the change, compare with countersign status; SOP 4 Low
R-25 A configuration change strands or invalidates existing records A field is removed, a rule tightened or a record type dropped while records depend on it Approved data that can no longer be edited or that contradicts the rules in force H L M A proposal is refused, when proposed and again when approved, while a record in use would lose data or hold a value the new rules refuse, naming the records: FR-CFG-10; a field that becomes required leaves existing records in effect and marks them until they are completed: FR-CFG-11, FR-UI-13; the editor shows the effect before anything is submitted: FR-UI-11 Try the change on a restored copy first; work off the list of marked records after a new mandatory field; config apply --force only under a deviation Low
R-26 A record is placed under itself in a nested hierarchy A record type that nests inside itself, and two moves that close a loop Inheritance and the tree would have no defined order M L L The engine refuses, on every create, edit, approval and revoked approval, a record becoming its own ancestor, pending changes included: FR-HIER-02; the parent picker does not offer such a place: FR-UI-10 None Low
R-22 The configuration is wrong Error in the document: a role can approve too much, a field rule is missing, the inheritance order is not what was meant Wrong authority or wrong inherited values H M M Complete validation of the document: FR-CFG-01; a change cannot orphan records: FR-CFG-04; the history still replays: FR-CFG-06 Review and approval of the document; PQ with the production configuration (same SHA-256); test in the test environment first Low
R-23 Migrated data is wrong or incomplete Mapping error; source data errors; rows silently dropped Wrong records in effect, marked as approved H M M Same validation as manual entry: FR-MIG-03; parents first with conversion: FR-MIG-04; every row accounted for: FR-MIG-05; no double import: FR-MIG-02, FR-MIG-06; rehearsal before writing; report with source hashes and reconciliation; origin on every record: FR-MIG-01 Migration plan; dry run reviewed; reconciliation signed by a second person; sample comparison against the source; source files retained Low
R-24 Migration is used to bring unreviewed data in as approved Mode approved writes approved versions without an approver here Four eyes bypassed for those records H L H Needs the import permission and the command-line tool: FR-ACC-03, FR-SIG-08; every such record is marked with origin and batch and has action import in the trail: FR-MIG-01; mode review is available: FR-MIG-07 Use approved only for data approved in a validated source; otherwise review; QA approval of every batch; audit trail review lists all import entries Low

3.4 Audit trail, storage and time

Id Hazard Cause Effect S P D Technical controls in the software Procedural controls needed Residual
R-25 An audit entry is altered or deleted through the application's database account Compromised application; SQL access with the application's credentials History falsified H L H Triggers refuse UPDATE, DELETE, TRUNCATE: FR-STO-04; the application has no command that changes an entry: FR-AUD-01 Application role with SELECT and INSERT only, not the table's owner (IQ) Low
R-26 An entry in the middle of the trail is altered by a database administrator Owner or superuser disables the triggers and changes a row History falsified H L M Hash chain and replay find a changed, forged, missing, reordered or inserted entry: FR-INT-01 to FR-INT-04; a server refuses changes once it reads the damaged entry: FR-OPS-02 Scheduled countersign verify, because a running server re-checks only entries it has not read yet; few named administrators; database audit logging of DDL and of trigger changes Low
R-27 The whole tail of the trail is removed, or the database is restored from an old backup Administrator action; restore after an incident; restore to hide changes Approved changes disappear; the shortened trail verifies as intact H L L A running server notices fewer entries or a changed newest entry: FR-OPS-03. After a restart nothing in the store reveals it Head-hash anchoring outside the administrators' reach and verify --expect-entry <n>:<hash> (SOP 5); restore only under the backup SOP with comparison against the last anchor; database point-in-time recovery to minimise loss Medium
R-28 The whole trail is rewritten with recomputed hashes A skilled administrator with the source code rebuilds a consistent chain Falsified history that verifies H L L Replay also re-runs the rules, so a rebuilt chain must still be a valid history: FR-INT-03, FR-INT-06. It cannot detect a consistent rewrite Anchoring (any rewrite changes every later hash); independent copies of exports; segregation of duties between database administrators and application roles Low
R-29 An entry is inserted past the application Direct INSERT with database credentials An action nobody performed through the application H L H The insert trigger demands chain continuity: FR-STO-02; a row that breaks a rule or does not hash is found on reading and stops all changes: FR-INT-03, FR-OPS-03. A row that is rule-conformant and correctly hashed is accepted Database credentials restricted; network access to the database limited to the application servers; review of entries with unexpected auth method Low
R-30 Entries are lost Crash between acceptance and durable write; storage failure; memory store used; file store on unreliable storage Accepted changes missing H L M The response is sent only after the store accepted the entry; SQLite and the file store sync to disk; state is rebuilt from the store only: FR-STO-01, FR-STO-03 PostgreSQL with durable settings (fsync, synchronous_commit on) and tested backup; never memory or the demo path for real records (IQ checks storage in /api/health) Low
R-31 Two servers write at once and the trail forks Several application servers Inconsistent history H M H The store accepts exactly one entry per number; the loser retries on the new head: FR-STO-05, FR-STO-02 Several servers only with PostgreSQL; never two servers on one SQLite or file store Low
R-32 Entry times are wrong Server clock not synchronised; time zone confusion; a clock set ahead (later entries then all carry that future time until real time passes it) Sequence of events misdated M M M Time from the server, never from the browser; never earlier than the previous entry: FR-AUD-03, FR-OPS-04; stored in UTC; PostgreSQL also stores its own inserted_at Time synchronisation on application and database servers with monitoring; audit trail review compares at with inserted_at; incident if they differ by more than the tolerance Low
R-33 An alteration of a convenience column of the table goes unnoticed The plain columns at, actor, action, record_id, record_type repeat the entry for indexes and queries and are not checked against it A query written directly against those columns shows altered data while verify passes M L L The application reads only the hashed entry text; the view countersign_audit_trail takes every column from entry as well Build reports on the view, the exports or the application, never on the plain columns; periodic check that the columns equal the values inside entry (query in data integrity, section 6.4) Low
R-34 An integrity fault is not acted on, or the system is unavailable No monitoring; no trained responder Work stops; pressure to bypass M L H /api/health answers 503 with integrity-fault, store-unreachable or misconfigured; writes are refused, reading continues: FR-OPS-02, FR-OPS-06 Monitoring and alerting; integrity-fault SOP; business continuity SOP Low

3.5 Options, exports, operation and change

Id Hazard Cause Effect S P D Technical controls in the software Procedural controls needed Residual
R-35 A wrong option value is taken as the one in effect Misreading inheritance; a pending value mistaken for an approved one; a definition changed under its values Wrong setting used downstream H M H Only approved, active values count, with source shown: FR-OPT-04, FR-OPT-05, FR-UI-05; definitions cannot strand values: FR-OPT-06; a value that no longer fits is skipped and reported: FR-OPT-07 Training; PQ scenario covering every level; consumers of the data read effective values only Low
R-36 An export is taken as complete evidence when it is not, or a spreadsheet alters it The CSV summarises changes and omits the full before, after and command; spreadsheets reformat cells Incomplete or distorted inspection copy M M M No executable cells in the CSV: FR-EXP-01; complete entries in JSON and JSON Lines, verifiable against the chain Use JSON Lines for archive and evidence, CSV for review only; verify exports with the script in data integrity Low
R-37 A new version of the software evaluates old entries differently A rule change in the engine; replay re-runs every stored command under the installed version After the upgrade the server reports an integrity fault on a trail that was never altered, and refuses changes H L H Replay stops at the first entry that does not reproduce: FR-INT-06, FR-OPS-02 Before every upgrade run the new version's countersign verify against a copy of production; keep the old version deployable; upgrade SOP Low
R-38 A defect in the engine lets a rule be bypassed Software error Any of the above H L M One engine for browser, server and replay; requirement-tagged tests; traceability check: all FR Run the full suite in OQ; manual tests of high-risk rules; follow the project's security advisories; periodic review Low
R-39 Performance degrades as the trail grows State is replayed in memory at start and held in memory; the browser loads the trail Slow start, slow pages, memory exhaustion M M H None beyond the design Measure in PQ with the expected volume plus margin; monitor start time and memory; see PQ protocol, section 6 Low
R-40 Data is exposed or changed in transit No TLS, or TLS ending at an untrusted point Disclosure; session theft H L M Secure cookie flag when the public address is https TLS on every hop; IQ step Low
R-41 Records become unreadable over the retention period No archiving function; dependence on the application Records unavailable for inspection H L M Open export formats; documented hash algorithm; standalone verification script Retention and archive SOP; periodic readability check of archives Low

4. Risks of the organisation (add)

Id Hazard Cause Effect S P D Technical controls Procedural controls Residual
R-U-01
R-U-02
R-U-03

5. Conclusions (complete)

Item Entry
Rows re-rated for the intended use
Residual risks above Low and their acceptance
Tests added to OQ or PQ because of this assessment
Procedures required (reference)
Next review of this assessment

The rows proposed above as Medium after controls are R-03, R-04, R-11, R-15, R-17, R-19 and R-27. Each rests on a control the software cannot provide: human diligence, physical access to a signed-in workstation, the network in front of the application, secret handling, the absence of read restrictions, and an anchor outside the database.