{"record":{"id":"1adc277107cc04fa","repo":"paperclipai/paperclip","slug":"decision-signing-secrets-directory-at-directoryp-1adc27","errorCode":null,"errorMessage":"Decision signing secrets directory at ${directoryPath} must have permissions 0700","messagePattern":"Decision signing secrets directory at (.+?) must have permissions 0700","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"server/src/services/decision-signing.ts","lineNumber":61,"sourceCode":"\nfunction enforceSecretsDirectoryPermissions(directoryPath: string) {\n  let stats = lstatSync(directoryPath);\n  if (!stats.isDirectory()) {\n    throw new Error(`Decision signing secrets directory at ${directoryPath} must be a directory`);\n  }\n  assertOwnedByCurrentUser(stats, `Decision signing secrets directory at ${directoryPath}`);\n  if (process.platform === \"win32\") return;\n\n  const mode = stats.mode & 0o777;\n  if ((mode & 0o077) !== 0) {\n    chmodSync(directoryPath, 0o700);\n    stats = lstatSync(directoryPath);\n    if (!stats.isDirectory()) {\n      throw new Error(`Decision signing secrets directory at ${directoryPath} must be a directory`);\n    }\n    assertOwnedByCurrentUser(stats, `Decision signing secrets directory at ${directoryPath}`);\n    if ((stats.mode & 0o077) !== 0) {\n      throw new Error(`Decision signing secrets directory at ${directoryPath} must have permissions 0700`);\n    }\n  }\n}\n\nfunction readGeneratedSecret(keyPath: string): string {\n  enforceKeyFilePermissions(keyPath);\n  const existing = readFileSync(keyPath, \"utf8\").trim();\n  if (existing.length < MIN_SECRET_LENGTH) {\n    throw new Error(\n      `Invalid decision signing key at ${keyPath} (must be at least ${MIN_SECRET_LENGTH} characters); remove the file to regenerate it or set PAPERCLIP_DECISION_SIGNING_SECRET`,\n    );\n  }\n  return existing;\n}\n\nfunction isAlreadyExists(error: unknown) {\n  return (error as NodeJS.ErrnoException).code === \"EEXIST\";\n}","sourceCodeStart":43,"sourceCodeEnd":79,"githubUrl":"https://github.com/paperclipai/paperclip/blob/120ae5428fa29bee300bcf806491cd4d965fbb7c/server/src/services/decision-signing.ts#L43-L79","documentation":"Permission guard in enforceSecretsDirectoryPermissions: the directory still exposes group/other bits after a best-effort chmod to 0700. A looser directory would let other local users list/replace secret files inside, so startup refuses.","triggerScenarios":"Thrown at server/src/services/decision-signing.ts:61 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Set permissions to 0700 on the secrets directory: chmod 0700 <directoryPath>."],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"120ae5428fa29bee300bcf806491cd4d965fbb7c","analyzedAt":"2026-08-18T22:49:45.177Z","contentChangedAt":"2026-08-18T22:49:45.177Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}