{"record":{"id":"2c8cbeb3cb06868a","repo":"ruvnet/ruflo","slug":"proofchain-requires-an-explicit-signingkey-hardc","errorCode":null,"errorMessage":"ProofChain requires an explicit signingKey — hardcoded defaults are not secure","messagePattern":"ProofChain requires an explicit signingKey — hardcoded defaults are not secure","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/guidance/src/proof.ts","lineNumber":136,"sourceCode":"\n// ============================================================================\n// ProofChain\n// ============================================================================\n\n/**\n * A tamper-evident, hash-chained sequence of ProofEnvelopes.\n *\n * Each envelope links to the previous one via `previousHash`, forming\n * a blockchain-like structure. Every envelope is HMAC-signed so any\n * modification to the chain can be detected.\n */\nexport class ProofChain {\n  private envelopes: ProofEnvelope[] = [];\n  private readonly signingKey: string;\n\n  constructor(signingKey: string) {\n    if (!signingKey) {\n      throw new Error('ProofChain requires an explicit signingKey — hardcoded defaults are not secure');\n    }\n    this.signingKey = signingKey;\n  }\n\n  /**\n   * Append a new ProofEnvelope to the chain.\n   *\n   * @param runEvent - The RunEvent to wrap\n   * @param toolCalls - Tool call records from the run\n   * @param memoryOps - Memory operations from the run\n   * @param metadata - Optional metadata overrides\n   * @returns The newly created and signed ProofEnvelope\n   */\n  append(\n    runEvent: RunEvent,\n    toolCalls: ToolCallRecord[] = [],\n    memoryOps: MemoryOperation[] = [],\n    metadata?: Partial<ProofEnvelopeMetadata>,","sourceCodeStart":118,"sourceCodeEnd":154,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/guidance/src/proof.ts#L118-L154","documentation":"ProofChain's constructor requires a non-empty signingKey because every envelope in the tamper-evident hash chain is HMAC-signed with it — a hardcoded default key would let anyone forge envelopes and defeat the entire design, so the class fails fast instead. The factory createProofChain({ signingKey }) has the same requirement. Empty string, undefined, or null all trigger this.","triggerScenarios":"new ProofChain('') or new ProofChain(undefined as any); reading the key from an unset environment variable; tests constructing the chain without injecting a secret; config loading that silently yields '' for missing values.","commonSituations":"Missing PROOF_SIGNING_KEY-style env var in CI or a new environment; .env files not loaded before construction; deployment manifests that omit the secret reference.","solutions":["Generate a strong secret, e.g. openssl rand -hex 32, and pass it explicitly to the constructor","Load the key from a secret manager or environment variable and validate it at startup before constructing the chain","Fail fast with a clear config error if the key is missing rather than defaulting or falling back","Never commit the key; rotate by re-verifying and re-exporting chains under the new key if rotation is required"],"exampleFix":"// before\nconst chain = new ProofChain(process.env.PROOF_KEY); // undefined if unset -> throws\n// after\nconst signingKey = process.env.PROOF_SIGNING_KEY;\nif (!signingKey || signingKey.length < 32) {\n  throw new Error('PROOF_SIGNING_KEY must be set to a >=32-char secret');\n}\nconst chain = new ProofChain(signingKey);","handlingStrategy":"validation","validationCode":"const signingKey = process.env.PROOF_SIGNING_KEY;\nif (!signingKey || signingKey.trim().length < 32) {\n  throw new Error('PROOF_SIGNING_KEY is missing or too weak; generate with: openssl rand -hex 32');\n}\nconst chain = new ProofChain(signingKey);","typeGuard":"function isValidSigningKey(key: unknown): key is string {\n  return typeof key === 'string' && key.trim().length > 0;\n}","tryCatchPattern":null,"preventionTips":["Generate keys with openssl rand -hex 32 and store them in a secret manager","Validate secret presence in CI/smoke checks so misconfiguration surfaces before runtime","Never fall back to a default or empty key; the constructor's fail-fast is the security control"],"tags":["guidance","proof","security","signing-key","hmac","configuration","secrets"],"backgroundTag":"missing-secret-or-api-key","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-08-22T04:17:13.399Z"}