Back to skill

Security audit

德州扑克

Security checks for vulnerabilities and agentic risk

Overview

This is a local Texas Hold'em game skill with no evidence of data theft, persistence, or unsafe system access, though one packaged entry point has game-fairness bugs.

Install only if you are comfortable with a simple local Node poker game. Prefer invoking the documented final-game.js path rather than the package bin until the game.mjs card-visibility bug is fixed, and treat the mixed-language notes as documentation quality issues rather than hidden behavior.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
Findings (1)

other

Warning
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: Medium

Vulnerable 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 when showAll is 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, showAll becomes 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 because package.json designates scripts/game.mjs as both the package entry point and the holdem-poker executable.

Attack Path

  1. Run the package CLI or import PokerGame from scripts/game.mjs.
  2. Create a game and invoke startNewRound().
  3. Obtain the state returned by startNewRound() or call getGameState() directly.
  4. Inspect the hand field for each player whose isHuman propert ...[truncated 892 chars]
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:

  1. Add automated tests for every phase:
    • AI hands must equal ?? during pre-flop, flop, turn, and river.
    • AI hands may be revealed during showdown.
    • Human cards should remain visible to the human-facing state.
  2. Keep one centralized serialization policy for confidential game state rather than constructing visibility conditions independently in multiple scripts.
  3. Test the package entry point and CLI executable specifically, because both resolve to scripts/game.mjs.
  4. Review future state fields to ensure private deck contents, undealt cards, and AI decision data are never included in public responses.
Vulnerability Patterns
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (13)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 130)May include surrounding context.

md
import { PokerGame } from './scripts/simple-game.mjs';

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 154)May include surrounding context.

md
import { PokerGame } from './scripts/simple-game.mjs';

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 155)May include surrounding context.

md
- `scripts/game.mjs` - Full interactive CLI version

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 166)May include surrounding context.

md
- 修改`scripts/final-game.js`中的AI弃牌逻辑

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

Using the generic trigger word "start" creates a broad activation surface in chat environments, increasing the chance the skill launches unintentionally during normal conversation. In an agent platform with execution-capable tools, accidental activation can lead to unexpected process execution or confusing state changes even if the documented command itself is benign.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

A substantial section of the skill documentation is written in Chinese while the rest of the file is in English, and the skill does not state that users can choose their preferred language. This creates a language/locale policy concern because it effectively forces a language change without user opt-in or justification.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The code comments and surrounding logic indicate this block is producing 'Showdown Results', where all active hands should be revealed. However, it calls getCardString() without enabling reveal, and that method returns '??' for non-human players unless showAll is true, so AI hole cards are hidden even in showdown output.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
96% confidence
Finding

This code file contains a Chinese-language comment in an otherwise English-language program, which creates a mixed-language experience without any user opt-in or documented locale constraint. The policy specifically calls for flagging language or locale requirements that are imposed without offering a choice or clear justification.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
94% confidence
Finding

The comment at this line uses Chinese in a codebase whose user-facing text is otherwise English, again implying a locale choice without notice or justification. Even though it is not user-facing output, the rule applies to natural-language content in code comments as well.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
94% confidence
Finding

This inline comment uses Chinese without any indication that the skill or repository permits mixed-language source comments. That creates an undocumented language-policy inconsistency covered by the natural-language policy rule.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
97% confidence
Finding

These lines mix Chinese and English in comments, which is a clear locale inconsistency and lacks any explicit opt-in or region-specific justification. The rule applies to comments, so this is a natural-language policy issue even though it does not affect runtime behavior.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
94% confidence
Finding

This comment introduces another unannounced language switch inside the source file. Because the project otherwise appears English-oriented, the mixed locale should be treated as a policy inconsistency unless justified or offered as an explicit choice.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
94% confidence
Finding

The source file continues to mix Chinese comments into an otherwise English program, with no explanation that the skill is region-specific or multilingual by design. That matches the rule's language-policy concern for natural-language content in code files.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.