hardening
This commit is contained in:
104
app/Services/KnowledgeBase/PromptGuardService.php
Normal file
104
app/Services/KnowledgeBase/PromptGuardService.php
Normal file
@@ -0,0 +1,104 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\KnowledgeBase;
|
||||
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class PromptGuardService
|
||||
{
|
||||
// Soalan yang terlalu pendek atau terlalu panjang
|
||||
private const MIN_LENGTH = 3;
|
||||
private const MAX_LENGTH = 1000;
|
||||
|
||||
private array $patterns = [
|
||||
// Inject arahan baru
|
||||
'instruction_override' => [
|
||||
'/ignore (all |previous |above |prior |your |the )?instructions?/i',
|
||||
'/forget (everything|all|what you|your instructions|your rules)/i',
|
||||
'/override (your |all |previous )?instructions?/i',
|
||||
'/disregard (all |your |previous )?instructions?/i',
|
||||
'/new instruction[s]?:/i',
|
||||
],
|
||||
|
||||
// Ubah persona / roleplay
|
||||
'persona_switch' => [
|
||||
'/you are now\b/i',
|
||||
'/pretend (you are|to be|that you)/i',
|
||||
'/act as (a |an |if |though )/i',
|
||||
'/roleplay as/i',
|
||||
'/from now on (you are|you will|act|behave)/i',
|
||||
'/your (new |true |real )?role is/i',
|
||||
],
|
||||
|
||||
// Jailbreak klasik
|
||||
'known_jailbreak' => [
|
||||
'/\bDAN\b/', // Do Anything Now
|
||||
'/do anything now/i',
|
||||
'/jailbreak/i',
|
||||
'/developer mode/i',
|
||||
'/grandma (trick|exploit|jailbreak)/i',
|
||||
'/token manipulation/i',
|
||||
],
|
||||
|
||||
// Cuba dedah system prompt
|
||||
'prompt_extraction' => [
|
||||
'/what (is|are) your (system |initial |original )?(prompt|instruction)/i',
|
||||
'/show (me |us )?(your )?(system |hidden |secret |original )?prompt/i',
|
||||
'/repeat (your |the )?(system |above |initial )?prompt/i',
|
||||
'/print (your |the )?(system |above |initial )?instructions?/i',
|
||||
'/reveal (your |the )?(system |hidden |secret )?prompt/i',
|
||||
],
|
||||
|
||||
// Token injection
|
||||
'token_injection' => [
|
||||
'/<\|im_start\|>/i',
|
||||
'/<\|im_end\|>/i',
|
||||
'/\[INST\]/i',
|
||||
'/\[\/INST\]/i',
|
||||
'/<<SYS>>/i',
|
||||
'/\[SYSTEM\]/i',
|
||||
'/###\s*System/i',
|
||||
'/###\s*Human/i',
|
||||
'/###\s*Assistant/i',
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* Semak input user. Return array dengan status dan sebab.
|
||||
*
|
||||
* @return array{ blocked: bool, reason: string|null, category: string|null }
|
||||
*/
|
||||
public function check(string $input): array
|
||||
{
|
||||
$input = trim($input);
|
||||
|
||||
if (mb_strlen($input) < self::MIN_LENGTH) {
|
||||
return $this->blocked('Soalan terlalu pendek.', 'too_short');
|
||||
}
|
||||
|
||||
if (mb_strlen($input) > self::MAX_LENGTH) {
|
||||
return $this->blocked('Soalan melebihi had aksara.', 'too_long');
|
||||
}
|
||||
|
||||
foreach ($this->patterns as $category => $categoryPatterns) {
|
||||
foreach ($categoryPatterns as $pattern) {
|
||||
if (preg_match($pattern, $input)) {
|
||||
Log::warning('PromptGuard: input blocked', [
|
||||
'category' => $category,
|
||||
'pattern' => $pattern,
|
||||
'input' => mb_substr($input, 0, 200),
|
||||
]);
|
||||
|
||||
return $this->blocked('Input tidak dibenarkan.', $category);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ['blocked' => false, 'reason' => null, 'category' => null];
|
||||
}
|
||||
|
||||
private function blocked(string $reason, string $category): array
|
||||
{
|
||||
return ['blocked' => true, 'reason' => $reason, 'category' => $category];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user