Files
ChatbotAI/app/Services/KnowledgeBase/PromptGuardService.php
2026-05-31 00:45:19 +08:00

105 lines
3.4 KiB
PHP

<?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];
}
}