{"record":{"id":"57130d7404c63d8a","repo":"facebook/react","slug":"to-taint-a-value-a-lifetime-must-be-defined-by-pa","errorCode":null,"errorMessage":"To taint a value, a lifetime must be defined by passing an object that holds the value.","messagePattern":"To taint a value, a lifetime must be defined by passing an object that holds the value\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/react/src/ReactTaint.js","lineNumber":70,"sourceCode":"    ? new FinalizationRegistry(cleanup)\n    : null;\n\nexport function taintUniqueValue(\n  message: ?string,\n  lifetime: Reference,\n  value: string | bigint | $ArrayBufferView,\n): void {\n  if (!enableTaint) {\n    throw new Error('Not implemented.');\n  }\n  // eslint-disable-next-line react-internal/safe-string-coercion\n  message = '' + (message || defaultMessage);\n  if (\n    // $FlowFixMe[invalid-compare]\n    lifetime === null ||\n    (typeof lifetime !== 'object' && typeof lifetime !== 'function')\n  ) {\n    throw new Error(\n      'To taint a value, a lifetime must be defined by passing an object that holds ' +\n        'the value.',\n    );\n  }\n  let entryValue: string | bigint;\n  if (typeof value === 'string' || typeof value === 'bigint') {\n    // Use as is.\n    entryValue = value;\n  } else if (\n    value instanceof TypedArrayConstructor ||\n    value instanceof DataView\n  ) {\n    // For now, we just convert binary data to a string so that we can just use the native\n    // hashing in the Map implementation. It doesn't really matter what form the string\n    // take as long as it's the same when we look it up.\n    // We're not too worried about collisions since this should be a high entropy value.\n    TaintRegistryByteLengths.add(value.byteLength);\n    entryValue = binaryToComparableString(value);","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/facebook/react/blob/eafeac097ba51e1eab809c07102126bd5f8e5425/packages/react/src/ReactTaint.js#L52-L88","documentation":"React's taintUniqueValue requires a lifetime object — an object or function that holds the secret and stays alive exactly as long as the secret does — so React can forget the taint via weak semantics when the holder is collected. Passing null or a primitive (string, number, boolean) as the lifetime throws because React would either never clean up or track the wrong scope.","triggerScenarios":"taintUniqueValue(message, 'user', secret) or taintUniqueValue(message, null, secret) — passing a primitive or null where the API expects the object that contains the value (e.g. the request or user session object).","commonSituations":"Calling the server-security taint APIs for the first time and misunderstanding the second parameter as a label/scope string; refactoring code that previously passed a symbol or string as the lifetime.","solutions":["Pass the object that holds the secret (e.g. the per-request cache/session object) as the lifetime: taintUniqueValue(message, requestContext, token)","If no natural holder exists, create one (const lifetime = {token}) and keep it alive as long as the secret","Ensure the lifetime is neither null nor a primitive; functions are also accepted as holders"],"exampleFix":"// before\ntaintUniqueValue(msg, 'session-token', token); // string lifetime -> throws\n\n// after\nconst session = await loadSession();\ntaintUniqueValue(msg, session, session.token); // object lifetime","handlingStrategy":"validation","validationCode":"// Validate the lifetime argument before tainting\nfunction isLifetime(v: unknown): v is object | Function {\n  return v !== null && (typeof v === 'object' || typeof v === 'function');\n}\nif (isLifetime(lifetime)) {\n  taintUniqueValue(message, lifetime, secret);\n} else {\n  throw new TypeError('lifetime must be the object holding the secret');\n}","typeGuard":"const isTaintLifetime = (v: unknown): v is object | Function =>\n  v != null && (typeof v === 'object' || typeof v === 'function');","tryCatchPattern":null,"preventionTips":["Always pass the request/session object that owns the secret as the lifetime","Wrap taint calls in a small helper that validates (lifetime, value) types once and fails with a clear message"],"tags":["security","taint-apis","taintuniquevalue","lifetime","server-components"],"backgroundTag":"taint-value-lifetime","analyzedSha":"eafeac097ba51e1eab809c07102126bd5f8e5425","analyzedAt":"2026-08-21T22:01:08.818Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}