Skip to content

Verify enclave config against onchain DON in confidentialrelay handler (PRIV-458)#22516

Merged
prashantkumar1982 merged 11 commits into
developfrom
tejaswi/priv-458-relay-config-verify
Jun 11, 2026
Merged

Verify enclave config against onchain DON in confidentialrelay handler (PRIV-458)#22516
prashantkumar1982 merged 11 commits into
developfrom
tejaswi/priv-458-relay-config-verify

Conversation

@nadahalli

@nadahalli nadahalli commented May 18, 2026

Copy link
Copy Markdown
Contributor

Verifies the enclave's reported EnclaveConfig against onchain DON state on
the relay-DON path. Relay-DON portion of PRIV-458.

After Nitro attestation validation, the confidentialrelay node handler
compares the attested EnclaveConfig (Signers and F) in each
SecretsRequestParams and CapabilityRequestParams against the local node's
WorkflowDON membership and fault tolerance. The attestation binds the
request hash but does not on its own prove the config matches the DON, so
without this check a malicious host could produce a genuinely-attested
request over a forged enclave config.

The relay DON runs on the same nodes as the workflow DON, so
localNode.WorkflowDON.Members is the comparison target. LocalNode is an
O(1) in-memory lookup populated by the registry syncer on a ~12s tick, so
the check stays off the RPC hot path; up to ~12s staleness during DON
membership rotations is acceptable.

