Dashboard › cli › Distillation
b39263be-23ad-459c-9f52-fc5481b1d6be["lore_tm_v1_MBZAlMoNuMToGBIzrPHcudPEsBVfHTUw-_C2_zJ6b3g","lore_tm_v1_72gMzhicYLP8725KbNY0ZXWF86Tv528rtdmJ6jwgQK0","lore_tm_v1_eGsoY6Y04_LfHu8m7DxxkJ0beRX3ks6HtuWrMhw_Q4c","lore_tm_v1_vGmITAxXTE0sRBxureSy0s42b1xiIc-BKU9E5OcloUs","lore_tm_v1_WMvtvb-ZHiavks3OPMDflgXbumAzQSsI0v7rQxpx3sE","lore_tm_v1_8fxs0RGSX4EfMc_L181n_2mEKrxdz3jyMa2CmdFlElM","lore_tm_v1_Ft0Jge0D3yqTazQdwpbIdD7OA-W2Er-p_7LgOBNHqXw"]
Date: Sep 10, 2026
.sentryclirc files are never consulted when snapshotting an env-token host because they have weaker integrity than environment variables or embedded token claims.sntrys_ token format uses exactly 2 underscores, with the second underscore always separating the Base64 JSON payload from the secret.getRawEnvToken() always returns the env token if set, regardless of whether stored OAuth credentials normally take precedence.scheme+host[+port] via normalizeOrigin.packages/cli/src/lib/token-host.ts implements host-scoped token trust: credentials attach only when a request destination matches the recorded token host, preventing untrusted routing inputs from leaking credentials. Trust is exact normalized-origin matching, except a token scoped to https://sentry.io can trust *.sentry.io only under strict HTTPS/default-port SaaS equivalence; non-SaaS hosts never use subdomain suffix matching.isHostTrusted(candidate, trusted) in packages/cli/src/lib/token-host.ts returns false for missing/unparseable inputs, returns true for exact normalized-origin matches, otherwise permits only isSaaSTrustOrigin(trustedOrigin) && isSaaSTrustOrigin(candidateOrigin).getActiveTokenHost() in packages/cli/src/lib/token-host.ts mirrors getAuthConfig() precedence: usable stored OAuth host wins over an env-token host unless a nonblank SENTRY_FORCE_ENV_TOKEN is set; it uses getUsableStoredTokenHost() atomically to avoid a library-mode clearAuth() race between usability and host reads.packages/cli/src/lib/token-host.ts has a process-local normalized loginTrustAnchor, registered only by explicit login --url or boot-time environment snapshot via registerLoginTrustAnchor(url); the .sentryclirc shim does not register an anchor. isLoginTrustAnchorFor(host) performs a host-trust match rather than existence-only checking, preventing stale prior login anchors from admitting another host.isRequestOriginTrusted() returns true when no active token exists; otherwise it trusts the active tokenβs host or dynamically discovered trusted regional origins via isTrustedRegionOrigin(). isRequestOriginTrustedForCustomHeaders() fails closed with no token and no explicit login anchor; with a token it follows token-origin trust, and with only an anchor it checks that anchor.packages/cli/src/lib/env-token-host.ts pins an env-token host before post-boot paths can mutate env.SENTRY_HOST/env.SENTRY_URL: boot order is captureEnvTokenHost() β findProjectRoot β applySentryCliRcEnvShim β getDefaultUrl() fallback.captureEnvTokenHost() is idempotent and ordered: (1) normalized sntrys_ claim url, authoritative for org-auth tokens; (2) normalized SENTRY_HOST or SENTRY_URL for tokens without a claim; (3) DEFAULT_SENTRY_URL. getEnvTokenHost() auto-captures for library-mode callers, and resetEnvTokenHostForTesting() clears the pinned host.packages/cli/src/lib/token-claims.ts parses sntrys_<base64(JSON{iat,url,region_url,org})>_<random-secret> tokens. parseSntrysClaim() rejects absent/non-sntrys_ tokens, tokens over MAX_TOKEN_LENGTH = 2048, tokens not containing exactly 2 underscores, invalid Base64/JSON, non-object payloads, missing/falsy iat, and absent/empty string url; it returns { url, regionUrl?, org? }.sntrys_ claims are unsigned and forgeable, but the userβs trust model treats a legitimate tokenβs embedded URL claim as authoritative against environment-injection attacks because an attacker able to poison SENTRY_HOST in layered CI cannot read or alter the token bytes; forged-token risk is accepted because supplying a forged token already compromises the credential and is outside the threat model.packages/cli/src/lib/db/auth.ts: SENTRY_AUTH_TOKEN has priority over SENTRY_TOKEN; blank/whitespace-only values are unset. getAuthConfig() defaults to stored OAuth before env token, reversing that only when SENTRY_FORCE_ENV_TOKEN is nonblank; this prevents wizard-generated build tokens from silently overriding interactive login (core fix for #646).getStoredAuthHost() and getUsableStoredTokenHost() in packages/cli/src/lib/db/auth.ts lazily migrate pre-v16 auth rows with NULL host to the currently configured host; expired stored tokens without a refresh token are unusable, while expired tokens with a refresh token remain usable for OAuth refresh. DB failures return undefined/false tolerantly.packages/cli/test/lib/security/sntrys-claim-mismatch.test.ts tests defense in depth: fetch-layer code must refuse to attach a sntrys_ bearer token when the embedded claim URL disagrees with the request origin, so a token for one Sentry instance cannot be routed to another; this primarily catches honest misconfiguration because claims are unsigned.https://sentry.firsthost.com with routing to https://sentry.secondhost.com throws an embedded-claim mismatch and never sends the bearer; matching claim/request at https://sentry.acme.com attaches bearer auth; absent explicit URL uses claim URL http://localhost:8000 as getApiBaseUrl() and requests http://localhost:8000/api/0/organizations/.https://stored.example.com takes precedence over an inactive env sntrys_ claim; invalid claim URL falls back to https://sentry.io; opaque non-sntrys_ tokens bypass claim checks and remain governed by ordinary host scoping.sntrys_ claim for control silo https://sentry.acme.com may attach its bearer token to registered regional silo https://us.sentry.acme.com, discovered through /users/me/regions/. Root cause of prior failure: raw isHostTrusted recognized only exact origin/SaaS equivalence. Fix: claim enforcement uses isHostTrustedForClaim, which also honors the trusted-region URL extension.sntrys_ token and neither SENTRY_HOST nor SENTRY_URL gets the claimβs self-hosted URL as the env-token host snapshot rather than defaulting to SaaS and failing host guards.