other
- Location
scripts/game.mjs:203- Finding
AI Hole Cards Are Disclosed Before Showdown
- Content
View full analysis
Vulnerability Details
File Location:
scripts/game.mjs:203
Vulnerability Type: Premature Sensitive Game-State Disclosure
Risk Level: MediumVulnerable Code
javascript getGameState() { return { round: this.round, phase: this.gamePhase, players: this.players.map(p => ({ id: p.id, position: p.position, chips: p.chips, hand: p.getCardString(!p.isHuman && this.gamePhase !== 'showdown'), isHuman: p.isHuman, isActive: p.isActive, currentBet: p.currentBet })), communityCards: this.communityCards.map(c => `${c.value}${c.suit}`), pot: this.pot, currentBet: this.currentBet, humanPosition: this.smallBlindPos }; }The affected method relies on this card-display logic:
javascript getCardString(showAll = false) { if (this.hand.length === 0) return '??'; if (!showAll && !this.isHuman) return '??'; return this.hand.map(card => `${card.value}${card.suit}`).join(' '); }Technical Analysis
Player.getCardString()hides an AI player's cards only whenshowAllis false. However,getGameState()supplies the following expression as that argument:javascript !p.isHuman && this.gamePhase !== 'showdown'For an AI player during pre-flop, flop, turn, or river, both operands are true. Consequently,
showAllbecomes true and the AI player's complete hand is included in the returned game state.This condition reverses the documented security rule that AI cards must remain represented as
??until showdown. The affected file is particularly significant becausepackage.jsondesignatesscripts/game.mjsas both the package entry point and theholdem-pokerexecutable.Attack Path
- Run the package CLI or import
PokerGamefromscripts/game.mjs. - Create a game and invoke
startNewRound(). - Obtain the state returned by
startNewRound()or callgetGameState()directly. - Inspect the
handfield for each player whoseisHumanpropert ...[truncated 892 chars]
- Run the package CLI or import
- Remediation
View remediation
Remediation Suggestions
Replace the inverted disclosure condition with a phase-only showdown check:
javascript hand: p.getCardString(this.gamePhase === 'showdown'),This preserves visibility of the human player's cards because
getCardString()already permits human cards to be shown, while keeping AI cards hidden until the game reaches showdown.Additionally:
- Add automated tests for every phase:
- AI hands must equal
??duringpre-flop,flop,turn, andriver. - AI hands may be revealed during
showdown. - Human cards should remain visible to the human-facing state.
- AI hands must equal
- Keep one centralized serialization policy for confidential game state rather than constructing visibility conditions independently in multiple scripts.
- Test the package entry point and CLI executable specifically, because both resolve to
scripts/game.mjs. - Review future state fields to ensure private deck contents, undealt cards, and AI decision data are never included in public responses.
- Add automated tests for every phase:
