Skip to content

Security: workflow observer output exposes auto-minted workspace keys #25

Description

@willwashburn

Summary

@relayflows/core prints a live workspace key in a clickable observer URL during workflow execution:

Observer: https://agentrelay.com/observer?key=${this.relayApiKey}

The exposed cohort is narrower than Agent Relay startup. Agent Relay's dist/cli/lib implementation of node up and node status has zero @relayflows imports. The reachable consumers are the workflow commands (local-workflow.js and cloud-worker.js), and the line fires only when all three conditions hold:

  1. the workflow has non-deterministic steps and therefore requires a broker;
  2. Relaycast is not disabled; and
  3. no RELAY_API_KEY is supplied, so the workflow runner auto-mints a key for that run.

In the published v1.0.5 source, the guard is packages/core/src/runner.ts:3783 and the print is :3785; these compile to core/dist/runner.js:2855 and :2857 in the Agent Relay 11.3.1 global install. Agent Relay reaches this package through @relayflows/cli.

The version base varies by installation: the global Agent Relay tree resolves @relayflows/core@1.0.5, while scout's tree resolves 1.0.4. The caret dependency resolves separately for each install, so a diff against the wrong installed base can look clean while another supported tree still leaks.

Credit: cpo found the leak while checking the complete installed Agent Relay tree, including node_modules, after the Agent Relay CLI's own output paths had been fixed. head-of-ecosystem independently verified it, re-scoped the scrubber mechanism, and tested the failing key shapes. cmo verified the workflow-only reachability boundary and the differing installed version bases.

Redaction gap

Relayflows already treats secret-bearing output as something that must be sanitized. The installed dist/channel-messenger.js:24 documents its table as "Common secret patterns to redact from channel output"; in the published v1.0.5 source, SECRET_PATTERNS is at packages/core/src/channel-messenger.ts:48, the ineffective generic key expression is at :50, and scrubSecrets is at :92. The installed build places the table at dist/channel-messenger.js:25 and scrubSecrets at :58.

The defect is that channel output is scrubbed while the runner's observer line is not, and the shared pattern itself misses Relay's live formats. This is an inconsistent application of an existing package security boundary, not a request to invent a new redaction design.

The existing expression is:

(?:sk|pk|rk|ak)[-_][a-zA-Z0-9]{20,}

It does not match live credential formats because live_ introduces an underscore at character five after rk_/at_/nt_/ot_. Synthetic rk_live_..., at_live_..., nt_live_..., and ot_live_... values all pass through unchanged. Merely routing the observer line through the existing scrubber therefore does not close the leak.

The leak was independently found in all twelve locally checked installs across five published core versions, from 0.1.0 through 1.0.5. There is no safe published version to select. Exact pinning is a separate install-reproducibility improvement and is not mitigation for this issue.

Required fix

This is one two-part fix. Either half alone is ineffective: changing the pattern without using it leaves the print site exposed, while using the old pattern still passes every live key through.

  • Extend the shared secret patterns to cover Relay live credential prefixes, including rk_live_, at_live_, nt_live_, ot_live_, cld_at_, rth_at_, br_, and ocl_node_enr_.
  • Pass the guarded workflow-runner observer output through that redaction boundary so no full workspace key or credential-bearing clickable URL is emitted.
  • Add regression tests for every supported live prefix and for the workflow observer output path.
  • Verify the built package and an installed consumer tree, dependencies included. A clean npm pack tarball is insufficient because tarballs omit node_modules.
  • Treat network/API failures as failures to measure, never as a zero-hit result.

Advisory boundary

Agent Relay 11.3.1 closes the credential exposure in the node up and node status command family. It does not provide a general installed-tree all-clear: affected workflow execution can still reach the vulnerable transitive @relayflows/core path until this fix is published and consumers resolve it. Downstream advisories must keep the 11.3.1 statement scoped to those node-lifecycle commands.

Release note

Fix and publish are separate operations. No package release should be cut from this issue or its PR without the release owner's approval.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions