Current section
Files
Jump to
Current section
Files
SECURITY.md
# Security policy
AshHooks handles webhook authentication, untrusted request bodies, signing secrets,
outbound destinations, and durable delivery state. We welcome responsible reports about
any weakness in those boundaries.
## Supported versions
Security fixes are released for the newest minor release in the current major line.
| Release line | Supported |
| --- | --- |
| >= 3.2.0 and < 3.3.0 | Yes |
| < 3.2.0 | No |
Upgrade to a supported release before requesting a backport. Safety corrections may
tighten behavior in a patch release when the previous behavior accepted unsafe input or
misclassified an incomplete operation.
## Report a vulnerability privately
Do not open a public issue. Use the repository's
[private vulnerability report](https://github.com/baselabs/ash_hooks/security/advisories/new).
Please include:
- the affected AshHooks version and runtime environment;
- the affected surface, such as inbound verification, outbound signing, destination
validation, HTTP transport, delivery recovery, retention, or redaction;
- the smallest reproducible input and the observed result;
- the impact you believe is possible; and
- real service or protocol-peer evidence for transport and interoperability findings,
when available.
Never include production secrets, credentials, or signed customer payloads. Use newly
generated credentials and synthetic payload bytes. We aim to acknowledge reports within
seven days and will coordinate validation, remediation, release timing, and credit with
the reporter.
## Security guarantees
### Inbound verification
- The package's byte-key HMAC verifier checks lengths and compares MAC bytes in
constant time. Custodians must provide the same full-MAC comparison guarantee
for opaque keys. Public-key verification uses OTP's cryptographic functions.
Give `AshHooks.Ingress` the exact raw body. It verifies before decoding the payload.
- Verification fails closed: a missing, malformed, or undecodable signature, key, header,
or signed-input part returns a classified error from the packaged signature functions
and validated scheme verifier. Application providers and secret resolvers must
provide their own error handling. Errors omit key and signature bytes.
- Keys and algorithms come only from the host's provider configuration and secret
sources. The package never fetches keys from a URL, a header, or the token being
verified. A JWS body is verified only with the host-pinned algorithm; `none`, an
algorithm mismatch, a nonempty `crit` header, `b64: false` payloads, and padded
segments are rejected.
- X.509 certificates supplied as keys are used only as containers for a key the host
pins; their chain, expiry, and revocation are not evaluated.
- Inbound DSL secret options accept resolver sources rather than literal binaries.
Byte-based verification obtains secrets from callbacks. Opaque custody keys sign
and verify through custodian callbacks without returning secret material.
Persisted endpoint rows contain references and reject known secret-material prefixes.
- Timestamped schemes enforce their replay windows before handler execution, and only
after the signature verifies. For schemes that sign no timestamp, retained ledger
identities prevent repeated handling. Leases and fencing tokens prevent a stale or
superseded owner from marking a newer claim complete.
- Inbound headers are not stored. Decoded payloads and a digest of the signed raw
body remain in the ledger until the host applies redaction or retention policies.
Application providers and secret resolvers must provide their own error handling.
## Outbound requests
- `AshHooks.Http.Bounded` is the default adapter. By default it limits the combined
response header stream to 32 KiB, retained response bodies to 64 KiB, interim
responses to eight, connection setup to five seconds, and the complete HTTP operation
to 15 seconds. The operation deadline includes DNS resolution, connect, send, interim
responses, and body reads. Once the body cap is reached, the adapter returns the
retained prefix and closes the connection without draining the remaining response.
- Redirects are never followed. A redirect is returned to the delivery state machine and
classified as refused.
- Destination validation runs when an endpoint is written and again when it is sent.
Metadata hosts and non-global IPv4 and IPv6 ranges are rejected. DNS validation is
fail-closed: every returned address must be public, and the connection is pinned to a
validated address while TLS and the `Host` header continue to use the original host.
A consumer `:destination_policy` (`AshHooks.DestinationPolicy`) may allow or deny
ahead of this check: an `:allow` is an explicit consumer trust decision that replaces
the packaged send-time gate for that URL (the HTTP adapter's resolve-and-pin remains
the transport's own boundary), a `:deny` is terminal, and a contained callback
failure retries: a policy defect never dead-letters deliveries.
- TLS uses the OTP trust store unless the host supplies a CA bundle. Hostnames use the
normal certificate hostname check. Literal HTTPS addresses must match an `iPAddress`
subject alternative name.
- HTTP methods come from a finite supported set. Header names must be valid HTTP tokens;
header values and event identifiers must be valid UTF-8 and cannot contain control
bytes. Validation happens before serialization in both bundled adapters.
- `AshHooks.Http.Httpc` remains available, but OTP may assemble a non-2xx body before the
package can truncate it. It also refuses literal-IP HTTPS because it cannot enforce the
IP subject-alternative-name check. Use the bounded adapter when these guarantees matter.
### Delivery state and stored data
- Each delivery attempt has a finite deadline covering endpoint reads, secret
resolution, signing, transport, response handling, and the result write. Attempt and
enqueue tokens, finite leases, durable source/route ownership, and endpoint snapshots
prevent stale workers from committing a result or disabling a replacement endpoint.
- Response bodies are not stored by default. Explicit diagnostic capture runs through a
bounded redaction pipeline before persistence.
- Telemetry contains identifiers, counts, states, and classified reasons. Secret
material is not emitted.
- The package performs internal state transitions with authorization disabled. Consumer
read and write surfaces remain governed by the host application's Ash policies.
## Reportable issues
Examples include:
- accepting an invalid, forged, replayed, or stale inbound delivery;
- exposing secret material through storage, logs, errors, telemetry, or response capture;
- reaching a private, link-local, loopback, reserved, or metadata destination without an
explicit validation override;
- following an outbound redirect or accepting the wrong TLS identity;
- bypassing header, body, interim-response, or operation-time bounds;
- allowing a stale delivery owner to commit, resend, or disable an endpoint;
- crossing tenant or declared resource boundaries; and
- reprocessing a terminal row or allowing a superseded row to reach a handler.
Host application policies, migrations, secret-manager controls, queue scheduling, and
receiver-side deduplication are outside the package's enforcement boundary. Custom HTTP
adapters and explicit destination-validation or bound overrides replace the corresponding
built-in guarantee and should be assessed as part of the host application.
The supported version range is `>= 3.2.0 and < 3.3.0`.