Why we’re doubling down on API token security

Melinda Fekete

Melinda Fekete

Documentation Lead

October 29, 2026

Passwords have been hashed for decades. Nobody serious stores them in plaintext, because a database leak would turn into a credential leak. API tokens are credentials too, but across the industry they’re still mostly stored in full. Some platforms let you reveal an SDK key at any time after creating it, which is only possible if the key is kept in a recoverable form. Unleash was no exception. Until now, every token you created lived in the Unleash database, in full.

Unleash 8.3 fixes that. Every new backend, frontend, personal access, or service account token is shown to you once, hashed, and never stored in a usable form. Unleash keeps the hash and the token’s metadata, never the token itself. If the database or one of its backups leaks, what leaks is a list of hashes and metadata, not keys to your release workflow.

Nothing breaks when you upgrade. Tokens created before 8.3 keep working exactly as they do today, and there is no deprecation date for them. Their complete values do stay in the database until you delete them, so rotating is how you extend this protection to the integrations you already run. This post covers why we made the change, what it does and doesn’t protect, and how to rotate.

Read our FeatureOps Whitepaper
Get your free copy and learn how to connect engineering performance to business outcomes for fun and profit.Download now

Secrets are where attackers are winning in 2026

The reason to care about a single table in a single database is the shape of the breaches happening right now.

Credentials are no longer just the way attackers get in. They’re how attackers move once inside. The Verizon 2026 Data Breach Investigations Report found credential abuse in 39% of breaches across the full attack chain, and third-party involvement in 48% of breaches, up from 30% the year before. Your vendors’ databases are part of your attack surface.

Leaked secrets are also abundant and long-lived. GitGuardian’s State of Secrets Sprawl 2026 found 24,008 secrets sitting in public MCP configuration files, the files that tell AI assistants which systems they’re allowed to touch. And 64% of the credentials it confirmed valid in 2022 were still valid in January 2026. Nobody rotated them. OWASP now ranks secret leakage second on its Non-Human Identities Top 10.

The stored-secrets scenario is not hypothetical either. On October 21, 2026, the deployment platform Railway disclosed that an unauthorized party accessed its environment variable store and, for some variables, obtained the decrypted contents. Every customer was told to roll every API key and credential stored on the platform.

Railway’s variables were encrypted at rest, and the attacker still walked away with usable values. Encryption at rest protects against someone stealing a disk. It doesn’t protect against someone with access to the running system that holds the key. A hash protects in both cases, because there is nothing to decrypt. Railway can’t take that route: its product has to hand secrets back to users, so it has to be able to recover them. Unleash doesn’t need to hand tokens back. We have a choice Railway doesn’t, and we took it.

Why this matters for feature flags

An API token is a key to your release workflow. Backend tokens let SDKs and Unleash Edge read flag configuration for their projects and environments. Personal access tokens carry the permissions of the person who created them. Service account tokens carry the permissions of their role, which often includes changing flags in production.

Those keys are everywhere. CI pipelines create and toggle flags. Edge instances fetch configuration. Terraform manages projects and environments. Integrations and AI assistants connect through the Unleash MCP server. Every connection holds a token, and the more automation you run, the more tokens are in circulation. Most of them belong to machines, not people, and machine credentials are the ones that get forgotten.

Read access to a database is also far more common than a full compromise. Backups get copied to shared storage. Snapshots get attached to support tickets. Read replicas get opened up for analytics. In the old model, any of these paths exposed working tokens. In the new model, they expose a list of tokens and their metadata, nothing you can authenticate with.

What changed in Unleash 8.3

Each new token has two parts: a selector and a random secret. The selector tells Unleash which database record to look up. The secret is 32 random bytes.

When you create a token, Unleash stores the selector and a SHA-256 hash of the complete token. When an SDK or a user sends the token, Unleash finds the record by its selector, hashes the token it received, and compares the two hashes in constant time. Unleash can verify a token without holding a copy it could later hand out, and nothing in the database can be turned back into a token. The docs describe how Unleash stores tokens in more detail.

