Problem
Secret references in the app-config blob currently become direct lookups in the default Trusted Server secret store. A principal that can write the config blob can choose any non-empty secret key name, recompute the blob checksum, and make Trusted Server resolve that secret at runtime.
This breaks the intended boundary between config-store write access and secret-store read access. In particular, a config writer can assign an unrelated secret key to ec.partners[*].ts_pull_token, configure a controlled pull-sync URL and allowlist, and cause the resolved value to be sent as an outbound Bearer token.
BlobEnvelope::verify() provides integrity checking, but is not an authorization boundary: a config-store writer can create a valid checksum for modified data.
Goal
Prevent a config-store writer from selecting or exporting a secret outside the secret scope explicitly assigned to the relevant configuration field, without adding a separate signature/authentication layer to config envelopes.
Proposed direction
- Do not use an arbitrary string from the config blob as a physical secret-store key.
- Define field-owned secret namespaces/slots, selected by schema metadata and resolved by the runtime/platform adapter. For example, proxy authentication, EC inbound tokens, EC pull-sync tokens, and handler passwords must be separate scopes.
- Keep each field's resolver confined to its own scope; a value intended for
publisher.proxy_secret must never be resolvable as a pull-sync token, and vice versa.
- Use platform-native secret-store capabilities and deployment provisioning for the mapping. This follow-up should not require signing config envelopes.
- Treat credentials sent to an external service (currently
ts_pull_token) specially: its allowed destination and credential identity must not both be freely retargetable by a config-store writer. Namespacing prevents cross-scope theft, but alone does not prevent export of a pull-sync credential if the mutable blob can also redirect its endpoint.
Acceptance criteria
Relevant code
crates/trusted-server-core/src/config_payload.rs
crates/trusted-server-core/src/secret_resolution.rs
crates/trusted-server-core/src/ec/pull_sync.rs
crates/trusted-server-core/src/config.rs
Problem
Secret references in the app-config blob currently become direct lookups in the default Trusted Server secret store. A principal that can write the config blob can choose any non-empty secret key name, recompute the blob checksum, and make Trusted Server resolve that secret at runtime.
This breaks the intended boundary between config-store write access and secret-store read access. In particular, a config writer can assign an unrelated secret key to
ec.partners[*].ts_pull_token, configure a controlled pull-sync URL and allowlist, and cause the resolved value to be sent as an outbound Bearer token.BlobEnvelope::verify()provides integrity checking, but is not an authorization boundary: a config-store writer can create a valid checksum for modified data.Goal
Prevent a config-store writer from selecting or exporting a secret outside the secret scope explicitly assigned to the relevant configuration field, without adding a separate signature/authentication layer to config envelopes.
Proposed direction
publisher.proxy_secretmust never be resolvable as a pull-sync token, and vice versa.ts_pull_token) specially: its allowed destination and credential identity must not both be freely retargetable by a config-store writer. Namespacing prevents cross-scope theft, but alone does not prevent export of a pull-sync credential if the mutable blob can also redirect its endpoint.Acceptance criteria
publisher.proxy_secret, EC inboundapi_token, handler passwords, or another unrelated secret to be emitted in a pull-sync Authorization header.Relevant code
crates/trusted-server-core/src/config_payload.rscrates/trusted-server-core/src/secret_resolution.rscrates/trusted-server-core/src/ec/pull_sync.rscrates/trusted-server-core/src/config.rs