passbolt/passbolt_api · error · BadRequestException

The Duo state cookie should be a valid UUID.

Error message

The Duo state cookie should be a valid UUID.

What it means

Format guard on the Duo state cookie during MFA callback verification: the cookie value, while a string, does not pass Validation::uuid(), so it cannot be the authentication token id the flow expects and a 400 is raised.

Solutions

  1. Clear MFA cookies and restart the Duo verification flow to mint a fresh UUID state cookie.
  2. Ensure no intermediary truncates or re-encodes the Cookie header.
  3. Avoid manual cookie manipulation; rely on server-generated values.
  4. Reproduce by comparing the cookie value against the UUID format (8-4-4-4-12 hex).
Defensive patterns

Strategy: validation

Validate before calling

const uuidRe = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
if (!uuidRe.test(cookies.passbolt_mfa_duo_state ?? '')) { throw new Error('Duo state cookie is not a valid UUID; restart flow.'); }

Type guard

function isValidUuid(value: unknown): value is string {
  return typeof value === 'string' && /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value);
}

Try / catch

try {
  await duoVerifyCallback();
} catch (e) {
  if (e.status === 400 && /valid UUID/.test(e.message)) {
    clearMfaCookies(); restartDuoVerifyFlow();
  } else { throw e; }
}

Prevention

When it happens

Trigger: GET /mfa/duo/verify/callback with a corrupted, truncated, or forged state cookie value that fails UUID validation.

Common situations: Proxy header truncation; URL encoding mangling the cookie; user-crafted cookies in security testing; leftover cookies from a differently formatted flow.

Understand the failure class

Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.

Related errors


AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17). Data as JSON: /api/errors/ca160b796157f07a. Report an issue: GitHub.

Appendix: source

Thrown at plugins/PassboltCe/MultiFactorAuthentication/src/Controller/Duo/DuoVerifyCallbackGetController.php:188

     *
     * @return string The token id stored in the cookie
     * @throws \Cake\Http\Exception\BadRequestException if the cookie is not defined
     * @throws \Cake\Http\Exception\BadRequestException if the cookie value is not a string
     * @throws \Cake\Http\Exception\BadRequestException if the cookie value is not a valid uuid
     */
    private function consumeAndAssertCookieToken(): string
    {
        $cookieToken = (new MfaDuoStateCookieService())->readDuoStateCookieValue($this->getRequest());
        if (is_null($cookieToken)) {
            throw new BadRequestException(__('A Duo state cookie is required.'));
        }
        $cookieToExpire = new Cookie(MfaDuoStateCookieService::MFA_COOKIE_DUO_STATE);
        $this->setResponse($this->getResponse()->withExpiredCookie($cookieToExpire));

        if (!is_string($cookieToken)) {
            throw new BadRequestException(__('The Duo state cookie value should be a string.'));
        } elseif (!Validation::uuid($cookieToken)) {
            throw new BadRequestException(__('The Duo state cookie should be a valid UUID.'));
        }

        return $cookieToken;
    }

    /**
     * Add to the response the MFA verified cookie.
     *
     * @param \App\Utility\UserAccessControl $uac User access control
     * @param \App\Authenticator\SessionIdentificationServiceInterface $sessionIdentificationService session ID service
     * @return void
     * @throws \Cake\Http\Exception\InternalErrorException if it cannot create MFA cookie
     */
    private function addMfaVerifiedCookieToResponse(
        UserAccessControl $uac,
        SessionIdentificationServiceInterface $sessionIdentificationService
    ): void {
        try {

View on GitHub (pinned to 31c1bbc10f)