Security
Understand Batchwork's credential, media fetch, webhook signature, and replay-safety boundaries before production use.
Credentials
Pass secrets through provider environment variables or ProviderCredentials; do not place them in requests, metadata, logs, or custom_id. Per-call values override client configuration, which overrides the environment. Injected base URLs and headers are trusted application configuration, but base URLs still require HTTPS and cannot contain userinfo, a query, or a fragment. HTTP is allowed only for the exact host localhost or a literal loopback IP such as 127.0.0.1 or ::1, not a hostname that resolves to loopback. This validation intentionally hardens the trusted-configuration boundary.
Remote media
The default media resolver accepts bytes, data URLs, public HTTPS URLs, local paths, and provider file references. Local paths are literal: home directories, environment variables, shell substitutions, and globs are not expanded. Files must resolve to readable regular files and are read only up to the configured bound. The CLI resolves relative paths from a workload file’s parent or from the working directory for stdin, then freezes the bytes before provider serialization. For fetched URLs the resolver rejects credentials, private or reserved addresses, DNS rebinding, non-HTTPS redirects, oversized bodies, and unsupported media. It uses an isolated client and never forwards provider credentials, configured headers, cookies, or authorization state. Keep BatchLimits.max_request_bytes appropriate for your service.
Provider-direct URLs
Some URLs are not fetched by Batchwork. They are passed directly to the selected provider and retrieved under that provider’s network, authentication, retention, and size policies. Batchwork therefore does not DNS-validate, content-sniff, or byte-limit those resources.
Direct modes include OpenAI image URLs and Responses PDF URLs, Anthropic image/PDF URLs, Groq image URLs, Mistral HTTPS PDF URLs, xAI image/file URLs, and constrained Google Gemini Files/YouTube URLs. Other remote media is resolved and inlined where the adapter supports it.
Treat provider-direct URLs as provider-visible input. Do not assume DefaultMediaResolver SSRF controls apply to them.
Outbound webhooks
The default webhook path requires HTTPS, rejects URL credentials, resolves every address as globally routable, and pins delivery to the validated address. It does not follow redirects. A custom URL validator or transport replaces part of that boundary, so apply equivalent SSRF and redirect controls.
Signatures and replay protection
sign_webhook() and verify_webhook() use Standard Webhooks-compatible HMAC-SHA256 headers with a five-minute timestamp tolerance. Verify the exact raw request body before JSON parsing. Each delivery attempt has a replay identity; the stable event identity remains suitable for consumer idempotency.
MemoryWebhookReplayStore is atomic only within one process. Distributed receivers should implement AtomicWebhookReplayStore.claim() with an atomic write-if-absent and expiry operation.
verify_webhook() returns a claimed VerifiedWebhook. If handling fails after verification, call await verified.release() before returning a retryable response so the same signed delivery can be verified again.
Delivery semantics
The poller provides at-least-once delivery: it performs the completion side effect before persisting delivered_at. Consumers must deduplicate by event ID, and operators should retain undelivered records for retry rather than deleting them after a transient error.