Coverage for /home/admin/Documents/AI/applications/lexigram-dev/lexigram/experimental/ai/lexigram-ai-guard/src/lexigram/ai/guard/input/injection.py: 59%

29 statements  

« prev     ^ index     » next       coverage.py v7.15.4, created at 2026-08-25 07:19 +0800

1"""Prompt injection detector for input content. 

2 

3Detects attempts to override system instructions, hijack the model, 

4or bypass safety constraints through adversarial phrasing. 

5 

6Detection uses a multi-signal approach: 

7- Keyword/phrase pattern matching (fast, low false-negative rate) 

8- Instruction override detection (``ignore previous``, ``new task:``, etc.) 

9- Role-play jailbreak heuristics (``pretend you are``, ``act as DAN``, etc.) 

10 

11No external model calls are made — detection is purely heuristic and 

12runs synchronously under an async wrapper. For production deployments 

13add an LLM-based classifier as an additional guard. 

14""" 

15 

16from __future__ import annotations 

17 

18import re 

19from typing import TYPE_CHECKING, Any 

20 

21from lexigram.ai.guard.input.base import AbstractInputGuard 

22from lexigram.ai.guard.pipeline.result import GuardCheckResult 

23from lexigram.contracts.ai.guards import GuardResultProtocol 

24from lexigram.result import Ok, Result 

25 

26if TYPE_CHECKING: 

27 from lexigram.contracts.ai.exceptions import GuardError 

28 

29# --------------------------------------------------------------------------- 

30# Heuristic patterns — ordered from most to least specific 

31# --------------------------------------------------------------------------- 

32 

33# Patterns that strongly indicate instruction override attempts 

34_OVERRIDE_PATTERNS: list[re.Pattern[str]] = [ 

35 re.compile(r"ignore\s+(all\s+)?(previous|prior|above)\s+instructions?", re.I), 

36 re.compile( 

37 r"disregard\s+(all\s+)?(previous|prior|above|your)\s+instructions?", re.I 

38 ), 

39 re.compile(r"forget\s+(all\s+)?(previous|prior|above)\s+instructions?", re.I), 

40 re.compile(r"new\s+(instruction|task|command|objective)\s*:", re.I), 

41 re.compile( 

42 r"your\s+(new|actual|real)\s+(instructions?|task|role)\s+(is|are)\s*:", re.I 

43 ), 

44 re.compile(r"override\s+(system|previous|above)\s+(prompt|instructions?)", re.I), 

45] 

46 

47# Role-play / persona jailbreak attempts 

48_ROLEPLAY_PATTERNS: list[re.Pattern[str]] = [ 

49 re.compile( 

50 r"pretend\s+(you\s+are|to\s+be)\s+(an?\s+)?(evil|uncensored|unrestricted|DAN|jailbreak)", 

51 re.I, 

52 ), 

53 re.compile( 

54 r"act\s+as\s+(an?\s+)?(uncensored|unrestricted|evil|DAN|jailbreak)", re.I 

55 ), 

56 re.compile( 

57 r"you\s+are\s+now\s+(an?\s+)?(uncensored|unrestricted|DAN|evil\s+AI)", re.I 

58 ), 

59 re.compile(r"DAN\s+mode", re.I), 

60 re.compile(r"jailbreak\s+(mode|prompt|yourself)", re.I), 

61 re.compile(r"developer\s+mode\s+enabled", re.I), 

62] 

63 

64# Exfiltration / system prompt extraction attempts 

65_EXFILTRATION_PATTERNS: list[re.Pattern[str]] = [ 

66 re.compile( 

67 r"(print|repeat|output|echo|reveal|show|tell\s+me|what\s+(are|is))\s+(your|the)\s+system\s+prompt", 

68 re.I, 

69 ), 

70 re.compile( 

71 r"(print|reveal|output|show|tell\s+me)\s+(your\s+)?(initial|original|base)\s+instructions?", 

72 re.I, 

73 ), 

74 re.compile( 

75 r"what\s+(instructions?|prompts?)\s+(were\s+you|have\s+you\s+been)\s+given", 

76 re.I, 

77 ), 

78] 

79 

80_ALL_PATTERNS: list[tuple[str, list[re.Pattern[str]]]] = [ 

81 ("instruction_override", _OVERRIDE_PATTERNS), 

82 ("roleplay_jailbreak", _ROLEPLAY_PATTERNS), 

83 ("prompt_exfiltration", _EXFILTRATION_PATTERNS), 

84] 

85 

86 

87def _detect_injection(content: str) -> tuple[bool, str, str]: 

88 """Check content for injection patterns. 

89 

90 Args: 

91 content: Text to inspect. 

92 

93 Returns: 

94 Tuple of (detected, category, matched_pattern_description). 

95 """ 

96 for category, patterns in _ALL_PATTERNS: 

97 for pattern in patterns: 

98 match = pattern.search(content) 

99 if match: 

100 return True, category, match.group(0)[:80] 

101 return False, "", "" 

102 

103 

104class PromptInjectionDetector(AbstractInputGuard): 

105 """Heuristic detector for prompt injection and jailbreak attempts. 

106 

107 Blocks or warns on content that attempts to override system 

108 instructions, break out of a persona, or exfiltrate the system prompt. 

109 

110 Args: 

111 action: Action when injection is detected — ``"block"`` (default) 

112 or ``"warn"``. 

113 

114 Example:: 

115 

116 guard = PromptInjectionDetector(action="block") 

117 result = await guard.check(user_message) 

118 if not result.passed: 

119 return Err(InjectionAttemptError()) 

120 """ 

121 

122 def __init__(self, action: str = "block") -> None: 

123 """Initialise the injection detector. 

124 

125 Args: 

126 action: ``"block"`` or ``"warn"``. 

127 """ 

128 super().__init__(action=action) 

129 

130 async def check( 

131 self, 

132 content: str, 

133 *, 

134 messages: list[Any] | None = None, 

135 metadata: dict[str, Any] | None = None, 

136 ) -> Result[GuardResultProtocol, GuardError]: 

137 """Evaluate content for prompt injection attempts. 

138 

139 Args: 

140 content: User-supplied text to check. 

141 messages: Optional structured messages for context. 

142 metadata: Optional request metadata. 

143 

144 Returns: 

145 BLOCK or WARN if injection detected, PASS otherwise. 

146 """ 

147 detected, category, matched = _detect_injection(content) 

148 

149 if not detected: 

150 return Ok(GuardCheckResult.allow(self.name)) 

151 

152 if self._action == "warn": 

153 return Ok( 

154 GuardCheckResult.warn( 

155 self.name, 

156 reason=f"Potential prompt injection detected ({category})", 

157 category=category, 

158 matched_fragment=matched, 

159 ) 

160 ) 

161 

162 return Ok( 

163 GuardCheckResult.block( 

164 self.name, 

165 reason=f"Prompt injection attempt detected ({category})", 

166 category=category, 

167 matched_fragment=matched, 

168 ) 

169 ) 

170 

171 

172__all__ = ["PromptInjectionDetector"]