Security policy

Status: draft.

The credential, transport and diagnostic review below was performed for judgevet 0.6.0. The 0.7.0 changes leave those paths unchanged and add local typed policy evaluation and JSON decoding. This is an implementation review, not a new security certification. See installation and the release evidence and API verification limits.

Report a vulnerability

Use GitHub's private Report a vulnerability form. Private vulnerability reporting is enabled for this repository and was checked through GitHub's repository API during this documentation review. Sign in to GitHub to submit a report. Do not put vulnerabilities, credentials or private state in a public issue.

Include the affected version, impact and a minimal reproduction using dummy credentials and synthetic data. Review attachments and logs before submitting. This policy does not promise a response deadline or backports to older releases.

Credentials

The CLI and MCP composition roots use Settings. They accept JEV_API__KEY or the compatibility alias TYPESAFE_API_KEY; the former wins when both are set. JEV_API__KEY_FILE selects a mounted regular file. A configured key beginning with ! selects a trusted command. Explicit CLI keys are literal; then literal settings keys, files and commands take precedence in that order. A selected-source failure does not fall back. Settings can also be constructed in Python. The library's sync and async HTTP adapters instead take an explicit api_key argument and do not load credentials from the environment themselves.

Settings wraps the key in Pydantic's SecretStr, which masks its normal string and representation output. The composition roots resolve files or commands only when constructing the adapter. They retain a wrapped result and unwrap it only in the HTTP constructor expression. The adapter retains a plain Python string and puts it in the authentication header. Masking the settings object is not a promise that arbitrary tracebacks, debuggers or memory dumps cannot expose it. The settings tests cover masking and precedence.

judgevet does not create a credential file or a persistent key store. Supply credentials through the supported environment, file or command sources. The client reads mounted files and does not write resolved keys to disk or the environment. A configured command is a trusted external program; its own storage, network access and logging are outside the client's control.

Command stdout is bounded, stderr is discarded, and nonzero exits fail without disclosing output. Source values must be printable ASCII tokens within 4096 bytes after a bounded read. Resolution errors omit source contents and command text. POSIX process-group cleanup covers success, failure and timeouts; it is not a sandbox for hostile programs. The command inherits the launch environment and working directory. Use noninteractive providers and keep command arguments free of literal secrets. See credential configuration for exact precedence, deadlines and platform limits. If you use direnv, it reads your approved .envrc; judgevet does not encrypt that file. Git ignores .envrc in this checkout, but ignoring a file does not protect it from local readers or copies. Keep credentials out of committed files and command arguments.

Data sent to the service

The HTTP adapter sends the supplied state, named questions (including instructions and criteria), and requested model as JSON. Optional caller-owned state redaction replaces only the state field before serialization. By default it sends the API key in a Bearer authorization header. This follows the official API quick start. The default service is https://api.typesafe.ai; the CLI and MCP accept JEV_API__BASE_URL or TYPESAFE_BASE_URL, and library callers can supply base_url directly. A configured replacement service receives the same data and credential. Only send content you are authorized to disclose to it.

Explicit gateway configuration can replace the credential header and scheme and add caller-selected metadata. A configured correlation header forwards only the dedicated scoped request ID. Other bound context remains local. Custom headers are not a secret vault, and state handling does not redact questions or header values. Gateway operators own upstream credential injection and removal. Credentials and metadata are sent to the selected destination on every retry; redirects remain disabled. Normal HTTP transport headers, such as content type and length, accompany the request. There is no judgevet telemetry or phone-home payload.

With a configured StateRedactor, the client passes a deep copy of ordinary JSON state to redact and serializes its return value once per logical call. Retries reuse those bytes. Copy, callback or serialization failures prevent transmission; the client never falls back to the original state. Without a redactor, the client sends the supplied state unchanged. The callback receives no questions, model or headers. Independent copies of sensitive content in question text or metadata remain outside state redaction. Built-in diagnostics exclude state and callback exception text, but application tracebacks and callback IO remain caller-owned. This seam supplies no detection rules, retention guarantees or compliance certification. See redactor configuration.

CLI file/stdin inputs become state or questions before the call. CLI policy rules are evaluated locally; they are not added to the API payload. MCP tools send the state and question supplied by the MCP client and return answers to that client over stdio. The client's own storage and logging are outside judgevet's control. judgevet does not establish the remote service's retention, training or deletion policy.

Diagnostics and error content

