Short-lived context,
explicit trust.
Forwarded is designed so that forwarded context cannot be forged, replayed, or leaked. Sessions expire. API keys are scoped and hashed at rest. Nothing sensitive is stored beyond what's needed to resolve a payload once.
How sessions are protected.
Every security property in Forwarded was designed around a narrow threat model: protecting payload confidentiality and binding integrity from the moment a session is created to the moment it is claimed. These are the three primitives that underpin everything.
Signed sessions
Session tokens are HMAC-SHA256 signed using a per-workspace secret. The token includes a random nonce and an expiry timestamp. The server stores only a hash of the token — the raw value is displayed once and never stored again. Resolving a session requires presenting the raw token; the server verifies the HMAC and checks the hash before returning any payload.
Short-lived by design
Sessions expire. Unresolved sessions are pruned automatically. Once a session is resolved, the token cannot be resolved again — single-use. Claims are idempotent: retrying with the same idempotency key is safe, but a different user cannot claim an already-claimed session. There is no mechanism to extend or reopen an expired session.
No fingerprinting
Forwarded does not use device fingerprinting, IP geolocation, or probabilistic matching. Context is delivered through native platform mechanisms — iOS app-argument, Android Install Referrer — that are deterministic by design. Forwarded labels the confidence tier of every resolution and never silently upgrades a lower-confidence path.
What Forwarded protects against.
The threat model is narrow: protecting payload confidentiality and binding integrity from web click to app claim. These are the four classes of attack the design addresses.
Token replay
Tokens include a nonce and are invalidated server-side after resolution. A captured token cannot be resolved again. Expired tokens are rejected before HMAC verification begins, so time-bounded replay is not possible even if a nonce check were bypassed.
Payload injection
Payloads are stored server-side and returned by the API — never embedded in the token or in the client-facing URL. A forged or modified URL cannot inject a different payload. There is no client-controlled field that reaches the resolved payload.
Session hijacking
Resolving requires the raw token, which is never stored server-side after creation. The token is passed through native OS mechanisms — app-argument, referrer string — not through clipboard or shared storage paths where it could be read by other apps.
Cross-app leakage
Sessions are scoped to a workspace and an app registration. An API key from one workspace cannot resolve or claim sessions from another. App IDs are validated at resolve time — a token issued for App A will be rejected if presented to the SDK configured for App B.
Scoped, hashed, revocable.
API keys give your SDK and backend access to Forwarded. They are designed so that a leaked key causes the minimum possible damage: each key carries only the scopes it needs, and the raw value can never be recovered from what Forwarded stores.
One-time display
Random 32-byte values generated server-side. Displayed exactly once after creation. If lost, revoke and create a new one — Forwarded cannot reveal a key after creation because it is never stored in recoverable form.
scrypt at rest
Keys are hashed at rest using scrypt with a per-key salt. The raw value is never stored or logged anywhere in the system. Forwarded cannot reconstruct a key from what it stores, and neither can an attacker with database access.
Scoped permissions
Keys carry explicit scopes: forwarded:resolve for SDK use, forwarded:claim for backend use, events:write for telemetry. A key used in the iOS SDK should not carry claim scope. Principle of least privilege is enforced at the API level, not just by convention.
Every event is signed.
Webhook payloads are signed so that your endpoint can verify the request came from Forwarded — not a replay, not a third party. Signature verification should be the first check in your webhook handler. The verification algorithm is HMAC-SHA256; the timestamp is included in the signed payload to prevent replay attacks.
// Check timestamp against current time (max 5-minute skew) to prevent replay attacks.
Minimum viable data.
Forwarded collects only what is needed to deliver sessions. You control what goes in the payload — and that content is entirely your responsibility. Forwarded does not interpret, index, or analyze your payload data.
IP anonymization
Visitor IP addresses are HMAC-hashed with a rotating salt before storage. The raw IP is never written to disk. The hash can only be compared within a single salt rotation window, after which it cannot be reversed or linked to a specific visitor.
No tracking pixels
Forwarded does not embed analytics pixels, load third-party scripts on landing pages, or track users across sessions or domains. The SDK communicates only with your Forwarded workspace — no third-party beacons, no side-channel attribution.
Developer-controlled payloads
Forwarded does not interpret your payload. You decide what fields it contains. Do not include passwords, payment data, PHI, or long-lived credentials. The Forwarded API rejects payloads over 8 KB and does not log payload content in error responses.
Security disclosure
If you discover a vulnerability in Forwarded, please contact security@forwarded.link. We will acknowledge within 48 hours and aim to resolve critical issues within 7 days. Please include a description of the vulnerability, steps to reproduce, and your assessment of the impact. We do not operate a public bug bounty program at this time.