{"record":{"id":"a10897094c80cb6f","repo":"ruvnet/ruflo","slug":"worker-worker-id-capability-envelope-cannot-exp","errorCode":null,"errorMessage":"worker ${worker.id} capability envelope cannot expand","messagePattern":"worker (.+?) capability envelope cannot expand","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/codex/src/dual-mode/orchestrator.ts","lineNumber":585,"sourceCode":"      !patterns?.length\n      || patterns.some((pattern) => pattern === '*' || pattern === value\n        || (pattern.endsWith('*') && value.startsWith(pattern.slice(0, -1))))\n    );\n    const subset = (values: string[] | undefined, patterns: string[] | undefined): boolean => (\n      !patterns?.length || (!!values?.length && values.every((value) => matches(patterns, value)))\n    );\n    const valid = subset(child.actions, parent.actions)\n      && subset(child.resources, parent.resources)\n      && subset(child.tools, parent.tools)\n      && (parent.maxConcurrency === undefined\n        || (child.maxConcurrency !== undefined && child.maxConcurrency <= parent.maxConcurrency))\n      && (parent.expiresAt === undefined\n        || (child.expiresAt !== undefined && child.expiresAt <= parent.expiresAt))\n      && (parent.delegationDepth === undefined\n        || (child.delegationDepth !== undefined && child.delegationDepth <= parent.delegationDepth))\n      && !(child.network === true && parent.network !== true)\n      && !(child.destructive === true && parent.destructive !== true);\n    if (!valid) throw new Error(`worker ${worker.id} capability envelope cannot expand`);\n    return child;\n  }\n\n  private workerEnvironment(worker: WorkerConfig): NodeJS.ProcessEnv {\n    const env: NodeJS.ProcessEnv = {};\n    const sensitive = /(?:^|_)(?:API_?KEY|KEY|SECRET|TOKEN|PASSWORD|CREDENTIALS?)$/i;\n    for (const [name, value] of Object.entries(process.env)) {\n      if (sensitive.test(name)\n        || name.startsWith('CLAUDE_FLOW_POLICY_')\n        || name === 'CLAUDE_FLOW_PRINCIPAL_ID') continue;\n      env[name] = value;\n    }\n    env.FORCE_COLOR = '0';\n    env.CLAUDE_FLOW_DB_PATH = this.config.memoryDbPath;\n    env.CLAUDE_FLOW_PRINCIPAL_ID = `agent:${worker.id}`;\n    env.CLAUDE_FLOW_CAPABILITY_ENVELOPE = JSON.stringify(\n      this.resolveWorkerEnvelope(worker),\n    );","sourceCodeStart":567,"sourceCodeEnd":603,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/codex/src/dual-mode/orchestrator.ts#L567-L603","documentation":"resolveWorkerEnvelope merges a worker's requested capabilityEnvelope over a fixed synthetic parent envelope (actions/resources/tools '*', maxConcurrency 1, network false, destructive false, delegationDepth 0, expiresAt now + config.timeout). Delegation may only reduce scope: every child axis must be a subset of the parent's, and any requested value that expands it throws for that worker id. Because the parent pins delegationDepth to 0 and network/destructive to false, requesting delegationDepth > 0, network: true, or destructive: true always fails; maxConcurrency > 1 and expiresAt beyond the orchestrator timeout also fail.","triggerScenarios":"worker.capabilityEnvelope set with network: true or destructive: true; delegationDepth greater than 0; maxConcurrency greater than 1; expiresAt later than Date.now() + config.timeout; or actions/resources/tools patterns not covered by the parent's wildcard patterns.","commonSituations":"Porting worker envelopes from a system where the parent process held broad grants (here the parent is a synthetic default, not your process); trying to give spawned workers network access by default; setting a long expiresAt that overruns the orchestrator timeout.","solutions":["Remove escalations from the worker envelope: network and destructive must remain false and delegationDepth 0","Set maxConcurrency to 1 and expiresAt to a value at or before the orchestrator's timeout","Keep actions/resources/tools at or below the defaults (wildcards or narrower explicit values)","If a worker genuinely needs more capability, raise it at the orchestrator level (e.g. a longer timeout) — never by widening the child envelope"],"exampleFix":"// before\nworker.capabilityEnvelope = {\n  network: true,          // parent has network: false\n  destructive: true,      // parent has destructive: false\n  maxConcurrency: 4,      // parent pins 1\n  delegationDepth: 1,     // parent pins 0\n};\n\n// after\nworker.capabilityEnvelope = {\n  network: false,\n  destructive: false,\n  maxConcurrency: 1,\n  delegationDepth: 0,\n  expiresAt: Date.now() + 60_000, // at or before orchestrator timeout\n};","handlingStrategy":"validation","validationCode":"function isSubsetEnvelope(child: WorkerCapabilityEnvelope, parent: WorkerCapabilityEnvelope): boolean {\n  const covered = (patterns: string[], value: string) =>\n    patterns.some((p) => p === '*' || p === value || (p.endsWith('*') && value.startsWith(p.slice(0, -1))));\n  return (\n    child.actions.every((a) => covered(parent.actions, a))\n    && child.resources.every((r) => covered(parent.resources, r))\n    && child.tools.every((t) => covered(parent.tools, t))\n    && child.maxConcurrency <= parent.maxConcurrency\n    && child.expiresAt <= parent.expiresAt\n    && child.delegationDepth <= parent.delegationDepth\n    && !(child.network && !parent.network)\n    && !(child.destructive && !parent.destructive)\n  );\n}\n// parent defaults: maxConcurrency 1, delegationDepth 0, network/destructive false, expiresAt = now + timeout","typeGuard":null,"tryCatchPattern":"Catch around worker registration; on 'capability envelope cannot expand', log the worker id and prune the offending fields (network/destructive/delegationDepth/maxConcurrency/expiresAt) rather than retrying — the check is deterministic.","preventionTips":["Never hand-write worker envelopes wider than defaults; start empty and add only reductions","Compute expiresAt relative to the orchestrator timeout, never a fixed wall-clock constant","Encode the subset rule in a shared validator used by every component that creates worker envelopes"],"tags":["capability","security","privilege-escalation","orchestration","envelope"],"backgroundTag":"privilege-escalation-blocked","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","contentChangedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}