Skip to main content
Anyone with an inbox URL or a testing address can send to it. Reading what arrived needs an API key or a dashboard session with access to the workspace, and everyone with that access can read all of it.

Who can send and who can read

  • Every member of the workspace, at every role, can read, download, wait, inject, and delete. There is no read-only role for testing data.
  • API keys have no scopes. A key that can list monitors can also read every captured request and email in its workspace. Create a separate key for CI so you can revoke it alone. See API keys.
  • The URL and the domain are not credentials for reading. An inbox or domain in another workspace returns 404.

The inbox URL is a write secret

The ingest URL is https://api.devhelm.io/api/v1/ingest/<public-token>. The token is 256 random bits, and ingest takes no other authentication. An unknown token and a disabled inbox both return 404. The token cannot be rotated. If a URL leaks:
  1. Create a new inbox and point your sender at its httpUrl.
  2. Delete the old inbox. Its URL returns 404 right away.
To pause capture without losing the URL, set the inbox status to disabled. Senders get 404 until you enable it again.
Logs on public repositories are public. Do not print an inbox URL in CI output. In GitHub Actions, mask it with echo "::add-mask::$WEBHOOK_URL" before any step can log it.
Testing addresses are not secrets. Every local part on a domain is an inbox, and anyone who knows or guesses an address can send mail to it. Assert on the sender or subject when a stray message would break a test.

Captured headers are stored as sent

DevHelm stores every request header and every email header without redaction, along with the raw body, the query string, and sourceIp. An Authorization, Cookie, X-Api-Key, or signature header a sender includes is returned to anyone who can read the workspace. Webhook header names are stored lowercased; email header names keep their case. Point senders at an inbox with test credentials only. When a test captures a credential by design, delete the event when the test ends:
The CLI has no single-event delete. inboxes events clear removes every event on the inbox.

Returned HTML is not sanitized

GET on an email message returns html exactly as received, and a webhook body is returned as sent. Scripts, forms, remote images, and meta refreshes are left in place. Render captured HTML only inside a sandboxed frame:
An empty sandbox attribute blocks scripts, forms, popups, and same-origin access. Never insert captured HTML with innerHTML.

API keys in CI

  • Store the key as an encrypted secret named DEVHELM_API_TOKEN, and the workspace ID as DEVHELM_WORKSPACE_ID. Expose them only to the job that runs the tests.
  • GitHub does not pass repository secrets to pull_request runs from forks, or to runs started by Dependabot. Skip the DevHelm tests on those runs instead of failing them.
  • Do not use pull_request_target to get secrets into a fork’s run. Checking out the fork’s code there lets that code read the key.
  • If a key leaks, revoke it under API keys and create a new one.
Testing in CI has a complete workflow.

Retention and cleanup

An inbox’s retentionDays defaults to your testing plan’s ceiling, and a higher value returns 403 INBOUND_RETENTION_ABOVE_PLAN. The setting is stored, but DevHelm does not currently delete captured data on a schedule. Events and messages stay until you delete them, so clean up in test teardown. maxEvents (default 10000) caps how many events an inbox keeps; the oldest is dropped as a new one arrives. Set it low on inboxes that capture sensitive payloads. Do not delete the assigned email domain to clean up. Concurrent runs share it, and the next address() call creates a domain with a new name, which breaks stored addresses.

Do not use testing addresses for real accounts

A testing address receives any mail sent to it, and every member of the workspace can read it. A password reset or login link sent there can be used by anyone who reads it.
  • Do not register real accounts, on your product or a third party’s, with a testing address.
  • Do not send customer or personal data to an inbox or a testing address. Use synthetic users and fixtures.
  • Do not point a production webhook sender at an inbox. Use a staging sender with test credentials.

Next steps

Limits, quotas, and errors

Plan quotas, size limits, and every error code.

Testing in CI

Secrets, per-job inboxes, and teardown in GitHub Actions.

Webhook inboxes

How inboxes capture and store requests.

Email testing

How testing mailboxes receive and store mail.