Risks and technical debt¶
The design and gbo-demo v0.9.0 have known risks and technical debt. The risk list carries forward the gap analysis of the archived reference architecture v0.6.2, with updates from the demo findings. Every entry names its follow-up: a decision, a hardening action, a demo issue, or an open question. Each entry links the findings (F), open questions (Q), requirements (REQ), and decisions (ADR) that it rests on.
Overview¶
Each risk belongs to one group:
| ID | Risk | Group |
|---|---|---|
| R1 | The ASI exists at demo grade only | Routes |
| R2 | The SDG-OOTS bridge is design-level only | Routes |
| R3 | No Gov-to-Gov regime and no positive evidence for it | Routes |
| R4 | The consent proof is a bearer token | Security |
| R5 | The EUDI adapter accepts unauthenticated issuance callbacks | Security |
| R6 | No rate limiting or quota | Security |
| R7 | Data-chain responses are not sealed | Security |
| R8 | Contract acceptance sees the parties but not the service | Security |
| R9 | Demo-grade shared services | Production readiness |
| R10 | The consent register (toestemmingsregister) is a dependency of every DvTP decision | Production readiness |
| R11 | The demo runs one PDP for all providers | Production readiness |
| R12 | Policy distribution has no integrity chain and no visible fallback | Production readiness |
| R13 | The PDP mapper is a patch on OpenFTV | Production readiness |
| R14 | New sources need a restart of the issuance server | Production readiness |
| R15 | The legal ceiling of the service catalog (dienstencatalogus) has no technical counterpart | Governance |
| R16 | Rego instead of ODRL | Governance |
| R17 | GraphQL is not a recognized data service (datadienst) type of the Federatief Datastelsel (FDS) | Governance |
| R18 | Integrator mandates have no validity and no governance | Governance |
| R19 | LDV gaps: citizen view, activity register, ASIP | Governance |
| R20 | Onboarding cost for small bronhouders | Governance |
| R21 | The absence of a consent proof selects the PID regime | Security |
| R22 | BSN in the decision logs of the EUDI and ASI routes | Privacy |
| R23 | The ADL record is incomplete behind the FSC Inway | Audit |
| R24 | The consent proof freezes at consent | DvTP |
| R25 | Source isolation is incomplete | Security |
| R26 | The QTSP can read the BSN in the ASI token | Privacy |
| R27 | No national register for QTSP admission | ASI |
| R28 | No link between the QTSP login and the source login | ASI |
| R29 | The NL PID has no place of birth | ASI |
| R30 | Fuzzy matching without returning a value | ASI |
| R31 | The backend revokes a revoked consent again | DvTP |
| R32 | Only the network protects the register listener | Security |
| R33 | A suspended consumer keeps access | DvTP |
| R34 | Any connected peer can read any consent status | Security |
| R35 | The consumer sets the consent validity | DvTP |
| R36 | Attestations are valid 365 days without a change feed | EUDI |
| R37 | BSNk recognition of the consent facility (toestemmingsvoorziening) is not settled | DvTP |
Routes¶
R1: The ASI exists at demo grade only¶
- Risk: The Authentic Source Interface is built (ADR-0037), but only as a local demo stack. From January 1, 2027, the interface of CIR 2026/1735 Annex IV and the seal obligation apply (F-80).
- Impact: Production needs these parts, which the demo does not have:
- a qualified seal certificate and its holder (Q-17, Q-28, Q-32)
- the national register of relying parties and access certificates (R27)
- real identification means: the DigiD route is a mock, and the wallet verifier also trusts the development issuer CA (Q-36)
- a decision on the role of GBO (Q-37) and on catalog registration (Q-31, Q-67)
- a simulation deployment (#594)
- Follow-up: Three items track this risk:
- Related: F-80, F-84, F-87, REQ-112, SL-28.
R2: The SDG-OOTS bridge is design-level only¶
- Risk: The AS4 bridge for SDG-OOTS has no implementation.
- Impact: Until the bridge is built, the EU obligation is not met.
- Follow-up: ADR-0020, ADR-0024. It is open who builds the adapter (Q-79).
- Related: SDG-OOTS scenario.
R3: No Gov-to-Gov regime and no positive evidence for it¶
- Risk: The PDP knows two regimes: consent and PID. No legal-basis regime, rule set, or legal basis (grondslag) data exists. A request without a consent proof falls in the PID regime (ADR-0031).
- Impact: The two-path access-basis model of ADR-0004 is only half proven. A Gov-to-Gov regime cannot reuse "absence of a token" as its evidence, because the PID regime already uses it (R21).
- Follow-up: Define the positive evidence for a legal basis. Then add a regime and a rule set.
- Related: REQ-74, Gov-to-Gov scenario.
Security hardening¶
R4: The consent proof is a bearer token¶
- Risk: The actor binding stops another consumer from using a proof. It does not stop replay by the same consumer within the validity period.
- Impact: A stolen proof gives data access for its remaining life.
- Follow-up: Make the validity period shorter. Bind the proof to the FSC identity with proof of possession (ADR-0032).
- Related: REQ-68, Bearer token.
R5: The EUDI adapter accepts unauthenticated issuance callbacks¶
- Risk: The issuance server verifies the PID disclosure. The gap is
behind it: the adapter route
POST /attestations/{source}/{type}has no caller authentication (source_release_runtime.go#L69-L81, plainListenAndServeatmain.go#L700). The developer portal shows the gap: its playground posts a typed BSN straight to the adapter through/eudi-api/(EudiQrPanel.tsx#L36-L51,nginx.conf#L36-L42). - Impact: Any caller that reaches the adapter can post an arbitrary
BSN. The adapter calls the source over FSC as the designated issuer. As
a result, the PDP allows the request, and the adapter returns the claims
without any wallet. Two more gaps add to this risk:
- nothing binds the BSN in the source query to the verified disclosure
- the PID trust list of the issuance server also holds non-PID anchors, including the GBO development issuer CA.
- Follow-up: Authenticate the callback (mTLS or a signed request from the issuance server), or let the adapter verify the SD-JWT itself. Bind the disclosure to the request. Restrict the PID trust list to PID issuers (REQ-45, #133). The QTSP callback already uses a secret path and CA-pinned TLS.
- Related: F-70, Q-18, ADR-0018, SL-25 (dropped), the callback gap.
R6: No rate limiting or quota¶
- Risk: Authorization concern ⑤ exists only as structural checks: parse, depth, size, and coverage. Rate limiting and quota are not built.
- Impact: Only the FSC contracts limit enumeration and abuse.
- Follow-up: Define limits per grant. Enforce them at the Inway or the PDP (ADR-0004).
- Related: REQ-17.
R7: Data-chain responses are not sealed¶
- Risk: DvTP and EUDI source responses carry no qualified electronic
seal. ASI verification results carry a seal: a detached JWS (ES256,
x5c) over the exact body. The ASI certificate is a development certificate and is not qualified (REQ-83). - Impact: Non-repudiation of a data-chain response rests on the FSC transaction log and the ADL. No seal supports it.
- Follow-up: Decide whether every source response gets one seal, whatever the channel (Q-75). The ASI seal format waits for Q-32 (ADR-0041). The BSN in the decision logs is a separate risk (R22).
- Related: F-80, E4.
R8: Contract acceptance sees the parties but not the service¶
- Risk: The autosign input carries peer IDs and grant types only.
- Impact: At contract time, the policy cannot enforce admission per service.
- Follow-up: An upstream FSC change. Until that change, request-time rules compensate (ADR-0015).
- Related: F-56 (closed), REQ-62.
R21: The absence of a consent proof selects the PID regime¶
- Risk: A request without a consent proof is in the PID regime
(
engine.rego#L168-L181). The only control is the list of designated issuers per EUDI rule. A consumer on that list can skip consent: it leaves out the consent proof. - Impact: The PID regime rests on an identifier whose origin no one in the chain checks. A test keeps the issuer list disjoint from the DvTP consumers, but the test knows only the local consumers. For the simulation consumer, only an inspection shows that it is disjoint.
- Follow-up: Make positive PID evidence at the point where the wallet presentation is verified. Bind this evidence to the subject of the query (REQ-45, #133, #381). Until then, test the disjointness per environment.
- Related: F-70, REQ-74, Q-18, Q-22, ADR-0031.
R25: Source isolation is incomplete¶
- Risk: The rule "Decrypt only after the allow" depends on one
condition: only the FSC Inway reaches the source gateway
(REQ-81). In Docker Compose,
the gateways publish no port and are only on
source-gatewaysandsources. However, the source APIs (graphql-server,brp-graphql-server,lvg-graphql-server) are also onbackendandfsc-infra(docker-compose.yml#L631-L636), together with the consumer backend (#L1080-L1082). - Impact: A party on those networks can reach a source API without the Inway, the PDP, and the gateway. The Helm chart has no NetworkPolicy. The decrypted value is not bound to one consent (no nonce).
- Follow-up: Take the source APIs off the shared networks. Outside Compose, add a NetworkPolicy or an equal control. Add the nonce as a second safeguard (BSNk preconditions).
- Related: F-79, REQ-21, ADR-0033, network isolation.
R32: Only the network protects the register listener¶
- Risk: The register listener for create, list, read, and revoke has
no caller authentication. The consent portal (toestemmingsportaal) backend is its only
intended caller (REQ-39). In
Compose, the register is on
backend(docker-compose.yml#L737-L740). - Impact: Any party that reaches the register directly can create or revoke consents for every citizen.
- Follow-up: Decide between authentication of the backend and network isolation (Q-58). Isolation alone works only under one condition: the register and the backend run at one participant (Q-49).
- Related: REQ-76 (the status listener goes over FSC).
R34: Any connected peer can read any consent status¶
- Risk: The status service over FSC answers every peer that has a contract for it. It does not check that the caller is the PDP of a source in the consent.
- Impact: A connected peer with a
consent_idlearns its status. - Follow-up: Restrict the status answer to the PDPs of the sources in the consent (REQ-76, #382).
- Related: ADR-0032.
Privacy and audit¶
R22: BSN in the decision logs of the EUDI and ASI routes¶
- Risk: In the EUDI and ASI routes, the query names the citizen with the plain BSN. The PDP input, the ADL, and the console decision log hold it. Nothing masks the BSN, and the mapper stopped pseudonymizing it.
- Impact: REQ-60 is not met for these routes. Masking alone also does not meet the requirement.
- Follow-up: Keep identifiers out of the PDP input (ADR-0043, proposed). The decision is made in #368.
- Related: F-54, SL-29 (reversed by PR #370), the BSN exception.
R23: The ADL record is incomplete behind the FSC Inway¶
- Risk: The ADL is the authoritative decision record (ADR-0036). Three parts are missing:
- Impact: An auditor finds the record only through the stored request header. The auditor cannot replay the decision against a known policy.
- Follow-up: Fix the trace headers upstream in open-fsc (ADR-0035). Record the bundle revision in the ADL.
- Related: F-41, REQ-71, Q-25.
R26: The QTSP can read the BSN in the ASI token¶
- Risk: ETSI requires the identification data in the access token.
In the demo, a token claim holds the BSN in readable form
(
tokens.go#L29). - Impact: The QTSP holds the token. It can read a BSN that it is not allowed to process (P-04).
- Follow-up: Encrypt the identification data for the ASIP (#595). Send the gap to ETSI (E7).
- Related: F-86, REQ-86, Q-36.
ASI production gaps¶
R27: No national register for QTSP admission¶
- Risk: The authorization server admits a QTSP on the entitlement
QEAA_Providerin the national register of relying parties. That register and its API do not exist. It is not fixed which identifier links the QTSP certificate to its entry. The demo uses a stub register file. - Impact: QTSPs cannot be admitted in production. If the register is unreachable during a re-check, the demo keeps the client active (fail-open). Issued tokens stay valid up to 10 minutes after a withdrawal.
- Follow-up: Q-34 (outage behavior), Q-35 (identifier), Q-41 (tokens after withdrawal).
- Related: F-85, REQ-88, REQ-89, E10.
R28: No link between the QTSP login and the source login¶
- Risk: The QTSP identifies the citizen, and the ASI authorization server identifies the citizen again. Nothing links the two. The QR route can be completed on another phone.
- Impact: A QTSP can attest the data of person B to person A.
- Follow-up: Add a check under CIR 2025/1569 art. 9(5). In this check, the QTSP sends its identification data for verification. As an alternative, the QTSP gives this data to the authorization server as a hint (Q-40). Send the gap to ETSI (E6).
- Related: F-93, REQ-90, REQ-102.
R29: The NL PID has no place of birth¶
- Risk: CIR 2024/2977 makes the place of birth a mandatory PID attribute. The NL PID type metadata has no place of birth. As a result, the authorization server asks for four of the five mandatory attributes.
- Impact: If the Netherlands reads "identification data" as the mandatory PID attributes, a token from the NL Wallet cannot meet that reading. DigiD gives a BSN only (F-88).
- Follow-up: Ask the NL Wallet team. Fix the minimum identification data in the PSA (Q-36).
- Related: F-94, REQ-86.
R30: Fuzzy matching without returning a value¶
- Risk: The ASIP gives
MatchWithVariationand never returns the stored value. Annex IV of CIR 2026/1735 makes the value optional but keeps the fuzzy-matching requirement. The conformance matrix marks that requirementfailing. - Impact: In a literal reading of the annex, the ASIP does not conform.
- Follow-up: Decide whether the ASIP returns the value on a match (Q-29). Send the gap to ETSI (E2).
- Related: F-92, REQ-85, REQ-113.
DvTP consent¶
R24: The consent proof freezes at consent¶
- Risk: BSNk transforms only while the citizen is logged in (BSNK-04). As a result, the proof fixes the parties, the key versions, the BSN authorization, and the proof form for its whole validity period. The proof has no version.
- Impact: A new source needs a new consent. A re-keyed source must
keep its old keys (AV-09).
A new proof form makes all outstanding proofs fail with
CONSENT_CONTEXT_INVALID. - Follow-up: Give the proof a version. Extend the service catalog with OIN, key version, and BSN authorization per party (REQ-82, Q-77).
- Related: F-78, ADR-0032, the proof freezes at consent.
R31: The backend revokes a revoked consent again¶
- Risk: A direct revoke of an expired or already revoked consent
returns HTTP 200, sets
REVOKEDagain, and writes a new LDV record (main.go#L282-L299). - Impact: The status history and the logbook get false entries.
- Follow-up: Refuse the revoke with
CONSENT_NOT_REVOCABLE(REQ-109, #600). - Related: F-97.
R33: A suspended consumer keeps access¶
- Risk: The request policy does not read the admission status of a direct consumer. A suspended consumer with an existing contract can still send queries under a valid consent.
- Impact: Suspension takes effect only at the revocation of the contract.
- Follow-up: REQ-110. Q-53 covers the time until the suspension takes effect.
- Related: ADR-0015.
R35: The consumer sets the consent validity¶
- Risk: The consumer sends the validity period. The default is one year, with no upper limit. The citizen cannot change it.
- Impact: A proof can live longer than the purpose needs. This makes R4 and R24 worse.
- Follow-up: Decide who sets the validity period (Q-13, Q-76).
- Related: F-11, REQ-19.
R37: BSNk recognition of the consent facility is not settled¶
- Risk: Only a recognized party can activate and transform (BSNK-01). It is open whether the consent facility can be that party, and in which role. The demo assumes route D: the backend derives and activates, and the register stores PI and PP.
- Impact: Route D works only under one condition: the backend and the register are one BSNk participant. The rotation of the reference key (Q-56) and the protection of stored PI and PP (Q-57) are open.
- Follow-up: Q-26, Q-49, and ADR-0040 (proposed).
- Related: F-75, REQ-69.
EUDI issuance¶
R36: Attestations are valid 365 days without a change feed¶
- Risk: Every attestation type gets a fixed validity of 365 days. GBO only queries sources and has no change feed.
- Impact: If the source data changes, an issuer must revoke an attestation that is valid for 24 hours or more. GBO cannot do that.
- Follow-up: Per type, choose short-lived attestations or a change feed with revocation (REQ-77).
- Related: F-82, AV-12, AV-13, ADR-0028.
Production readiness¶
R9: Demo-grade shared services¶
- Risk: The shared services are demo grade: the consent register runs in memory by default, DigiD is a mock, and the PKI is self-generated. The BSNk mock follows the BSNk interface (as JSON), but it encrypts nothing. The three demo sources share one OIN and one decryption component.
- Impact: None of these services carries production trust or availability. The demo does not demonstrate unlinkability per source.
- Follow-up: ADR-0023, ADR-0005, a replicated register store (SL-12), and a DigiD connection.
- Related: Q-54, demo mock and production BSNk.
R10: The consent register is a dependency of every DvTP decision¶
- Risk: For every request, the policy asks for the consent status online, without a cache.
- Impact: A register outage stops all consent-based traffic (fail closed).
- Follow-up: Set the availability, latency, and propagation targets (REQ-75, Q-47). Replicate the register.
- Related: F-61, ADR-0032.
R11: The demo runs one PDP for all providers¶
- Risk: The target model has a PAP and a PDP at each bronhouder (ADR-0021). The demo runs one shared PDP.
- Impact: The demo does not show policy separation between bronhouders.
- Follow-up: Run a PDP per provider in the simulation deployment.
- Related: Q-21 (answered).
R12: Policy distribution has no integrity chain and no visible fallback¶
- Risk: By default, the PDP loads policies from a bind mount. Bundle distribution through the OpenFTV Manager is opt-in. Bundles are not signed. Signing is not planned while bundles stay inside one organization (#426). The policy store is cumulative, and one broken module stops every decision.
- Impact: There is no integrity chain from author to runtime. There is no visible fallback to the last valid policy set.
- Follow-up: Guidelines RL-01 and RL-05. If a bundle crosses an organization boundary, signing becomes a requirement.
- Related: F-09, F-51, F-52, Q-21.
R13: The PDP mapper is a patch on OpenFTV¶
- Risk: The PDP is built from OpenFTV tag v0.1.0, with the FTV GraphQL mapper patched in.
- Impact: Upstream changes can break the build. The patch steps fail loudly, but the maintenance cost stays.
- Follow-up: Contribute the mapper extension point to OpenFTV upstream (ADR-0013).
- Related: REQ-42.
R14: New sources need a restart of the issuance server¶
- Risk: The issuance server reads its configuration at startup.
- Impact: Source activation needs a controlled restart.
- Follow-up: Accepted in demo v0.9.0 (ADR-0016). If the issuance server supports reload, revisit this decision.
- Related: REQ-64.
Governance and standards¶
R15: The legal ceiling of the service catalog has no technical counterpart¶
- Risk: Rule coverage replaced the catalog artifact. The legally anchored ceiling and its governance (the Bureau DvTP process) are not defined.
- Impact: The legal ceiling of what a consumer can ask for is not inspectable on its own.
- Follow-up: A legal anchoring decision (ADR-0008, ADR-0009). The data-set description is one input (REQ-121).
- Related: F-74.
R16: Rego instead of ODRL¶
- Risk: The PSA lists ODRL for S06. The design uses Rego, and Cedar inside the OpenFTV Manager.
- Impact: The comply-or-explain duty is open.
- Follow-up: Bring the deviation to the standards bodies, in line with D-13. For more information, see Policy lifecycle and Q-78.
R17: GraphQL is not a recognized FDS data service type¶
- Risk: The data access pillar rests on a deviation that no standard covers.
- Follow-up: ADR-0025.
R18: Integrator mandates have no validity and no governance¶
- Risk: Three points of the integrator route are open. A mandate has
no validity period, and the integrator is not in the proof
(Q-46). The upstream
act.subdeviates from RFC 8693. The route itself is built (opt-in) and has three parts (ADR-0034):- an FSC delegated grant
- a mandate per integrator, provider, and rule in the admission register
- a consent that binds the represented party.
- Impact: A mandate stays valid until someone removes it. It is not set who admits integrators and on which terms (AV-06).
- Follow-up: Three items are open: mandate validity, the governance of admission (Q-74), and a change log for admissions (REQ-123).
- Related: F-73 (closed), REQ-106, Q-12.
R19: LDV gaps: citizen view, activity register, ASIP¶
- Risk: LDV is built: each controller logs its own processings in its
own logbook (ADR-0026). These
gaps remain:
- the citizen view of processings per consent is not built (P-13)
- the register of processing activities is a stand-in (Q-08)
- the local
dpl.gbo.*extension is not agreed (Q-72) - the ASIP writes no LDV records
- no pointer leads from the ADL to the consent logbook (Q-25)
- no retention, access model, or tamper evidence exists for the ADL the logbooks, and the FSC transaction logs (REQ-32).
- Impact: A citizen cannot see QTSP verifications. A chain read stops at a party that does not log under LDV (F-68).
- Follow-up: The open points of ADR-0026, and the consumer obligation (AV-02).
- Related: REQ-72, F-64, SL-50.
R20: Onboarding cost for small bronhouders¶
- Risk: The cost to connect a source stays high for small organizations.
- Impact: There is an adoption risk for municipalities and small sources.
- Follow-up: ADR-0027.
Accepted technical debt¶
The design accepts the following technical debt on purpose:
- Monetary amounts in attestations are integers, because the pinned wallet stack cannot represent non-integral values (ADR-0017).
- Attestations have no nested claims (REQ-78).
- The
unsecuredsource transport exists for local development. The mount policy excludes it from deployments. The code does not exclude it. - The demo works around OpenFTV upstream quirks and documents them: the policy language flag, the missing policy-data APIs, and the broken policy DELETE (the demo retires a policy instead).
Traceability¶
- Requirements: REQ-39, REQ-45, REQ-59, REQ-60, REQ-71, REQ-74, REQ-75, REQ-76, REQ-77, REQ-81, REQ-83, REQ-86, REQ-88, REQ-106, REQ-109, REQ-110
- Findings: F-52 (open), F-54 (open), F-70 (open), F-72 (open), F-78 (open), F-79 (open), F-80 (open), F-85 (open), F-86 (open), F-92 (open), F-93 (open), F-94 (open)
- Open questions: Q-08, Q-13, Q-21 (answered), Q-29, Q-34, Q-36, Q-40, Q-49, Q-58, Q-75 (all open unless marked)
- Demo increments: SL-12 (planned), SL-25 (dropped), SL-28 (done), SL-29 (done, reversed by PR #370), SL-50 (done), SL-51 (done)