rl-c-client

Security

Do not open public issues for suspected vulnerabilities.

Until a dedicated security alias is published, report security concerns to:

wojciech@ratelimitly.com

Include:

Credential Handling

API key credentials can contain raw cookie or AES key material. Do not log:

Prefer environment-based credential delivery (RATELIMITLY_AUTH_KEY) over command-line arguments: argv is visible in process listings and shell history. Environment values are still readable by same-user processes and are inherited by children, so keep credentialed processes isolated and out of CI logs.

The library cleanses its own retained copies of secret material on destroy, but it never cleanses caller-owned buffers: zero your r_auth_key_info_t (for example with OPENSSL_cleanse) after inspecting a credential.

Authentication Modes

Use AES credentials for deployments that cross an untrusted network. Cookie credentials are intended only for private-network deployments where passive capture and on-path modification are outside the threat model. Cookie mode does not provide packet integrity, and it exposes the reusable 32-byte cookie value to any passive observer.

AES-256-GCM mode encrypts the request payload (the PDU) and authenticates the whole datagram: the plaintext packet header is bound to the GCM tag as associated data. Packet headers — the tenant key ID, request ID, timestamp, and steering flag — remain readable by any on-path observer in both modes; only the payload is confidential, and only in AES mode.

The library generates a fresh random 96-bit GCM nonce for every encryption from the OpenSSL CSPRNG. The client performs no cross-instance nonce coordination: uniqueness under one AES key is probabilistic, and the standard budget for random-nonce GCM is 2^32 encryptions per key, aggregated across every client instance sharing the tenant key. Each admission performs roughly two to three encryptions with default policy (initial send, replay rounds, completion delivery) plus one per latency-report call. High-volume or long-lived deployments should rotate tenant AES keys well before the aggregate budget is approached.

The same CSPRNG supplies every resource-request and latency-report identity. If it reports failure, the operation returns RCLIENT_ERR_AUTH and the client does not send a packet with a predictable or repeated identity.

Response Replay Model

AES responses authenticate the clear packet header and encrypted PDU. This binds the response unique_id, server id, timestamp, and steering feedback to the GCM tag, so an observed response cannot be retargeted to another request.

The client treats unique_id as the replay boundary. A response is accepted only while a matching request is still in flight; after completion, timeout, or cancel, later datagrams with that unique_id are ignored. Duplicate responses from the same server id do not represent responses from additional servers. The authenticated timestamp is not used as a wall-clock freshness check.

The binding guarantees above apply to AES credentials. Cookie-mode responses are matched only by the plaintext unique_id and the echoed cookie value — nothing cryptographically binds the server id, timestamp, or payload — so on-path response forgery is not prevented in cookie mode, consistent with its private-network threat model.

A server-side authentication failure produces no response at all (the server blackholes unauthenticated traffic), and the client discards responses that fail verification while leaving the request in flight. Both therefore surface to the application as RCLIENT_ERR_TIMEOUT, never as an authentication error; see the Error Codes section of docs/api.md when debugging.

Host integrations must keep request deadlines short and must call r_client_on_timeout or r_client_cancel_request when the application request is no longer active.

Release Integrity

The release workflow builds each binary on a native runner, rejects incomplete or unexpected artifact sets, and publishes SHA256SUMS plus RELEASE-MANIFEST.json. The manifest binds every payload name to its version, source commit, architecture, size, and SHA-256 digest.

Every published payload, SHA256SUMS, and the release manifest receives a GitHub build-provenance attestation before the draft release becomes public. Verify both the checksum and the attestation; a matching checksum alone does not establish who produced an artifact.

Publication runs only after a push to main. The workflow reads the canonical VERSION, builds and validates the complete native matrix, then creates the matching release tag at that tested commit. An already published version is never overwritten.

Windows SDKs also contain a WDK-generated SPDX SBOM. Release packages are not claimed to be Authenticode-signed, Apple-notarized, or distribution-repository signed unless the individual release notes explicitly say so.

Supported Versions

Security fixes are provided for the most recent published release. Users of older releases should upgrade unless release notes explicitly extend support.

Reporting

Use the private reporting process above. Do not publish proof-of-concept code or real credentials in public issues, pull requests, logs, or examples.