Repository navigation
fix: security hardening of tokens, invites, secrets, egress and sign-in (batch 2026-10-16) - #572
Merged
Merged
Conversation
Fifteen fix specs for every critical and high finding of the first six daily security scans, plus three lower ones (federated sign-in skips TOTP, non-atomic attempt counters, revoked PAT cache). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #572 +/- ##
==========================================
+ Coverage 83.07% 83.23% +0.15%
==========================================
Files 1200 1207 +7
Lines 123542 124137 +595
==========================================
+ Hits 102632 103324 +692
+ Misses 20902 20804 -98
- Partials 8 9 +1
🚀 New features to boost your workflow:
|
…settings from drifting out of the docs again Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…reate an account from an unverified email ("nOAuth")
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…to an operator allowlist, at save time and at resolve time Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…m a struct, not an interpolated DSN string Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…configs and restrict `inCluster` for Kubernetes connections Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ing account logs in as that account, with the invite token as the only proof Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… and publication webhooks through the egress guard Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… Kubernetes) under the egress policy Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… without a signing secret, allow-list `response_url`, cap the body Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ork on the whole REST API and the consent screen, and can mint non-expiring PATs Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t and change-password attempt counters atomic Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… sign-in, through the existing 2FA temp-token step Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The callBack URL was registered in NewServer with the pre-overlay JWT secret and base URL, so it never matched the token the handler checks. Register it at the end of InitializeSystemConfig, never derive a token from the public default JWT secret, skip registration on a localhost base URL, and log one startup line without the token. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…red with OVH must carry the token and base URL the handler accepts Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…check fetch-ahead env vars They were ignored before (koanf env mangling and a string-blind ApplyFunc) and now apply.
Adds a docs drift test over the configuration pages and the runners wiki, a systemconfig guard that every overlay-only env var takes effect, and corrects the SP_POSTHOG_HOST default. Changelog: SP_SERVER_CHECK_WORKER_NB and SP_SERVER_JOB_WORKER_NB were ignored before and now apply. Someone who set SP_SERVER_CHECK_WORKER_NB=3 from the old docs drops from 25 to 3 runners (the fast-lane reservation is then clamped and warns). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…onment, their documented defaults match the code, and a test keeps them matched Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…nment, their documented defaults match the code, and a test keeps them matched Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Adds an LDAP / Active Directory section (precedence, env table, TLS, filter rules, lldap and AD examples, troubleshooting), the provider switches and session lifetime variables, and a systemconfig test that every auth.* env var (OIDC and SAML pending their own specs) is named in authentication.md. LDAP failures now log their cause at debug level. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…tings from drifting out of the docs again Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…tings from drifting out of the docs again Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ings from drifting out of the docs again Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… an unverified email
On a multi-tenant registration (common / organizations / consumers), the
Graph `mail` attribute is set by any tenant admin without proof of
ownership ("nOAuth"). It was used to link the Microsoft identity to an
existing local account, or to create one (consuming invitations and
auto-join rules). The connector now reads the ID token returned by the
token endpoint (aud, exp and oid bound to the Graph id) and only trusts
the email when it is pinned to one tenant, or when the ID token carries
`email` with `xms_edov: true`. Already-linked Microsoft IDs keep signing
in.
Changelog (security, behaviour change): multi-tenant Microsoft sign-in
refuses first sign-ins with EMAIL_NOT_VERIFIED until the app registration
adds the `email` and `xms_edov` optional claims to the ID token. A pinned
SP_MICROSOFT_TENANT_ID needs nothing. Existing links are not removed;
see wiki/runbooks/operations-gotchas.md for a read-only review query.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ounters atomic bumpCounter read the counter, compared it in Go and wrote count+1 in three separate statements, so a burst of parallel requests spent one unit of the attempt budget instead of N (about 100 TOTP guesses per 15 min per IP instead of 5, and a multiplied per-user reset-email cap). A burst on a fresh key also inserted N duplicate global rows, since unique (organization_uid, key) never fires for a NULL organization. New db.Service.BumpGlobalCounter does the read, the limit check and the increment in one transaction, serialized per key: on Postgres with pg_advisory_xact_lock(ClassGlobalCounter, hashtext(key)) (two-int4 class 0x50020001, registered in dblock and wiki/conventions/database.md), on SQLite by its single connection. It takes the largest live count across rows, so duplicates left by older code are tolerated and rewritten. Keys, limits and the sliding TTL are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…end one unit each Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e SQLite file Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nd change-password attempt counters atomic Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d change-password attempt counters atomic Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Federated callbacks (Google, GitHub, GitLab, Microsoft, Discord, Slack, OIDC, SAML and the Slack app install) all end in CompleteOrgLogin, which minted a full session without looking at user.TOTPEnabled. A user with TOTP enabled now gets no session there: the result carries requires2Fa and a 2FA temp token naming the org and role the session would have had, and the existing /2fa/verify and /2fa/recovery endpoints mint it once the code is accepted (audit method "<connector>+totp"). The handoff code carries the challenge instead of tokens (exactly one of accessToken / tempToken is accepted by Issue and Redeem), the exchange answers requires2Fa + tempToken with no user or organization info, and no session cookie is set until the code passes. Passkeys remain the only sign-in without the TOTP prompt. Changelog: Security: users with two-factor authentication enabled are now asked for their code on SSO and OAuth sign-ins too, not only on password and LDAP logins. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…prompt Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d sign-in The handoff exchange of a TOTP user now answers requires2Fa and a temp token instead of a session. /auth/complete keeps returnTo and membershipPending, shows the code step, and lands through resolveHandoffLanding once verify2FA / useRecoveryCode succeed. The TOTP / recovery form is extracted into the shared TwoFactorChallenge component, used by the login page too and listed in the design reference. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Also keeps /auth/complete from reading the stripped address bar as "opened without a code" while the code step is on screen. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ge responses Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…gn-in, through the existing 2FA temp-token step Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…n-in, through the existing 2FA temp-token step Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… in the cache
The PAT validation cache now:
- caps each entry at the token's own expiry, so an expired PAT is refused
at once instead of up to 15 minutes later;
- evicts after the row is deleted, behind a generation counter, so a lookup
racing a revocation cannot re-cache the token;
- broadcasts every revocation on the event notifier ("auth.patrevoked",
Postgres LISTEN/NOTIFY across replicas), and clears itself when the
notifier reconnects;
- keeps entries 5 minutes instead of 15 (backstop for a dropped notification);
- hands each cache hit its own copy of the claims.
Release note: in a multi-replica install, revoking a personal access token
now takes effect on every replica within moments, and an expiring token stops
working at its expiry time.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…and reconnects Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…from the in-memory cache for up to 15 minutes Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rom the in-memory cache for up to 15 minutes Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… gate) The new-scan form now falls back to an offered method when the requested one (kubernetes, no cluster connection in the test org) is hidden, so the kubernetes cluster picker no longer renders. The test asserts the preserved URL param and the fallback instead. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…batch Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…om host Only the path and query come from the caller-supplied value, so the request target can never be anything but Slack (CodeQL go/request-forgery). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fclairamb
enabled auto-merge (squash)
October 16, 2026 12:06
Merged
fclairamb
added a commit
that referenced
this pull request
Oct 16, 2026
🤖 I have created a release *beep* *boop* --- ## [0.38.6](v0.38.5...v0.38.6) (2026-10-16) ### Bug Fixes * **deps:** update github.com/dop251/goja digest to 2cb8274 ([#561](#561)) ([085f7de](085f7de)) * **deps:** update go dependencies (non-major) ([#564](#564)) ([b91e3d7](b91e3d7)) * **deps:** update module github.com/anthropics/anthropic-sdk-go to v1.82.0 ([#568](#568)) ([c157444](c157444)) * **deps:** update module github.com/gookit/color to v1.6.2 ([#566](#566)) ([3bf6792](3bf6792)) * **deps:** update module github.com/gookit/color to v1.6.3 ([#567](#567)) ([f6a33d3](f6a33d3)) * **deps:** update module github.com/quic-go/quic-go to v0.64.0 ([#571](#571)) ([fd10f2d](fd10f2d)) * no degraded alert right after an outage recovers ([#577](#577)) ([c8a2dd2](c8a2dd2)) * security hardening of tokens, invites, secrets, egress and sign-in (batch 2026-10-16) ([#572](#572)) ([d67afc2](d67afc2)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements the 15 specs from the 2026-10-11 → 2026-10-16 security scans, plus 3 earlier specs (OVH SMS receipts, worker env vars, LDAP docs). Each spec was implemented, audited against its text, then archived in
specs/done/2026/10/.Security fixes
INVITE_LOGIN_REQUIRED, 403INVITE_EMAIL_MISMATCH).exec/auth-providerkubeconfigs and file references.inClusteris gated bySP_K8S_ALLOW_IN_CLUSTER.${env:}references only resolve names listed inSP_CHECK_ENV_ALLOWLIST. The list is empty by default and is enforced both when a check is saved and when it runs.AllowAllFiles=false, and its dial goes through the egress guard.xms_edov.dockersub-check now obeys the SaaS docker gate and the egress guard.response_urlmust be onhooks.slack.com, and request bodies are capped at 1 MiB.Breaking changes and operator actions
${env:NAME}stops resolving until the name is listed inSP_CHECK_ENV_ALLOWLIST, on the server and on each private agent.SP_SLACK_SIGNING_SECRET. Socket Mode does not.emailandxms_edovoptional ID-token claims. The review query for existing links is inwiki/runbooks/operations-gotchas.md.exec,auth-provideror file references stop working. UsinginClusterneedsSP_K8S_ALLOW_IN_CLUSTER=true.landiscovery is refused, and so iscontainerdiscovery on SaaS shared nodes.SP_EGRESS_ALLOW_PRIVATE, so self-hosted instances accept private/LAN endpoints.@ / ( ) ? & :; a reference can be used instead.SP_SERVER_CHECK_WORKER_NBandSP_SERVER_JOB_WORKER_NBnow take effect.Batch gate
make build-backend lint-back test: 251/0/0 packages, 0 lint issuesmake test-postgres: 251/0/0 packagestypecheck:e2eandlint:e2e: passdiscovery.spec.ts, was a test expectation made stale by the discovery fallback, and it is fixed in e7ce071. Onlydiscovery.spec.tswas re-run (30/0/0), not the full suite.Follow-ups are filed in
specs/backlog/2026-10-16-16to-21.🤖 Generated with Claude Code