From cda71cf6f3b4a42e79a4417336118b9bc9d789f4 Mon Sep 17 00:00:00 2001 From: "Z. Cliffe Schreuders" Date: Sat, 22 Nov 2025 00:46:56 +0000 Subject: [PATCH] SECURITY: Enforce server-side validation for all PIN/password attempts Critical security fix: PIN and password minigames were falling back to client-side validation when the correct answer was available. This allowed players to bypass security by inspecting client-side code. Changes: - PIN minigame: ALWAYS use server-side validation, never client-side - Password minigame: ALWAYS use server-side validation, never client-side - If API client is unavailable, fail securely by rejecting the attempt - Removed backwards compatibility code that allowed client-side validation Security principle: Never trust the client for authentication/authorization. All PIN and password validation must go through the server. --- .../minigames/password/password-minigame.js | 20 ++++++------------- .../js/minigames/pin/pin-minigame.js | 13 ++++++------ 2 files changed, 13 insertions(+), 20 deletions(-) diff --git a/public/break_escape/js/minigames/password/password-minigame.js b/public/break_escape/js/minigames/password/password-minigame.js index 68ae627..d69ce30 100644 --- a/public/break_escape/js/minigames/password/password-minigame.js +++ b/public/break_escape/js/minigames/password/password-minigame.js @@ -398,23 +398,15 @@ export class PasswordMinigame extends MinigameScene { this.gameData.attempts++; this.attemptsDisplay.textContent = this.gameData.attempts; - // Check if we need server-side validation (correctPassword is null or empty string) + // SECURITY: ALWAYS use server-side validation for password attempts const apiClient = window.ApiClient || window.APIClient; - if ((!this.correctPassword || this.correctPassword === '') && apiClient && gameId) { - console.log('Using server-side validation'); + if (apiClient && gameId) { + console.log('Using server-side validation (security enforced)'); await this.validatePasswordWithServer(enteredPassword); } else { - console.log('Using client-side validation', { - correctPassword: this.correctPassword, - hasApiClient: !!apiClient, - gameId: gameId - }); - // Client-side validation (backwards compatibility) - if (enteredPassword === this.correctPassword) { - this.passwordCorrect(); - } else { - this.passwordIncorrect(); - } + console.error('SECURITY WARNING: API client not available, cannot validate password'); + // Fail securely - reject the attempt if we can't validate with server + this.passwordIncorrect(); } } diff --git a/public/break_escape/js/minigames/pin/pin-minigame.js b/public/break_escape/js/minigames/pin/pin-minigame.js index 2bf4882..6da28b2 100644 --- a/public/break_escape/js/minigames/pin/pin-minigame.js +++ b/public/break_escape/js/minigames/pin/pin-minigame.js @@ -247,17 +247,18 @@ export class PinMinigame extends MinigameScene { this.attemptCount++; - // Check if we need server-side validation (correctPin is null or empty) + // SECURITY: ALWAYS use server-side validation for PIN attempts let isCorrect; const apiClient = window.ApiClient || window.APIClient; const gameId = window.breakEscapeConfig?.gameId; - if ((!this.correctPin || this.correctPin === '') && apiClient && gameId) { - console.log('Using server-side PIN validation'); + + if (apiClient && gameId) { + console.log('Using server-side PIN validation (security enforced)'); isCorrect = await this.validatePinWithServer(this.currentInput); } else { - console.log('Using client-side PIN validation'); - // Client-side validation (backwards compatibility) - isCorrect = this.currentInput === this.correctPin; + console.error('SECURITY WARNING: API client not available, cannot validate PIN'); + // Fail securely - reject the attempt if we can't validate with server + isCorrect = false; } // Record attempt