zod icon indicating copy to clipboard operation
zod copied to clipboard

Add `sensitive` to `ZodSchema`

Open kriswuollett opened this issue 3 years ago • 3 comments

I noticed in #595 the discussion regarding sensitive values. It would be great to add the ZodError to structured logging like through pino so that things like path can be directly searched to find / deduplicate issues in logs, but sensitive values can get logged due to the received field as well as some of the localized messages:

https://github.com/colinhacks/zod/blob/9828837fb94f1500ef362b20ca5fe35eed1b6d0e/src/locales/en.ts#L7-L13

Perhaps one could write code like the following to make sure received is undefined by adding a sensitive: boolean to the appropriate Zod types, as well as the localized messages appropriately not interpolating the sensitive value:

const databasePassword = z.sensitive.string().min(1).safeParse(process.env.MY_DATABASE_PASSWORD);
if (!databasePassword.success) {
  log.error({
    err: databasePassword.error // all `received` fields are not set
  }, 'Invalid database password: %s', databasePassword.error.message);
  return null;
}

Useful for credentials like passwords, and PII like email. Redaction in pino cannot be used in a workaround in all cases due to https://github.com/pinojs/pino/issues/1612.

kriswuollett avatar Dec 30 '22 19:12 kriswuollett

@kriswuollett Thanks for submitting this suggestion.

I think that you can achieve this by defining a custom error map on the schema. By doing that, you can clear whatever message would get logged and replace it by any other string/combination of characters of your choice (e.g., ***).

Do you want help with setting this up?

santosmarco-caribou avatar Jan 04 '23 04:01 santosmarco-caribou

Thanks for pointing out the custom error map -- I did not notice that. I think I can figure out from the docs how to suppress info in the error message.

I guess I'm just looking for a generic way to add tags/labels to values for various reasons.

I was just looking into transform now to see if I could override the type, but I'm guessing that if a validation failed before the transform, then the received value would still contain sensitive info.

I'm thinking my best bet would have anyways been to transform (the Zod) errors into a shared generic type before logging.

Feel free to close the issue if you don't think it is needed for zod, but if you'd like to see another implementation for inspiration, check out secret types in Pydantic.

kriswuollett avatar Jan 04 '23 16:01 kriswuollett

In my scenario, I need certain attributes to be redacted not just when generating error messages, but also during a successful parse.

This is similar to how Pydantic handles the Secret type:

from pydantic import BaseModel, SecretBytes, SecretStr, field_serializer


class Model(BaseModel):
    password: SecretStr
    password_bytes: SecretBytes

    @field_serializer('password', 'password_bytes', when_used='json')
    def dump_secret(self, v):
        return v.get_secret_value()


model = Model(password='IAmSensitive', password_bytes=b'IAmSensitiveBytes')
print(model)
#> password=SecretStr('**********') password_bytes=SecretBytes(b'**********')

I understand that the creator of Zod is strongly opposed to passing any context to the parse function, but that creates challenges for cases like this.

I came up with this hack. It ain't pretty but it seems to work:

import { z } from 'zod'

let loggingFlag = false

/**
 * A zod string that will be redacted when logging
 */
export const sensitiveString = z.string().transform((a) => (loggingFlag ? '[REDACTED]' : a))

export function parseSensitive<TSchema extends z.ZodTypeAny>(
    schema: TSchema,
    data: unknown,
): z.infer<TSchema> {
    try {
        loggingFlag = true
        return schema.parse(data)
    } finally {
        loggingFlag = false
    }
}

canassa avatar Aug 24 '24 09:08 canassa

Hi, @kriswuollett. I'm Dosu, and I'm helping the Zod team manage their backlog. I'm marking this issue as stale.

Issue Summary:

  • You proposed adding a sensitive option to ZodSchema to prevent logging sensitive data.
  • santosmarco-caribou suggested using a custom error map, which you acknowledged as a potential solution.
  • You expressed interest in a more generic tagging system, inspired by Pydantic's secret types.
  • canassa shared a workaround for redacting sensitive data, noting the challenge of not passing context to the parse function.

Next Steps:

  • Please let us know if this issue is still relevant to the latest version of Zod. If so, you can keep the discussion open by commenting on the issue.
  • Otherwise, the issue will be automatically closed in 14 days.

Thank you for your understanding and contribution!

dosubot[bot] avatar Jul 24 '25 16:07 dosubot[bot]

I got something like this working:

import util from "util";

import z from "zod";

class Secret {
  #value: string;

  constructor(value: string) {
    this.#value = value;
  }

  get() {
    return this.#value;
  }

  toString() {
    return "REDACTED";
  }

  // JSON.stringify(config) will use this
  toJSON() {
    return "REDACTED";
  }

  [util.inspect.custom]() {
    return `Secret { ${this.toString()} }`;
  }
}

export const secret = z.codec(z.string(), z.instanceof(Secret), {
  encode: (secret) => secret.get(),
  decode: (secret) => new Secret(secret),
});

umstek avatar Nov 08 '25 08:11 umstek

Thanks for sharing your solution, @umstek! This is really helpful for others looking to handle sensitive data. I'll go ahead and close this issue now.

dosubot[bot] avatar Nov 08 '25 08:11 dosubot[bot]

@dosubot We would still like an official solution

umstek avatar Nov 08 '25 08:11 umstek

Hi @umstek! I'm Dosu and I’m helping the zod team.

I'm Dosu, a bot trained on Zod's codebase and issues.

There isn't an official solution in Zod 4 for sensitive/redacted types or automatic error redaction—no built-in sensitive flag, secret type, or error redaction mechanism like Pydantic's Secret types. The maintainers have intentionally avoided including received values in error messages to prevent leaking sensitive data, and recommend handling redaction outside of Zod if needed (source).

Zod 4 does introduce metadata tagging via .meta() and schema registries, which lets you label fields as sensitive, but this doesn't affect error reporting or output redaction (docs). You can customize error messages with the new error parameter, but sensitive values may still appear in the error's received field or in successful parse results (docs).

Current workarounds include custom error maps, transforms, or wrapper classes (like your Secret class), but these all require manual implementation. If your question is answered or you have a working solution, feel free to close the issue. If you want to see this feature in Zod, you can add your use case to the existing discussions for visibility.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other  Chat with Dosu Join Discord Share on X

dosubot[bot] avatar Nov 08 '25 08:11 dosubot[bot]