Bumps chainlink-common to v0.11.2-0.20260528150532-b12054695b25 for the
EnclaveConfig field on confidentialrelay request params
(chainlink-common#2063, merged).

This is additive at compile time (a new struct field plus a runtime
Validate requirement), so it does not break chainlink compilation. It is
a breaking wire change at runtime: the matching enclave side (sends and
hash-binds EnclaveConfig) must deploy alongside relays. That is acceptable
because confidential workflows is not released yet. The enclave side
(confidential-compute#330) is reverted for now (confidential-compute#351)
and re-merges once this lands.

Tests: match-accepts, F mismatch, signers-count mismatch, signer-value
mismatch, order-independent comparison, and the secrets-get path. Node
handler and gateway aggregator test fixtures set EnclaveConfig now that
confidentialrelay.Validate requires it.

Jira: https://smartcontract-it.atlassian.net/browse/PRIV-458

…r (PRIV-458)

The handler now compares the attested EnclaveConfig in every incoming
SecretsRequestParams and CapabilityRequestParams against the local
node's WorkflowDON membership and fault tolerance, after Nitro
attestation validation succeeds. Closes Sigma Prime CL112-01 on the
relay-DON path.

The relay DON runs on the same nodes as the workflow DON, so
localNode.WorkflowDON.Members is the right comparison target. LocalNode
is an O(1) in-memory map lookup populated by the registry syncer on a
~12s tick, so the check stays off the RPC hot path. Up to ~12s
staleness applies during DON membership rotations and is acceptable
given how rare those events are.

Tests cover match-accepts, F mismatch, signers-count mismatch, signer
value mismatch, order-independent comparison, and the secrets-get
path. Existing tests updated to fill EnclaveConfig in fixtures with
a matching WorkflowDON.Members in the mock registry.

Bumps chainlink-common to v0.11.2-0.20260518112011-40a8e4cedaa8 to pick
up the EnclaveConfig field on confidentialrelay request params
(smartcontractkit/chainlink-common#2063).

Companion PRs:
- smartcontractkit/confidential-compute#329 (pool.go-side check).
- smartcontractkit/chainlink-common#2063 (field on params).
- smartcontractkit/confidential-compute#330 (enclave fills field).
Copilot AI review requested due to automatic review settings May 18, 2026 12:42
@nadahalli nadahalli requested review from a team as code owners May 18, 2026 12:42
@github-actions

Copy link
Copy Markdown
Contributor

👋 nadahalli, thanks for creating this pull request!

To help reviewers, please consider creating future PRs as drafts first. This allows you to self-review and make any final changes before notifying the team.

Once you're ready, you can mark it as "Ready for review" to request feedback. Thanks!

@github-actions

Copy link
Copy Markdown
Contributor

I see you updated files related to core. Please run make gocs in the root directory to add a changeset as well as in the text include at least one of the following tags:

  • #added For any new functionality added.
  • #breaking_change For any functionality that requires manual action for the node to boot.
  • #bugfix For bug fixes.
  • #changed For any change to the existing functionality.
  • #db_update For any feature that introduces updates to database schema.
  • #deprecation_notice For any upcoming deprecation functionality.
  • #internal For changesets that need to be excluded from the final changelog.
  • #nops For any feature that is NOP facing and needs to be in the official Release Notes for the release.
  • #removed For any functionality/config that is removed.
  • #updated For any functionality that is updated.
  • #wip For any change that is not ready yet and external communication about it should be held off till it is feature complete.

@github-actions

github-actions Bot commented May 18, 2026

Copy link
Copy Markdown
Contributor

✅ No conflicts with other open PRs targeting develop

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Risk Rating: MEDIUM — changes add new validation in the confidential relay request handling path (security hardening) and bump a shared dependency (chainlink-common).

This PR hardens the confidential relay handler by verifying that the attested EnclaveConfig in incoming requests matches the node’s locally-synced onchain WorkflowDON membership and fault tolerance, addressing Sigma Prime CL112-01 (PRIV-458).

Changes:

  • Add relay-side EnclaveConfig vs WorkflowDON verification for both SecretsGet and CapabilityExec flows.
  • Bump github.com/smartcontractkit/chainlink-common to pick up the new EnclaveConfig field on request params.
  • Update handler tests/fixtures and add dedicated tests for EnclaveConfig verification (match, mismatches, order-independence, secrets-get coverage).

Targeted areas requiring scrupulous human review:

  • verifyEnclaveConfigMatchesDON: confirm the chosen onchain reference (localNode.WorkflowDON) is correct for all deployments/rotations and that the comparison logic matches the intended security model (especially around signer identity representation).
  • Request-path behavior during DON membership rotations / registry staleness: ensure the new rejection behavior is operationally acceptable for the gateway/enclave interaction.

Reviewed changes

Copilot reviewed 3 out of 4 changed files in this pull request and generated 2 comments.

File Description
go.mod Bumps chainlink-common to a newer pseudo-version to include EnclaveConfig in request params.
go.sum Updates module sums for the chainlink-common version bump.
core/capabilities/confidentialrelay/handler.go Adds EnclaveConfig verification against locally synced WorkflowDON members/F; hooks it into SecretsGet and CapabilityExec after attestation hash verification.
core/capabilities/confidentialrelay/handler_test.go Updates fixtures to include EnclaveConfig and adds tests covering accept/reject cases and order-independence.
Comments suppressed due to low confidence (1)

core/capabilities/confidentialrelay/handler_test.go:475

  • This struct literal has formatting/indentation issues (EnclaveConfig and the closing brace are misaligned). Please run gofmt (or adjust indentation) to keep formatting consistent and avoid gofmt-check failures.
				params := confidentialrelaytypes.CapabilityRequestParams{
					WorkflowID:   "wf-1",
					Owner:        testOwner,
					ExecutionID:  "32c631d295ef5e32deb99a10ee6804bc4af13855687559d7ff6552ac6dbb2ce1",
					ReferenceID:  "17",
					CapabilityID: "fail-cap@1.0.0",
					Payload:      base64.StdEncoding.EncodeToString(mustMarshalProto(t, &sdkpb.CapabilityRequest{Id: "fail-cap@1.0.0", Method: "Execute"})),
				EnclaveConfig: testEnclaveConfig(),
				}

// the Nitro attestation binds the request hash, but a malicious host
// can produce a genuinely-attested request over a forged enclave config
// unless we compare the config value against an onchain reference.
if err := h.verifyEnclaveConfigMatchesDON(ctx, params.EnclaveConfig); err != nil {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 3c903cf

Comment on lines 333 to 341
params := confidentialrelaytypes.CapabilityRequestParams{
WorkflowID: "wf-1",
Owner: testOwner,
ExecutionID: "32c631d295ef5e32deb99a10ee6804bc4af13855687559d7ff6552ac6dbb2ce1",
ReferenceID: "17",
CapabilityID: "my-cap@1.0.0",
Payload: makeCapabilityPayload(t, map[string]any{"key": "val"}),
EnclaveConfig: testEnclaveConfig(),
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 3c903cf

@trunk-io

trunk-io Bot commented May 18, 2026

Copy link
Copy Markdown

Static BadgeStatic BadgeStatic BadgeStatic Badge

View Full Report ↗︎Docs

nadahalli added 4 commits May 21, 2026 12:13
…elay-config-verify

# Conflicts:
#	go.mod
#	go.sum
…elay-config-verify

# Conflicts:
#	core/capabilities/confidentialrelay/handler_test.go
#	go.mod
#	go.sum
GolangCI flagged three issues introduced by this PR's test fixtures:
- gosec G115: uint32->uint8 narrowing in WorkflowDON.F assignment.
  Replaced with an untyped testEnclaveF const used by both
  EnclaveConfig.F (uint32) and WorkflowDON.F (uint8), so no conversion.
- gocritic assignOp x2: badCfg.F = badCfg.F + 5 and
  params.EnclaveConfig.F = ... + 5 rewritten with +=.
Root go.mod was bumped to chainlink-common b1205469 (post-#2063, adds
EnclaveConfig). The deployment, integration-tests, integration-tests/load,
system-tests/lib, system-tests/tests, and core/scripts modules replace
chainlink => ../ and so build against the root's confidentialrelay code,
but still pinned the pre-#2063 common (883689d). That skew broke
"make generate" (deployment error: exit status 1) because EnclaveConfig
was undefined when building root packages from those modules.

Bump all six to b1205469 and tidy.
@nadahalli nadahalli requested a review from a team as a code owner June 1, 2026 10:00
@github-actions

github-actions Bot commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

CORA - Analysis Skipped

Reason: The number of code owners (1) is less than the minimum required (5) and/or the number of CODEOWNERS entries with changed files (2) is less than the minimum required (2).

vreff
vreff previously approved these changes Jun 1, 2026
The chainlink-common bump in this PR makes confidentialrelay.Validate
require a non-empty EnclaveConfig (Signers, F, MasterPublicKey). The
gateway aggregator test fixtures (validCapParams/validSecretsParams)
didn't set it, so Hash() errored, no signed responses formed, and
TestConfidentialRelayHandler_QuorumWithRealAggregator blocked on quorum
until the 15m test timeout.

Add a valid EnclaveConfig to both fixtures. Gateway production code is
unaffected (nodes and gateway share one build, so hashing stays
consistent); only the stale test fixtures needed the field.
nadahalli added 3 commits June 1, 2026 23:29
- verifyEnclaveConfigMatchesDON now takes a localNode snapshot instead of
  fetching it itself. handleSecretsGet fetched LocalNode twice (once for
  the config check, once for request metadata); now it fetches once and
  passes the snapshot, avoiding the redundant lookup and any inconsistency
  if registry state changes between calls. handleCapabilityExecute fetches
  once and passes it too.
- gofmt the handler test: the EnclaveConfig struct literals added earlier
  were mis-indented.
- Drop the audit tag from the doc comment, matching the chainlink-common
  cleanup (keep PRIV-458).
The LocalNode-once refactor introduced `localNode, err :=` then kept
`if err := verifyEnclaveConfigMatchesDON(...)`, shadowing err (govet).
Use `=` so it assigns the existing err.
chainlink-common #2111 made EnclaveConfig optional (*EnclaveConfig). Bump
common to 208ae6dd across the root and the dependent submodules that
replace chainlink => ../, and adapt the relay handler:

- verifyEnclaveConfigMatchesDON takes *EnclaveConfig and skips the check
  when nil (sender on an older protocol that omits it), verifying only
  when present.
- Node-handler and gateway-aggregator test fixtures use the pointer form;
  add a node-handler subtest covering nil-config acceptance.
nadahalli added 2 commits June 2, 2026 13:35
…elay-config-verify

# Conflicts:
#	core/scripts/go.mod
#	core/scripts/go.sum
#	deployment/go.mod
#	deployment/go.sum
#	go.mod
#	go.sum
#	integration-tests/go.mod
#	integration-tests/go.sum
#	integration-tests/load/go.mod
#	integration-tests/load/go.sum
#	system-tests/lib/go.mod
#	system-tests/lib/go.sum
#	system-tests/tests/go.mod
#	system-tests/tests/go.sum
@cl-sonarqube-production

Copy link
Copy Markdown

pull Bot pushed a commit to bit-cook/chainlink that referenced this pull request Jun 10, 2026
…ntractkit#22762)

* Add privacy as CODEOWNER for core/capabilities/confidentialrelay

confidentialrelay holds the relay-DON authorization logic (PRIV-433, PRIV-458),
which is privacy-owned security code. It currently inherits /core/capabilities/
(keystone + capabilities-team) with no privacy entry. Add privacy alongside the
existing owners so privacy can review and approve changes there, e.g. smartcontractkit#22516
and smartcontractkit#22703.

* Make confidentialrelay CODEOWNERS privacy-only (capabilities + gateway)

Both confidentialrelay paths are purely privacy's confidential-relay code:
the capability handler (core/capabilities/confidentialrelay) and the gateway
handler (core/services/gateway/handlers/confidentialrelay). Assign both to
@smartcontractkit/privacy outright, mirroring confidentialhttp in chainlink-common.

* Add system-tests confidentialrelay CODEOWNERS for privacy
@prashantkumar1982 prashantkumar1982 added this pull request to the merge queue Jun 11, 2026
@github-merge-queue github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Jun 11, 2026
@prashantkumar1982 prashantkumar1982 added this pull request to the merge queue Jun 11, 2026
Merged via the queue into develop with commit 4360ac6 Jun 11, 2026
219 checks passed
@prashantkumar1982 prashantkumar1982 deleted the tejaswi/priv-458-relay-config-verify branch June 11, 2026 16:50
nadahalli added a commit that referenced this pull request Jun 12, 2026
Resolve the aggregator_test.go modify/delete conflict by keeping #22807's
deletion: #22516 (now on develop) added validEnclaveConfig to that file,
but the dumb-bundler replaces the aggregator entirely and that helper is
unused elsewhere. Relay packages build and tests pass with #22516's
config-verify changes merged in.
nadahalli added a commit that referenced this pull request Jun 12, 2026
#22516 (verifyEnclaveConfigMatchesDON) landed on develop and overlaps the PRIV-433
verifier in handler_test.go. Unify the fixtures so the Workflow DON members are real
ed25519 public keys that double as EnclaveConfig.Signers: this satisfies both
verifyEnclaveConfigMatchesDON (byte-compares Signers to Members) and
verifyWorkflowAuthorization (verifies F+1 signatures against Members). handleSecretsGet
fetches LocalNode once for both checks. Sign 2*F+1 (=3) compute requests to meet quorum.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants