agent) requests. Bounded custom table with expiry; only used * in direct-inbound mode, so it costs nothing on ordinary requests. */ final class NonceStore { public const TTL_SECONDS = 600; public static function table(): string { global $wpdb; return $wpdb->prefix . 'operanse_nonces'; } public static function install(): void { global $wpdb; $table = self::table(); $charset = $wpdb->get_charset_collate(); // The agent's own table: `%i` quotes its name, and the collation clause is `$wpdb->get_charset_collate()`, WordPress's own // value for this database, not input. $wpdb->query( $wpdb->prepare( 'CREATE TABLE IF NOT EXISTS %i (nonce VARCHAR(64) NOT NULL, expires_at INT UNSIGNED NOT NULL, PRIMARY KEY (nonce), KEY expires_at (expires_at)) ' . $charset, $table ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.NotPrepared -- $charset is $wpdb->get_charset_collate() } /** Returns true if the nonce was unused (and is now recorded). */ public function consume( string $nonce, ?int $now = null ): bool { global $wpdb; $now = $now ?? time(); if ( ! preg_match( '/^[A-Za-z0-9_\-=]{16,64}$/', $nonce ) ) { return false; } self::install(); // Probabilistic purge keeps the table bounded without a separate cron. if ( random_int( 1, 20 ) === 1 ) { $wpdb->query( $wpdb->prepare( 'DELETE FROM %i WHERE expires_at < %d', self::table(), $now ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery } $inserted = $wpdb->query( $wpdb->prepare( 'INSERT IGNORE INTO %i (nonce, expires_at) VALUES (%s, %d)', self::table(), $nonce, $now + self::TTL_SECONDS ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery return $inserted === 1; } }