A tenant administrator opens the authenticator-enrollment route for a user it legitimately manages, then replaces only the target user identifier with one from another tenant. The session is valid. The organization header is valid. The registration ceremony succeeds. If the server authorizes against the header but writes the credential to the user record, the request has created a future login path across the tenant boundary.
The protected effect in that sequence is the write to authentication authority. A passkey, security key, authenticator app, or passwordless setup artifact can make later logins look completely legitimate. Review that operation with the same care as a password reset or ownership transfer: bind actor, tenant, target account, recent assurance, enrollment transaction, and final credential record.
Multi-tenant APIs are vulnerable to mixed-context requests because each identifier can be valid on its own. Testing must intentionally combine a valid principal from tenant A, a valid target from tenant B, and every route that can create or recover an authenticator. A denied response is insufficient if a setup code, pending credential, or notification side effect survives.
Key Takeaways
- Adding, replacing, or recovering an authenticator changes who can prove control of an account and must be authorized as a privileged operation.
- Multi-tenant authorization must derive tenant ownership from the target user record, then verify the caller's capability in that tenant; a client-supplied organization context is not authoritative.
- WebAuthn or passkey ceremony validation proves important cryptographic properties, but it does not replace application-level authorization, recent reauthentication, or lifecycle controls.
- Enrollment tests must cover every entry point, including user self-service, administrator assistance, recovery, invitations, support tooling, API endpoints, mobile clients, and legacy routes.
- A secure workflow binds a short-lived, single-use enrollment intent to the acting principal, target user, tenant, authenticator type, purpose, and initiating session.
- Autonomous pentesting adds value when it explores negative identity combinations, verifies protected state, and converts every confirmed issue into a repeatable regression test without using real customer accounts.
Enrollment Changes the Account's Trust Root
An authenticator is not merely a preference. It is evidence the identity system will accept later when deciding whether to create a session. Adding one changes the set of parties and devices capable of satisfying that decision. Removing one can lock out the rightful owner. Replacing one can quietly transfer control. Generating a setup artifact can be just as sensitive as completing enrollment because the artifact may let its holder finish the binding later.
This leads to a simple security invariant:
An authenticator may be bound to target user U in tenant T only when
the authenticated actor P has the required capability over U in T,
has satisfied the required recent authentication strength,
and completes an enrollment intent issued for that exact transition.
Each noun matters. P is the actor making the request, not a user ID taken from the body. U is the target account loaded from trusted storage. T is the tenant that owns or governs U, not whichever organization identifier appears in a header. The capability must cover the operation and target relationship. The authentication strength and recency must match policy. The intent must not be transferable across users, tenants, sessions, or authenticator types.
When code reduces this invariant to a broad check such as caller is org admin, important bindings disappear. An administrator is not an administrator everywhere. A support role may help initiate recovery without being allowed to choose the replacement authenticator. A user who has a valid session may still need to reauthenticate before changing the account's trust root. Correct authorization is always contextual.
Enrollment Is Broader Than the Final Registration Call
Teams often protect the endpoint that stores a credential but overlook earlier steps. Yet a workflow may expose several security-sensitive artifacts:
- A passkey registration challenge.
- A passwordless enrollment code.
- A QR seed for a time-based one-time password authenticator.
- A recovery link that permits authenticator replacement.
- A device activation token.
- A support-generated reset ticket.
- A list of existing authenticators and their metadata.
- An endpoint that marks an authenticator as primary or trusted.
The first request can decide the target, tenant, allowed authenticator type, and policy. If that request is misauthorized, a perfectly implemented final ceremony may faithfully complete an attacker-selected operation. Security testing must follow the whole state transition, not only the last HTTP response.
The Multi-Tenant Confusion Pattern
Multi-tenant applications carry identity context through many layers. A route may look like this:
POST /users/{target_user_id}/authenticators/passkey/initiate
Authorization: Bearer <actor session>
X-Organization-ID: <selected organization>
There are at least three identities in that request: the session principal, the selected organization, and the target user. A vulnerable implementation may verify that the principal is an administrator of the selected organization, then initiate enrollment for the target user without confirming that the selected organization owns that user. Every individual lookup succeeds. The relationship between them is false.
The safer decision order is target-first:
- Authenticate the caller and establish the session principal from server-validated credentials.
- Load the target user by an opaque identifier without yet disclosing sensitive details.
- Resolve the target user's governing tenant from trusted server-side relationships.
- Evaluate whether the principal has the precise enrollment capability over that user in that tenant.
- Enforce self-service, delegated administration, and recovery rules as distinct policies.
- Require suitable reauthentication or approval.
- Issue a transaction-bound enrollment intent.
The client may still send a tenant identifier for routing or user experience. It can narrow a query, but it cannot create authorization. The decisive tenant must be independently derived and compared.
Why Generic Role Checks Fail
Role names hide scope. admin, owner, and support are not complete authorization facts. A decision needs at least:
(actor, actor_tenant_membership, action, target_user, target_tenant, assurance, context)
An organization administrator may manage users in one tenant but only view another. A managed service provider may have delegated access to selected customer groups. A parent organization may administer child tenants under explicit contracts but not sibling tenants. A support operator may initiate an owner-visible recovery flow but never receive or complete the enrollment artifact. Hard-coding a role name next to an endpoint cannot express those relationships safely.
Policy should answer a concrete capability question such as mayInitiateAuthenticatorEnrollment(actor, targetUser, method, context). The function should obtain target ownership internally and return a deny result when any relationship is absent or ambiguous. Denial should not depend on a UI hiding the button.
Cryptographic Ceremony Is Necessary but Not Sufficient
Passkeys and security keys rely on a registration ceremony that binds a new public key credential to an account for a particular relying party. A correct implementation verifies the challenge, origin, relying-party context, credential data, and other ceremony requirements. These checks defend against important classes of phishing, replay, and credential substitution.
They do not decide whether the current actor was permitted to start enrollment for the chosen account.
Imagine an application that correctly generates a random challenge, validates the browser origin, checks the relying-party identifier, and stores a valid public key. If the server associated that challenge with the wrong target user because of an authorization error, the cryptography has not failed. It has securely bound the attacker's key to the victim's account. The application-level transaction was wrong before the ceremony began.
The enrollment record therefore needs context beyond a challenge value:
| Binding field | Security purpose | Negative test |
|---|---|---|
| Acting principal ID | Prevents another session from completing the operation | Start as actor A, complete as actor B |
| Target user ID | Prevents challenge reuse for another account | Swap the target during completion |
| Governing tenant ID | Prevents cross-tenant enrollment | Mix a valid admin tenant with a foreign user |
| Authenticator type | Prevents upgrading a narrow intent into a different method | Initiate one method, complete another |
| Purpose | Separates add, replace, recovery, and admin-assisted flows | Reuse recovery intent for routine addition |
| Session or transaction ID | Limits theft and cross-channel reuse | Complete from an unrelated session |
| Issued and expiry times | Limits the useful replay window | Complete after expiry or clock boundary |
| Used/revoked state | Enforces single consumption | Submit two coordinated completions |
| Policy version | Makes the decision reproducible | Change policy during an outstanding intent |
The intent should be opaque, high entropy, short-lived, stored or integrity-protected, and consumed atomically. If it is encoded in a signed token, signing proves integrity but does not automatically provide revocation or single use. Durable state may still be necessary for high-impact transitions.
User Verification Does Not Equal Application Reauthentication
A platform authenticator may perform local user verification using a biometric or device PIN. That is valuable, but the application should not casually equate it with proof that the currently authenticated web session belongs to the intended account owner. The ceremony and the session have different contexts.
Before adding a new authenticator, policy may require a recent sign-in using an existing approved method, a step-up challenge, or an out-of-band approval. The appropriate requirement depends on account value, available authenticators, recovery conditions, and organizational policy. What matters is that the decision is explicit and testable.
Reauthentication should be bound to the enrollment operation and expire quickly. A session that was strongly authenticated weeks ago should not retain indefinite authority to add new trust anchors. Likewise, changing an email address immediately before using that address to approve enrollment creates a circular recovery path that needs additional controls.
Separate Self-Service, Administration, and Recovery
Many authorization defects begin when one endpoint tries to serve several different business purposes. Authenticator self-service, administrator-assisted enrollment, and account recovery may all end with a credential record, but their trust models differ.
Self-Service Enrollment
The signed-in user adds a method to their own account. The server should require a suitable existing authenticator or recent step-up, confirm that the account and session are not under a risky transition, bind the intent to the same user, and notify the owner through an independent channel. An active session is necessary but may not be sufficient.
Delegated Administrative Assistance
An authorized administrator helps a user enroll or reset a method. The policy must be tenant-scoped and should minimize how much authentication material the administrator can see or control. A safer design lets the administrator initiate an owner-bound, expiring process while the user completes possession and verification. High-value accounts may require a second approver or prohibit delegated enrollment entirely.
Recovery
Recovery exists precisely because the user cannot satisfy the normal authenticator requirement. It therefore needs compensating evidence and stricter monitoring. Recovery should not silently become the easiest way to add an attacker-controlled method. Rate limits, delays for sensitive accounts, independent notifications, risk signals, help-desk verification, revocation of outstanding intents, and reviewable audit records all matter.
Putting these paths behind one boolean such as skipMfa=true obscures the trust change. Separate policy names, endpoints, state transitions, and telemetry make both implementation and testing clearer.
Test Every Path That Can Create Authentication Authority
An inventory is the first practical control. Teams need to enumerate more than web settings pages.
| Entry point | Common risk | Expected invariant |
|---|---|---|
| User settings UI and API | Stale session or target substitution | Actor and target are identical; recent step-up required |
| Tenant admin console | Header or path tenant differs from target ownership | Capability evaluated in target's governing tenant |
| Support portal | Operator receives excessive enrollment power | Support initiates controlled recovery, not direct secret possession |
| Mobile API | Older endpoint enforces weaker policy | Same server-side policy as web and current API |
| Invitation flow | Invite token changes target or role | Token binds tenant, account, role, purpose, and expiry |
| Password reset flow | Reset token also permits unreviewed MFA replacement | Password recovery and authenticator replacement are explicitly governed |
| Device enrollment | Device code can be swapped between accounts | Code binds principal, device, tenant, and transaction |
| Bulk administration | Batch scope crosses tenant boundaries | Every item receives an object-level authorization decision |
| Legacy API | Compatibility route bypasses step-up or audit | No alternate path reaches the effect with weaker controls |
| Internal service call | Service identity is treated as globally trusted | Workload identity and delegated user context are both authorized |
The inventory should trace to the write boundary: the repository method, identity-provider call, or credential store operation that creates the authenticator. If two routes converge on one service, test the policy at that service, not only in route middleware. If a background worker completes enrollment, make sure authorization context cannot be lost between the request and the job.
Include Read and Delete Operations
Listing authenticators can disclose device names, usage times, transport hints, or account security posture. Renaming one can facilitate social engineering. Deleting the last strong authenticator can force recovery. Setting a method as primary can redirect future challenges. Security review should cover the entire lifecycle, with special attention to operations that reduce assurance or suppress owner visibility.
Build a Principal-Tenant-Target Test Matrix
Positive tests prove that intended workflows work. Authorization confidence comes from negative combinations. For each entry point, construct synthetic actors and targets that differ along one dimension at a time.
| Case | Actor relationship | Target | Tenant context supplied | Expected result |
|---|---|---|---|---|
| Self-service control | User | Same user | Correct tenant | Enrollment may proceed after required step-up |
| Same-tenant admin | Authorized admin | Managed member | Correct tenant | Proceed only under delegated enrollment policy |
| Wrong-tenant admin | Admin in tenant A | User in tenant B | Tenant A | Deny without creating an intent |
| Header substitution | Admin in tenant A | User in tenant B | Tenant B | Deny unless explicit cross-tenant delegation exists |
| Ordinary member | Member in tenant A | Another member in tenant A | Tenant A | Deny |
| Read-only support | Support viewer | Customer user | Customer tenant | Deny direct enrollment; allow only defined recovery initiation if applicable |
| Suspended actor | Previously authorized admin | Any managed user | Correct tenant | Deny |
| Suspended target | Authorized actor | Suspended user | Correct tenant | Follow explicit policy; never reactivate implicitly |
| Deleted membership | Former tenant admin | Tenant user | Correct tenant | Deny despite an otherwise valid session |
| Expired intent | Previously authorized actor | Correct target | Correct tenant | Deny and leave credential state unchanged |
| Concurrent completion | Authorized actor | Correct target | Correct tenant | At most one completion commits |
| Reused intent | Authorized actor | Different target | Correct tenant | Deny |
Use opaque IDs that have the same format and similar existence behavior. The goal is to test relationships, not to rely on malformed input. A request containing a real, accessible tenant A and a real, inaccessible user B is much more revealing than a request containing nonsense.
How Autonomous Pentesting Should Validate Enrollment
Authenticator enrollment has a combinatorial state space: roles, tenants, user states, sessions, methods, intents, devices, and completion timing. Automation can explore this space more consistently than a handful of manual happy-path tests, but it needs a security model and a safe environment.
1. Discover the Complete Flow
The test agent maps routes, client calls, schemas, redirects, background jobs, and writes that participate in enrollment. Code awareness helps connect a visible initiation endpoint to a less obvious completion handler or credential repository. Runtime observation confirms which paths are actually reachable.
2. Create Synthetic Identity Fixtures
Use dedicated tenants and non-production accounts: an owner, administrator, ordinary member, suspended administrator, cross-tenant user, support role, and service identity. Give each fixture narrowly documented capabilities. Never use employee or customer accounts for an autonomous enrollment test.
3. Capture a Valid Baseline
Complete the intended flow once with a disposable authenticator. Record the requests, state changes, audit events, and owner notification. A baseline helps the tester mutate relationships without guessing protocol mechanics.
4. Mutate One Trust Binding at a Time
Swap target user IDs, organization headers, session principals, intent tokens, completion sessions, authenticator types, and recovery purposes. Repeat across alternate endpoints. Coordinated agents can attempt double completion at a barrier to test atomic consumption.
5. Observe Protected State
An HTTP denial is not enough if a credential record, pending intent, or recovery artifact was still created. The oracle should inspect the synthetic user's authenticator list, credential ownership, session history, audit log, and notifications. For a permitted action, verify that exactly one expected credential exists and that it belongs to the intended account.
6. Clean Up and Preserve Evidence
Remove disposable credentials and invalidate test sessions. Preserve a redacted evidence package with the actor, target, tenant relations, request shape, policy decision, state before and after, and correlation IDs. Do not retain private key material, biometric data, production tokens, or reusable recovery codes.
This is where a platform such as SecureHup can create practical value without replacing the identity team's judgment: it can help teams turn a complex authorization hypothesis into a verified, replayable result, reduce time spent triaging speculative alerts, and confirm that the same cross-tenant path remains closed after remediation. The user gains faster feedback and clearer evidence about business impact, while the final policy and risk decision remains with the organization.
Evidence Must Prove the Trust Change
The strongest proof is not a successful 200 response and not possession of a challenge. It is a controlled demonstration that an unauthorized actor caused a new authenticator to become usable for a synthetic target account. Even in a test environment, minimize impact: use a dedicated account, a disposable key, a non-sensitive relying party, and immediate cleanup.
A useful evidence bundle includes:
- Test environment and deployment version.
- Entry point and operation purpose.
- Actor ID, actor tenant, roles, and relevant membership state.
- Target user ID and authoritative governing tenant.
- Supplied tenant context and how it differed.
- Required and observed authentication assurance.
- Enrollment intent ID, expiry, purpose, and binding fields, with secrets redacted.
- Credential count and metadata before and after.
- Completion result and whether a new session could be established in the synthetic account.
- Audit and notification records.
- Cleanup confirmation.
- A regression case that reproduces the denied relationship without retaining credential material.
Severity should follow demonstrated authority and preconditions. Cross-tenant durable account access is materially different from receiving a challenge that cannot be completed. Likewise, an administrator already authorized to reset a managed user's authentication has a different risk profile from an ordinary member. Evidence makes those distinctions defensible.
Design the Enforcement Near the Protected Effect
Route middleware is useful for authentication and coarse checks, but it is too easy for alternate routes, workers, or future refactors to bypass. The final service that creates, replaces, or activates an authenticator should require an explicit authorization context and independently verify the invariant.
activateAuthenticator(command, authContext):
actor = authContext.requirePrincipal()
target = users.load(command.targetUserId)
tenant = memberships.governingTenant(target)
policies.requireCapability(
actor=actor,
action="authenticator.activate",
target=target,
tenant=tenant,
assurance=authContext.assurance,
purpose=command.purpose
)
intent = intents.consumeAtomically(
id=command.intentId,
actor=actor.id,
target=target.id,
tenant=tenant.id,
purpose=command.purpose,
session=authContext.sessionId
)
credentials.createFromVerifiedCeremony(intent, command.attestation)
audit.recordSecurityTransition(...)
notifications.enqueueIndependentNotice(...)
This pseudocode is intentionally explicit. The target determines the tenant. Policy receives assurance and purpose. The intent is consumed atomically with exact bindings. Ceremony verification and credential creation happen only after authorization. Audit and notification are part of the security transition, not optional UI features.
Avoid Leaking Cross-Tenant Existence
Authorization failures should not become a user directory. Depending on the product, a request for a nonexistent user and an inaccessible foreign user may need externally indistinguishable responses. Internally, logs should retain enough structured detail for investigation without exposing sensitive account data to the caller.
Do not solve enumeration by skipping authorization diagnostics entirely. Record a stable reason code such as TARGET_TENANT_MISMATCH or INSUFFICIENT_TARGET_CAPABILITY, plus correlation identifiers and policy version. Keep those details in protected telemetry.
Notifications and Audit Are Active Controls
When a new authenticator is added, the account owner should receive a prompt notification through a channel not controlled solely by the newly enrolled method. The message should state what changed, when, approximate context, and how to report or reverse an unexpected action. It should not include reusable secrets.
Notifications shorten attacker dwell time, but they are not authorization. An email after silent takeover does not make the enrollment acceptable. Likewise, an audit log is useful only if it records the true actor and target. Logging the target user as the "user who added a passkey" can erase evidence that an administrator or support operator initiated the action.
Security-event records should distinguish:
- Initiating actor and authentication session.
- Target account.
- Governing tenant.
- Delegated authority or approval chain.
- Enrollment purpose and authenticator class.
- Policy and assurance decisions.
- Initiation, completion, revocation, and failure timestamps.
- Correlation to recovery, support, or administrative tickets.
These records support incident response and also act as a test oracle. If a permitted delegated enrollment cannot be attributed correctly, the workflow is operationally unsafe even if its access check is correct.
Make the Fix Durable in CI/CD
An enrollment authorization bug often returns when a new mobile endpoint, administrative bulk action, or identity-provider adapter is added. A one-time patch to one controller is not enough. Convert the security invariant into tests at several layers.
Policy Unit Tests
Exercise the principal-tenant-target matrix directly. Include membership deletion, suspension, delegated administration, assurance age, recovery purpose, and policy version. Unit tests should be deterministic and exhaustive over meaningful role combinations.
Service Integration Tests
Call the protected enrollment service through each adapter and verify durable state. Ensure background jobs carry immutable actor and target context. Test transaction rollback when credential creation, audit writing, or intent consumption fails.
End-to-End Security Tests
Replay representative negative workflows against a deployed environment. Confirm that no challenge, setup code, pending intent, credential, session, or notification is created for a denied action. Run coordinated completion attempts to establish single-use behavior.
Diff-Aware Replay
Changes touching identity routes, tenant resolution, role policy, session assurance, recovery, credential storage, or client-generated organization context should trigger the relevant suite. A small shared authorization helper can have a much larger blast radius than its line count suggests.
Useful program metrics include the percentage of enrollment paths covered, negative tenant combinations tested, time from code change to security result, unauthorized state mutations observed, stale intents outstanding, notification delivery success, and verified regressions. Counting raw scanner alerts does not measure control quality.
Authenticator Enrollment Review Questions
Before releasing an authenticator enrollment or recovery change, verify the following:
- The target user is loaded from trusted storage before tenant-scoped authorization.
- The governing tenant is derived from the target relationship and compared with any client-supplied context.
- The policy distinguishes self-service, administration, recovery, replacement, and initial bootstrap.
- Recent authentication strength is explicit and appropriate for the transition.
- Registration challenges and setup artifacts bind actor, target, tenant, session, type, purpose, expiry, and policy version.
- Enrollment intents are single-use and consumed atomically.
- Ceremony validation covers the correct relying-party and origin context.
- Alternate web, API, mobile, legacy, support, and worker paths reach the same enforcement layer.
- No denied request creates a usable or pending authentication artifact.
- Credential creation, deletion, replacement, and primary-method changes are attributable in protected audit logs.
- The owner receives an independent notification for security-sensitive changes.
- Recovery cannot be composed with a recent email, password, or profile change to bypass assurance.
- Tests use synthetic tenants and disposable authenticators.
- Confirmed failures become automated regression cases tied to the protected state transition.
Frequently Asked Questions
Is adding a passkey always a high-risk operation?
It is always security-sensitive because it changes which credential can authenticate the account. The required controls can vary by context. Initial enrollment during a tightly controlled account bootstrap may differ from adding a method to an established privileged account, but both need explicit authorization, correct account binding, and auditable lifecycle handling.
Does WebAuthn prevent unauthorized passkey enrollment?
WebAuthn provides cryptographic registration and authentication properties, including challenge and relying-party bindings. It does not decide whether the application selected the correct user or whether the current actor may alter that user's authenticators. Application authorization and transaction binding remain necessary.
Can a tenant administrator enroll MFA for users in the same tenant?
Only if the product's documented policy deliberately grants that capability. Even then, a safer workflow usually lets the administrator initiate an expiring process while the user completes possession and verification. The authorization decision must be scoped to the target user's governing tenant and recorded as a delegated action.
What should an automated test verify after a denied enrollment request?
It should verify protected state, not only the response code. No enrollment intent, challenge with usable authority, credential record, recovery token, authenticated session, or unintended notification should exist. Audit logs should record the denied attempt without leaking foreign-account details to the caller.
How often should authenticator enrollment controls be retested?
Run focused regression tests whenever identity, tenant, role, recovery, session, or credential-management code changes. Also run periodic full-path tests because infrastructure, identity-provider configuration, and alternate clients can change behavior without modifying the central policy code.
Enrollment Writes Future Login Authority
Endpoints, support actions, recovery flows, imports, and background tasks can all add, replace, prioritize, or remove an authenticator. Following authorization to the target account record reveals whether each path applies the required assurance to the acting principal. A synthetic principal-tenant-target matrix is especially useful because every identifier can remain valid while their relationship is not.
Durable state after a denial tells the rest of the story. A credential, challenge, setup token, recovery code, or queued job should not remain capable of completing enrollment later. We would preserve a compact replay for that protected write whenever identity routing, tenant resolution, or authenticator code changes. It is direct evidence about who may create the credentials the system will trust tomorrow.
#IdentitySecurity #Passkeys #MFA #WebAuthn #MultiTenantSecurity #ApplicationSecurity #AutonomousPentesting
Find issues like this in your own codebase
SecureHup runs this exact exploit chain — discovery, enumeration and cross-tenant validation — on every deployment, automatically.