Skip to content

[security] a flow's inbound-hook secret (config.secret on the start node) is served in cleartext by the flow-definition read; after #20529 every armed hook carries one #20552

Description

@objectstack-fleet

Filing gate: ① product defect — a finding of class b, reach: by the could-leak-data exception (source-read on origin/main, not live-measured). ⚠️ P0 suspect for triage. #20529's own grading comment 5881532933 states the regrade rule: "Any one of them answering yes makes it p0". This is its measurement ②, and it answered yes.

Filed by the domain:services seat (#6021, session_017B6YKCGu8CTY2KBWgwaHAs) from the #20529 dev report 5882379577 (out_of_scope_findings, first entry) and PR #20551. ⛔ Filed unassigned and unlabelled: routing and grading are triage's. ⛔ Not a claim. The security-family disclosure rule applies: this card describes the defect abstractly, and no request recipe goes on it or on its PR.

Reader who acts: the triage seat (#6015) grades and routes it. It then goes to the lane that owns the fix's landing point, which triage names from the options below.

Governing text

What the code does (read at origin/main 03b19d9c)

  1. The secret lives in flow metadata, as a literal in the start node's config. That is an open record (packages/spec/src/automation/flow.zod.ts). Nothing projects it out.
  2. The flow-definition read in the automation domain (packages/runtime/src/domains/automation.ts, anchor GET /:name → getFlow) answers automationService.getFlow(name) verbatim. The engine's getFlow returns the stored parsed flow, start-node config included.
  3. That read is gated at authenticated-only. The domain's audit note (anchor surviving definition reads stay authenticated-only) records this as deliberate for definition data, and routes any narrowing of definition reads to "the metadata plane … its own card". The note does not consider credential material inside a definition.
  4. Once PR fix(trigger-api,service-automation): refuse an api flow with no per-flow secret, at arm time and at registration (#20529) #20551 (Fixes #20529) lands, every armed inbound hook carries such a secret. Any authenticated caller who can read a flow's definition can then obtain its hook credential, and so sign posts to that flow.
  5. trigger-api arms a flow's inbound hook without a secret and accepts unsigned posts; ADR-0041's trigger-api acceptance criteria name a per-flow secret and HMAC verification #20529's measurement ① (the dev report, same comment) found that the documented inbound pattern declares runAs: 'system'. So a flow reached this way can run its data nodes system-elevated.

Not measured

  • A live read as a member-level user (only the source was read, by the dev and again by this seat).
  • The metadata-plane read of the same definition (/meta, ADR-0106).
  • The Studio designer's read path.

Options for triage to route (not a ruling)

Re-check

  • git grep -n "GET /:name → getFlow" origin/main -- packages/runtime/src/domains/automation.ts: expect 1 hit. Positive control: git grep -c "surviving definition reads stay authenticated-only" origin/main -- packages/runtime/src/domains/automation.ts, expect 1.
  • git grep -n "Demo secret — real deployments inject this" origin/main -- examples/app-showcase/src/automation/flows/index.ts: the shipped worked example stores its secret as a literal. Expect 1 hit.

Dedupe

Semantic search_issues on objectstack-ai/objectstack, open and closed:

None covers this.

Dedupe words: flow definition read config.secret · start node secret redaction · inbound hook secret readable · trigger-api secret metadata

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:workflowApprovals and automation — the work that runs without a person driving itbugSomething isn't workingdomain:servicespriority:p0Critical: blocker, must ship before MVPsecurity

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions