{"record":{"id":"62b80b8268af7e3c","repo":"ComposioHQ/composio","slug":"user-must-not-contain-nul-bytes","errorCode":null,"errorMessage":"user must not contain NUL bytes","messagePattern":"user must not contain NUL bytes","errorType":"validation","errorClass":"KeyringError","httpStatus":null,"severity":"error","filePath":"ts/packages/cli-keyring/src/stores/macos-security-subprocess.ts","lineNumber":74,"sourceCode":"  }\n  throw new KeyringError({\n    kind: 'NotSupportedByStore',\n    operation: `macos keychain domain \"${domain}\"`,\n  });\n}\n\nfunction validateSpecifier(service: string, user: string): void {\n  // Empty service or user would become wildcards in Keychain Services\n  // — keyring-rs throws `Error::Invalid` here and we match that.\n  if (service.includes('\\0')) {\n    throw new KeyringError({\n      kind: 'Invalid',\n      param: 'service',\n      reason: 'service must not contain NUL bytes',\n    });\n  }\n  if (user.includes('\\0')) {\n    throw new KeyringError({\n      kind: 'Invalid',\n      param: 'user',\n      reason: 'user must not contain NUL bytes',\n    });\n  }\n}\n\nfunction classifyExitCode(result: SpawnResult, operation: string): KeyringError {\n  const code = result.code;\n  const stderr = bytesToUtf8(result.stderr).trim();\n  if (code === EXIT_ITEM_NOT_FOUND) {\n    return new KeyringError({ kind: 'NoEntry' });\n  }\n  if (code !== null && EXIT_NO_STORAGE_ACCESS.has(code)) {\n    return new KeyringError({\n      kind: 'NoStorageAccess',\n      cause: new Error(stderr || `security ${operation} failed with exit ${code}`),\n    });","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/ComposioHQ/composio/blob/64b1b85502b1beeb2379e6c9e8bf1104504fa637/ts/packages/cli-keyring/src/stores/macos-security-subprocess.ts#L56-L92","documentation":"The macOS keyring store validates its inputs before shelling out to the `security` command. Because arguments are passed to a subprocess, embedded NUL bytes (`\\0`) would truncate or corrupt the argv string, so the store rejects any `user` value containing NUL bytes with an Invalid KeyringError.","triggerScenarios":"Calling setSecret, getSecret, or deleteCredential on the macOS-security store with a user string that contains a '\\0' character (e.g. a Buffer read past its data, or malformed serialized credentials passed as the user parameter).","commonSituations":"Passing binary data or an unsafely-decoded buffer as the user/account name; truncated strings from IPC or JSON with literal \\u0000 escapes; fuzzed input reaching the keyring layer.","solutions":["Inspect and sanitize the user string before calling the keyring API: strip or reject '\\0'.","Trace where the user value originates (env var, config file, IPC payload) and fix the encoding/truncation bug upstream.","If NUL is legitimate in your data, it cannot be a keyring user name — hash or encode it first."],"exampleFix":"// before\nawait store.setSecret(service, userWithNul, secret); // throws Invalid\n\n// after\nif (user.includes('\\0')) throw new Error('invalid user');\nawait store.setSecret(service, user, secret);","handlingStrategy":"validation","validationCode":"function isValidKeyringUser(user: string): boolean {\n  return user.length > 0 && !user.includes('\\0');\n}","typeGuard":null,"tryCatchPattern":"try {\n  await store.setSecret(service, user, secret);\n} catch (e) {\n  if (e instanceof KeyringError && e.kind === 'Invalid' && e.param === 'user') {\n    // sanitize and retry with a cleaned user value\n  }\n}","preventionTips":["Validate user/service strings at the boundary where they enter your app, before reaching the keyring.","Avoid passing Buffers or raw binary as keyring identifiers; stringify and sanitize first."],"tags":["macos","keyring","input-validation","nul-byte"],"backgroundTag":"invalid-argument-validation","analyzedSha":"64b1b85502b1beeb2379e6c9e8bf1104504fa637","analyzedAt":"2026-08-28T15:39:33.623Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}