If you’re wondering why SHA-256 rather than a slow, salted hash like bcrypt or Argon2: those exist to defend short, human-chosen passwords against guessing. A token secret is 32 random bytes, which is 256 bits of randomness. There is nothing to guess, so a slow hash would add cost to every request without adding protection.

Secure tokens work everywhere legacy tokens work. SDKs pass the token through as an opaque string. Unleash Edge reads the project and environment from the prefix of the token, and that prefix hasn’t changed, so existing Edge versions accept secure tokens. We recommend Edge v20.5.0 or later, which improves the token telemetry Edge reports back to Unleash, but it is not required.

You can tell the two kinds of tokens apart by their format. A legacy backend token for the development environment of the new-checkout-flow project looks like this:


new-checkout-flow:development.be44368985f7fb3237c584ef86f3d6bdada42ddbd63a019d26955178

The secure version of the same token contains `v2_`, followed by the selector and the random secret:


new-checkout-flow:development.v2_Y8mfumDNYCBPIzU_X48tyA_P3XdoA9Fel9KoioeVKw5FWmA-PGd2jxq9SYj2hqCwlk

Personal access and service account tokens follow the same pattern with a `user:` prefix. The get API tokens endpoint returns secure tokens with `secure: true` and only the selector in the `secret` field. Events for secure tokens include only the selector, never the complete token.

What hashed tokens do and don’t protect

This change protects the Unleash database. The complete token still exists wherever you use it, and some tools keep their own copies:

  • Your SDKs, Edge instances, and pipelines need the complete token to authenticate. Store it in a secrets manager.
  • Unleash Edge caches in memory by default. If you enable persistence with Redis, S3, or a backup folder, those snapshots contain complete tokens, including secure ones. Protect that storage like any other secret, and follow the production deployment guidance for Edge.
  • Terraform keeps the tokens it creates in its state file.
  • Request logs are outside the scope of this change. If a proxy or load balancer in front of Unleash or Edge logs the Authorization header, the complete token is in those logs.
  • Deleting a legacy token removes it from the live database. Older backups still contain it until your retention policy removes them.

Hashing tokens removes one place where a leak turns into access. Least-privilege roles, change requests, and the event log cover the rest. Our security and compliance guide walks through how they fit together.

What to do

If you’re on Unleash Cloud, you’re already on 8.3 and every token you create from now on is a secure token. Tokens you created before the rollout are legacy tokens, so rotate them like everyone else.

If you self-host, upgrade to 8.3. Then:

  1. Copy the token when you create it. Unleash shows it only once. If you lose it, create a new one, update the application that uses it, and delete the old one.
  2. Rotate your legacy tokens. Upgrading doesn’t convert them. For each integration, create a replacement token, update the integration, confirm it works, and then delete the legacy token. The docs cover rotating a token step by step.
  3. Include tokens from environment variables. Tokens you set through `INIT_BACKEND_API_TOKENS`, `INIT_FRONTEND_API_TOKENS`, or the deprecated `INIT_CLIENT_API_TOKENS` are legacy tokens, because Unleash stores the value you supply. Replace them with tokens created in the Admin UI or through the API. See the configuration reference.
  4. Keep using frontend tokens in the browser. Frontend tokens are still safe to expose in browsers and mobile apps. They return evaluated flag values for their project and environment and don’t reveal targeting rules. Scope them to what the app needs.

If you lead a team rather than run the upgrade yourself, there’s one question to ask: how many legacy tokens do we have, and who owns each one? The answer takes two minutes to get from the API tokens page in the Admin UI, and it’s usually more than expected. Put the rotation on the roadmap now, while it’s a maintenance task and not an incident response.

Want to dive deeper? The Unleash documentation covers how secure tokens are stored, what each token format looks like, and how to rotate them step by step.

Explore further