nova-hunting 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Thomas Roccia
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,99 @@
1
+ Metadata-Version: 2.2
2
+ Name: nova-hunting
3
+ Version: 0.1.0
4
+ Summary: Prompt Pattern Matching Framework for Generative AI
5
+ Home-page: https://github.com/fr0gger/nova-framework
6
+ Author: Thomas Roccia
7
+ Author-email: contact@securitybreak.io
8
+ License: MIT
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Operating System :: OS Independent
12
+ Requires-Python: >=3.9
13
+ Description-Content-Type: text/markdown
14
+ License-File: LICENCE
15
+ Requires-Dist: mkdocs-material
16
+ Requires-Dist: mkdocs
17
+ Requires-Dist: mkdocs-material[imaging]
18
+ Requires-Dist: sentence-transformers
19
+ Requires-Dist: transformers
20
+ Requires-Dist: requests
21
+ Requires-Dist: pyyaml
22
+ Requires-Dist: colorama
23
+ Requires-Dist: openai
24
+ Requires-Dist: anthropic
25
+ Requires-Dist: pytest
26
+ Dynamic: author
27
+ Dynamic: author-email
28
+ Dynamic: classifier
29
+ Dynamic: description
30
+ Dynamic: description-content-type
31
+ Dynamic: home-page
32
+ Dynamic: license
33
+ Dynamic: requires-dist
34
+ Dynamic: requires-python
35
+ Dynamic: summary
36
+
37
+ # NOVA: The Prompt Pattern Matching
38
+
39
+ ![GitHub](https://img.shields.io/github/fr0gger/nova-framework)
40
+
41
+ <p align="center">
42
+ <img src="nova_doc/docs/nova.svg" alt="NOVA Logo">
43
+ </p>
44
+
45
+ Generative AI systems are rapidly being adopted and deployed across organizations. While they enhance productivity and efficiency, they also expand the attack surface.
46
+
47
+ How do you detect abusive usage of your system? How do you hunt for malicious prompts? Whether it is identifying jailbreaking attempts, preventing reputational damage, or spotting unexpected behaviors, tracking prompt TTPs can be very useful to track the usage of your AI systems.
48
+
49
+ That's where NOVA comes in!
50
+
51
+ 🚧 **Disclaimer:** NOVA is currently in beta. Expect potential bugs, incomplete features, and ongoing improvements. If you identify a bug, please [report it here](https://github.com/fr0gger/nova-framework/issues).
52
+
53
+ NOVA is an open-source prompt pattern matching system combining keyword detection, semantic similarity, and LLM-based evaluation to analyze and detect prompt content.
54
+
55
+ ## Features
56
+
57
+ - 🔍 **Keyword Detection:** Flag suspicious prompts using predefined keywords or regex.
58
+ - 💬 **Semantic Similarity:** Identify pattern variations using configurable thresholds.
59
+ - ✨ **LLM Matching:** Create matching rules using natural language evaluated by LLM.
60
+
61
+ Inspired by YARA syntax, NOVA rules are readable and flexible, ideal for prompt hunting and threat detection.
62
+
63
+ ## Anatomy of a NOVA Rule
64
+
65
+ ```bash
66
+ rule RuleName
67
+ {
68
+ meta:
69
+ description = "Rule description"
70
+ author = "Author name"
71
+
72
+ keywords:
73
+ $keyword1 = "exact text"
74
+ $keyword2 = /regex pattern/i
75
+
76
+ semantics:
77
+ $semantic1 = "semantic pattern" (0.6)
78
+
79
+ llm:
80
+ $llm_check = "LLM evaluation prompt" (0.7)
81
+
82
+ condition:
83
+ keywords.$keyword1 or semantics.$semantic1 or llm.$llm_check
84
+ }
85
+ ```
86
+
87
+ ## Getting Started
88
+
89
+ ```bash
90
+ pip install nova-framework
91
+ ```
92
+
93
+ ## License
94
+
95
+ This project is licensed under the [MIT License](LICENSE).
96
+
97
+ ## Credits
98
+
99
+ Created and maintained by [fr0gger](https://github.com/fr0gger).
@@ -0,0 +1,63 @@
1
+ # NOVA: The Prompt Pattern Matching
2
+
3
+ ![GitHub](https://img.shields.io/github/fr0gger/nova-framework)
4
+
5
+ <p align="center">
6
+ <img src="nova_doc/docs/nova.svg" alt="NOVA Logo">
7
+ </p>
8
+
9
+ Generative AI systems are rapidly being adopted and deployed across organizations. While they enhance productivity and efficiency, they also expand the attack surface.
10
+
11
+ How do you detect abusive usage of your system? How do you hunt for malicious prompts? Whether it is identifying jailbreaking attempts, preventing reputational damage, or spotting unexpected behaviors, tracking prompt TTPs can be very useful to track the usage of your AI systems.
12
+
13
+ That's where NOVA comes in!
14
+
15
+ 🚧 **Disclaimer:** NOVA is currently in beta. Expect potential bugs, incomplete features, and ongoing improvements. If you identify a bug, please [report it here](https://github.com/fr0gger/nova-framework/issues).
16
+
17
+ NOVA is an open-source prompt pattern matching system combining keyword detection, semantic similarity, and LLM-based evaluation to analyze and detect prompt content.
18
+
19
+ ## Features
20
+
21
+ - 🔍 **Keyword Detection:** Flag suspicious prompts using predefined keywords or regex.
22
+ - 💬 **Semantic Similarity:** Identify pattern variations using configurable thresholds.
23
+ - ✨ **LLM Matching:** Create matching rules using natural language evaluated by LLM.
24
+
25
+ Inspired by YARA syntax, NOVA rules are readable and flexible, ideal for prompt hunting and threat detection.
26
+
27
+ ## Anatomy of a NOVA Rule
28
+
29
+ ```bash
30
+ rule RuleName
31
+ {
32
+ meta:
33
+ description = "Rule description"
34
+ author = "Author name"
35
+
36
+ keywords:
37
+ $keyword1 = "exact text"
38
+ $keyword2 = /regex pattern/i
39
+
40
+ semantics:
41
+ $semantic1 = "semantic pattern" (0.6)
42
+
43
+ llm:
44
+ $llm_check = "LLM evaluation prompt" (0.7)
45
+
46
+ condition:
47
+ keywords.$keyword1 or semantics.$semantic1 or llm.$llm_check
48
+ }
49
+ ```
50
+
51
+ ## Getting Started
52
+
53
+ ```bash
54
+ pip install nova-framework
55
+ ```
56
+
57
+ ## License
58
+
59
+ This project is licensed under the [MIT License](LICENSE).
60
+
61
+ ## Credits
62
+
63
+ Created and maintained by [fr0gger](https://github.com/fr0gger).
@@ -0,0 +1,28 @@
1
+ """
2
+ NOVA: The Prompt Pattern Matching
3
+ Author: Thomas Roccia
4
+ twitter: @fr0gger_
5
+ License: MIT License
6
+ Version: 1.0.0
7
+ Description: Main Nova framework package initialization
8
+ """
9
+
10
+ __version__ = "1.0.0"
11
+
12
+ from nova.core.rules import (
13
+ KeywordPattern,
14
+ SemanticPattern,
15
+ LLMPattern,
16
+ NovaRule
17
+ )
18
+ from nova.core.matcher import NovaMatcher
19
+ from nova.core.parser import NovaParser
20
+
21
+ __all__ = [
22
+ 'KeywordPattern',
23
+ 'SemanticPattern',
24
+ 'LLMPattern',
25
+ 'NovaRule',
26
+ 'NovaMatcher',
27
+ 'NovaParser',
28
+ ]
@@ -0,0 +1,29 @@
1
+ """
2
+ NOVA: The Prompt Pattern Matching
3
+ Author: Thomas Roccia
4
+ twitter: @fr0gger_
5
+ License: MIT License
6
+ Version: 1.0.0
7
+ Description: Core components package initialization
8
+ """
9
+
10
+ from nova.core.rules import (
11
+ KeywordPattern,
12
+ SemanticPattern,
13
+ LLMPattern,
14
+ NovaRule
15
+ )
16
+ from nova.core.matcher import NovaMatcher
17
+ from nova.core.parser import NovaParser, NovaRuleFileParser
18
+ from nova.core.scanner import NovaScanner
19
+
20
+ __all__ = [
21
+ 'KeywordPattern',
22
+ 'SemanticPattern',
23
+ 'LLMPattern',
24
+ 'NovaRule',
25
+ 'NovaMatcher',
26
+ 'NovaParser',
27
+ 'NovaRuleFileParser',
28
+ 'NovaScanner',
29
+ ]
@@ -0,0 +1,198 @@
1
+ """
2
+ NOVA: The Prompt Pattern Matching
3
+ Author: Thomas Roccia
4
+ twitter: @fr0gger_
5
+ License: MIT License
6
+ Version: 1.0.0
7
+ Description: Core matcher implementation for Nova rules
8
+ """
9
+
10
+ from typing import Dict, List, Tuple, Optional, Any
11
+ import re
12
+
13
+ from nova.core.rules import NovaRule, KeywordPattern, SemanticPattern, LLMPattern
14
+ from nova.evaluators.keywords import DefaultKeywordEvaluator
15
+ from nova.evaluators.semantics import DefaultSemanticEvaluator
16
+ from nova.evaluators.llm import OpenAIEvaluator
17
+ from nova.evaluators.condition import evaluate_condition
18
+
19
+
20
+ class NovaMatcher:
21
+ """
22
+ Matcher for Nova rules.
23
+ Evaluates text against rules using different pattern types.
24
+ """
25
+
26
+ def __init__(self,
27
+ rule: NovaRule,
28
+ keyword_evaluator: Optional[DefaultKeywordEvaluator] = None,
29
+ semantic_evaluator: Optional[DefaultSemanticEvaluator] = None,
30
+ llm_evaluator: Optional[OpenAIEvaluator] = None):
31
+ """
32
+ Initialize the matcher with a rule and optional custom evaluators.
33
+
34
+ Args:
35
+ rule: The NovaRule to match against
36
+ keyword_evaluator: Custom keyword evaluator (uses DefaultKeywordEvaluator if None)
37
+ semantic_evaluator: Custom semantic evaluator (uses DefaultSemanticEvaluator if None)
38
+ llm_evaluator: Custom LLM evaluator (uses OpenAIEvaluator if None)
39
+ """
40
+ self.rule = rule
41
+
42
+ # Initialize evaluators
43
+ self.keyword_evaluator = keyword_evaluator or DefaultKeywordEvaluator()
44
+ self.semantic_evaluator = semantic_evaluator or DefaultSemanticEvaluator()
45
+ self.llm_evaluator = llm_evaluator or OpenAIEvaluator()
46
+
47
+ # Pre-compile keyword patterns for performance
48
+ self._precompile_patterns()
49
+
50
+ def _precompile_patterns(self):
51
+ """Pre-compile regex patterns for better performance."""
52
+ for key, pattern in self.rule.keywords.items():
53
+ if pattern.is_regex:
54
+ self.keyword_evaluator.compile_pattern(key, pattern)
55
+
56
+ def check_prompt(self, prompt: str) -> Dict[str, Any]:
57
+ """
58
+ Check if a prompt matches the rule.
59
+
60
+ Args:
61
+ prompt: The prompt text to check
62
+
63
+ Returns:
64
+ Dictionary containing match results and details
65
+ """
66
+ # Get all keyword matches for debugging
67
+ all_keyword_matches = {}
68
+ for key, pattern in self.rule.keywords.items():
69
+ all_keyword_matches[key] = self.keyword_evaluator.evaluate(pattern, prompt, key)
70
+
71
+ # Get all semantic matches for debugging
72
+ all_semantic_matches = {}
73
+ all_semantic_scores = {}
74
+ for key, pattern in self.rule.semantics.items():
75
+ matched, score = self.semantic_evaluator.evaluate(pattern, prompt)
76
+ all_semantic_matches[key] = matched
77
+ all_semantic_scores[key] = score
78
+
79
+ # Get all LLM matches for debugging
80
+ all_llm_matches = {}
81
+ all_llm_scores = {}
82
+ for key, pattern in self.rule.llms.items():
83
+ # Use the pattern's threshold as the temperature parameter
84
+ temperature = pattern.threshold
85
+ matched, confidence, details = self.llm_evaluator.evaluate_prompt(pattern.pattern, prompt, temperature=temperature)
86
+ all_llm_matches[key] = matched # Don't compare confidence to threshold anymore
87
+ all_llm_scores[key] = confidence
88
+
89
+ # For the condition evaluation, only use variables explicitly referenced
90
+ condition = self.rule.condition
91
+
92
+ # Extract variables directly referenced in the condition
93
+ keyword_matches = {}
94
+ semantic_matches = {}
95
+ llm_matches = {}
96
+
97
+ # Check for direct variable references with wildcards (section.$var*)
98
+ for section, var_dict, target_dict in [
99
+ ('keywords', all_keyword_matches, keyword_matches),
100
+ ('semantics', all_semantic_matches, semantic_matches),
101
+ ('llm', all_llm_matches, llm_matches)
102
+ ]:
103
+ # Match exact references like "section.$var"
104
+ pattern = rf'{section}\.\$([a-zA-Z0-9_]+)(?!\*)'
105
+ for match in re.finditer(pattern, condition):
106
+ var_name = f"${match.group(1)}"
107
+ if var_name in var_dict:
108
+ target_dict[var_name] = var_dict[var_name]
109
+
110
+ # Match wildcard references like "section.$var*"
111
+ wildcard_pattern = rf'{section}\.\$([a-zA-Z0-9_]+)\*'
112
+ for match in re.finditer(wildcard_pattern, condition):
113
+ prefix = match.group(1)
114
+ # Add all variables matching this prefix
115
+ for var, value in var_dict.items():
116
+ if var[1:].startswith(prefix): # Remove $ from var name
117
+ target_dict[var] = value
118
+
119
+ # Check for standalone variables ($var)
120
+ var_pattern = r'(?<![a-zA-Z0-9_\.])(\$[a-zA-Z0-9_]+)(?!\*)'
121
+ for match in re.finditer(var_pattern, condition):
122
+ var_name = match.group(1)
123
+
124
+ # Skip if it's already handled as a section.$ reference
125
+ if any(var_name in d for d in [keyword_matches, semantic_matches, llm_matches]):
126
+ continue
127
+
128
+ # Try to find where this variable is defined
129
+ if var_name in all_keyword_matches:
130
+ keyword_matches[var_name] = all_keyword_matches[var_name]
131
+ elif var_name in all_semantic_matches:
132
+ semantic_matches[var_name] = all_semantic_matches[var_name]
133
+ elif var_name in all_llm_matches:
134
+ llm_matches[var_name] = all_llm_matches[var_name]
135
+
136
+ # Handle "any of" wildcards if present
137
+ any_of_pattern = r'any\s+of\s+\(\$([a-zA-Z0-9_]+)\*\)'
138
+ for match in re.finditer(any_of_pattern, condition):
139
+ prefix = match.group(1)
140
+
141
+ # Add variables matching this prefix from all sections
142
+ for var, value in all_keyword_matches.items():
143
+ if var[1:].startswith(prefix): # Remove $ from var name
144
+ keyword_matches[var] = value
145
+
146
+ for var, value in all_semantic_matches.items():
147
+ if var[1:].startswith(prefix):
148
+ semantic_matches[var] = value
149
+
150
+ for var, value in all_llm_matches.items():
151
+ if var[1:].startswith(prefix):
152
+ llm_matches[var] = value
153
+
154
+ # Process section wildcards (keywords.*, semantics.*, llm.*)
155
+ if "keywords.*" in condition:
156
+ keyword_matches.update(all_keyword_matches)
157
+ if "semantics.*" in condition:
158
+ semantic_matches.update(all_semantic_matches)
159
+ if "llm.*" in condition:
160
+ llm_matches.update(all_llm_matches)
161
+
162
+ # Evaluate condition if provided
163
+ has_match = False
164
+ condition_result = None
165
+
166
+ if self.rule.condition:
167
+ # Use the condition evaluator with filtered match types
168
+ condition_result = evaluate_condition(
169
+ self.rule.condition,
170
+ keyword_matches,
171
+ semantic_matches,
172
+ llm_matches
173
+ )
174
+ has_match = condition_result
175
+ else:
176
+ # Fall back to original behavior if no condition is specified
177
+ has_match = any(keyword_matches.values()) or any(semantic_matches.values()) or any(llm_matches.values())
178
+
179
+ # Build results with matching variables only
180
+ results = {
181
+ 'matched': has_match,
182
+ 'rule_name': self.rule.name,
183
+ 'meta': self.rule.meta,
184
+ 'matching_keywords': {k: v for k, v in keyword_matches.items() if v},
185
+ 'matching_semantics': {k: v for k, v in semantic_matches.items() if v},
186
+ 'matching_llm': {k: v for k, v in llm_matches.items() if v},
187
+ 'semantic_scores': all_semantic_scores,
188
+ 'llm_scores': all_llm_scores,
189
+ 'debug': {
190
+ 'condition': self.rule.condition,
191
+ 'condition_result': condition_result,
192
+ 'all_keyword_matches': all_keyword_matches,
193
+ 'all_semantic_matches': all_semantic_matches,
194
+ 'all_llm_matches': all_llm_matches
195
+ }
196
+ }
197
+
198
+ return results