← All write-ups
September 14, 2026CRITICAL

SAML Assertion Replay leading to Authentication Bypass

Overview

In this write‑up I detail how a replayed SAML assertion can grant an attacker access to a WordPress site that uses the WP Simple SAML plugin. The attack exploits the fact that the plugin stores the raw assertion in a cookie without expiration checks, allowing an attacker to capture and reuse it.

Prerequisites

Steps

  1. Capture the assertion – Use a browser‑network inspector or a tool like wireshark to grab the SAML response cookie after login.
  2. Replay the assertion – Set the same cookie value in another session (or in the same browser after clearing). The WP plugin will treat it as valid and log you in.
  3. Bypass MFA – If MFA is enabled on the IdP, replaying an older assertion still works because the assertion contains the AuthnStatement with the original issue time.

Validation technique

The retest used synthetic assertions and checked the temporal conditions before any session was created. A small verifier should reject an assertion outside its validity window and bind it to the expected audience and recipient:

from datetime import datetime, timezone

def assertion_is_fresh(not_before: datetime, not_on_or_after: datetime) -> bool:
    now = datetime.now(timezone.utc)
    return not_before <= now < not_on_or_after

def require_audience(actual: str, expected: str) -> None:
    if actual != expected:
        raise ValueError("unexpected SAML audience")

For a safe black-box check, use only a synthetic account and an expired fixture; the expected result is a denial rather than a second session. Log the assertion identifier so the service can reject the same identifier twice.

Mitigation