The CLI and MCP configure diagnostics on stderr. At the default level, routine HTTP calls emit no diagnostic. JEV_LOG__LEVEL=debug enables an http.call event containing filtered requested/resolved models, question count, terminal status/outcome, successful typed token counts and scoped caller correlation. It excludes state, question identifiers/text, headers and exception text. Arbitrary bound context is excluded from built-in events. Version-shaped model identifiers and caller request IDs must still contain no sensitive data. The event contract defines exact fields and filtering. JEV_LOG__FORMAT=json or console selects the renderer; automatic mode uses JSON off a terminal. Library imports do not configure logging; applications own their logging configuration.

MCP SDK warning/error diagnostics become a fixed mcp.runtime event with severity and dedicated request correlation, without the SDK's message or traceback. This protects diagnostic stderr, not MCP JSON-RPC error content on stdout. CLI error envelopes and library exceptions are also separate from these diagnostic events. They can contain service-supplied message text. The adapter discards validation input fields and malformed detail structures; it does not scrub arbitrary strings returned by a service. Exception chains can retain HTTP requests and answers. Review protocol errors, CLI errors and tracebacks before sharing them.

The logging adapter masks configured secret field names and PEM-looking strings and omits traceback frame locals. It is not a general secret detector. Applications can configure other handlers, and arbitrary exception messages or strings under other field names may expose data. The HTTP stream tests and MCP stream tests prove the bounded diagnostic behavior with synthetic canaries; they do not prove universal redaction.

Cryptographic posture

Transport and certificates

The default URL uses HTTPS. CLI and MCP settings validation rejects remote plaintext HTTP but permits http://localhost and http://127.0.0.1 for local testing. Loopback HTTP is unencrypted. Direct library adapter construction does not run that validator: library callers must choose an HTTPS URL and a trusted transport themselves.

The sync and async HTTP adapters delegate TLS to HTTPX. They accept explicit proxy and CA configuration through NetworkConfig and the CLI/MCP settings. They do not install certificate pins or select cipher suites. With the default transport, HTTPX verifies HTTPS certificates and host identity by default. It uses the certifi CA bundle rather than automatically using the OS trust store. The reviewed lockfile resolves HTTPX 0.28.1. The adapters also accept caller-supplied transports, whose behavior belongs to the caller.

HTTPX's default environment support remains enabled. SSL_CERT_FILE and SSL_CERT_DIR can replace its default trust roots; HTTP_PROXY, HTTPS_PROXY, ALL_PROXY and NO_PROXY affect routing. Review the launch environment as part of a deployment. An explicit proxy overrides environment proxy routing, including NO_PROXY. An explicit CA bundle replaces default/environment trust roots while retaining certificate and hostname checks. Invalid bundles fail construction. JEV_API__VERIFY=false or NetworkConfig(verify=False) disables those checks; use that override only for controlled tests with synthetic data. A CA bundle cannot accompany disabled verification. Proxy credentials are masked in Settings and omitted from NetworkConfig representations; arbitrary tracebacks remain outside that guarantee. See configuration.

Python's ssl module uses OpenSSL; the available protocols and cryptographic behavior depend on that runtime and its configuration. judgevet does not perform its own certificate validation or supply a separate cryptographic implementation.

Storage and memory

The request path has no persistent credential, state or answer store and no audit sink. The CLI prints answers and errors; file inputs read caller-owned files. Shell redirection, MCP hosts and application log handlers can persist that output. Python, installers and the platform can also write caches, swap or crash dumps. judgevet supplies no encryption at rest or retention control for those artifacts; their storage and protection belong to the application and platform.

SecretStr masks display; it is not encrypted or locked memory. Unwrapped keys, HTTP headers and serialized payloads can have multiple in-memory copies. Python strings are immutable, and the interpreter manages its object heap and allocators. Given those constraints and the adapter's plain strings, judgevet cannot guarantee secret zeroization when objects are freed. Closing an adapter releases network resources; it does not erase every copy of a credential.

Egress and compliance limits

The production request path targets the configured service and has no judgevet telemetry or phone-home endpoint. This is not a guarantee of exactly one outbound connection: HTTPX uses connection pools, and DNS, proxies and caller-supplied transports affect network activity. The default HTTPX clients do not follow redirects; the redirect test checks that setting. Network allowlists and enforcement belong to the deployment.

judgevet does not claim FIPS compliance or automatically inherit it from the OS. It neither configures nor verifies a FIPS provider. OpenSSL documents explicit FIPS module configuration requirements; a compliant deployment requires assessment of the actual cryptographic module, runtime and configuration. Certificate pinning, a judgevet mTLS configuration, encrypted storage and enterprise audit controls are not shipped features of 0.7.0.