// InjectScan rule set. Every rule is a documented, inspectable regular expression with a weight in (0, 1).
// Rules run on a normalized copy of the input (NFKC, invisible characters removed, common Cyrillic/Greek
// look-alikes folded to Latin, lower-cased); `cs: true` rules run on the normalized text before lower-casing.
// Weights are combined with a noisy-OR (see detect.js), so one strong signal or several weak ones raise the score.
// Bump RULESET_VERSION whenever a rule or weight changes: results are deterministic per version.
export const RULESET_VERSION = '2026.10.1';
export const CATEGORIES = {
instruction_override: 'Tries to cancel or replace the instructions the model is following ("ignore all previous instructions").',
jailbreak: 'Known jailbreak personas and "no rules" framing (DAN, developer mode, unfiltered, never refuse).',
system_prompt_extraction: 'Asks the model to reveal its system prompt, hidden instructions or secrets.',
role_spoofing: 'Fake chat-template tokens, fake system/assistant turns or "end of prompt" delimiters.',
data_exfiltration: 'Moves data out: markdown images or links with data in the URL, collector domains, "send the conversation/keys to ...", sensitive file paths.',
tool_hijack: 'Tries to make an agent call tools, run shell commands, approve or transfer funds, or skip confirmation.',
concealment: 'Tells the model to hide what it is doing from the user.',
hidden_text: 'Invisible or disguised text: zero-width characters, Unicode tag characters, bidi overrides, homoglyphs, hidden HTML.',
encoded_payload: 'Base64, hex or escaped payloads that decode to instructions, or requests to decode and obey.',
social_engineering: 'Fake authority or urgency ("I am your developer", "admin override", "this is very important").',
};
const r = (id, category, weight, re, description, extra = {}) => ({ id, category, weight, re, description, ...extra });
export const RULES = [
// ---- instruction override (EN) ----
r('override.ignore_previous', 'instruction_override', 0.8,
/\b(ignore|disregard|forget|neglect|abandon|discard|overrule)\b[^.\n]{0,40}?\b(all|any|every|the|your|my|these|those|prior|previous|preceding|above|earlier|initial|original|system|existing|old|current)\b[^.\n]{0,30}?\b(instructions?|prompts?|rules?|directions?|directives?|guidelines?|commands?|guardrails?|constraints?|programming|tasks?|assignments?)\b/g,
'Ignore / disregard / forget the previous instructions.'),
r('override.drop_instructions', 'instruction_override', 0.6,
/\b(drop|remove|delete|erase|clear|wipe|override|bypass)\b\s+(all\s+)?(of\s+)?(your|the|my|previous|prior|above|earlier|all)\s+(previous\s+|prior\s+|earlier\s+|current\s+|system\s+)?(instructions|prompts?|tasks|directives|programming|memory|system prompt)\b/g,
'Drop / remove / override your instructions.'),
r('override.forget_everything', 'instruction_override', 0.65,
/\b(forget|ignore|disregard)\s+(about\s+)?(everything|all(?=\s*(and\b|then\b|[,.;:!?]|$))|all (of )?(that|this|the above|above|before|i said|we discussed)|what (i|you|we) (have )?(said|told|wrote|discussed|talked about))\b/g,
'Forget everything / all of the above.'),
r('override.new_instructions', 'instruction_override', 0.5,
/\b(new|updated|real|actual|revised|true)\s+(instructions?|task|assignment|rules|orders|directives?|system prompt)\s*(:|are\b|is\b|follow)/g,
'Announces "new instructions" / "your real task is".'),
r('override.pivot_task', 'instruction_override', 0.55,
/\b(well done|very good|great|excellent|perfect|superb(ly done)?|good job|nice( work)?|congratulations|thank you|thanks|okay|ok|alright)\b[^\n]{0,60}?\b(now|but now|next)\b[^\n]{0,40}?\b(new|next|further|another|additional|other|different|following)\s+(tasks?|assignments?|challenges?|instructions?|jobs?)\b/g,
'Praise-then-pivot to a new task (classic goal hijack).'),
r('override.from_now_on', 'instruction_override', 0.2, /\b(from now on|henceforth|starting now|from this point (on|forward))\b/g, '"From now on ..."'),
r('override.do_not_follow', 'instruction_override', 0.6,
/\b(do not|don'?t|never|no longer|stop)\s+(follow|obey|comply with|adhere to|listen to|respect)(ing)?\b[^.\n]{0,30}\b(instructions?|rules?|guidelines?|polic(y|ies)|programming|developers?|openai|anthropic|system)\b/g,
'Do not follow your rules / guidelines.'),
r('override.was_a_test', 'instruction_override', 0.45, /\b(the (above|previous)( instructions?)?|that|everything (above|before))\s+(was|were|is)\s+(just\s+)?(a test|fake|a joke|not real|irrelevant|cancelled|void)\b/g, '"The above was just a test."'),
r('override.instead', 'instruction_override', 0.2, /\binstead,?\s+(you (should|must|will)|just\s+)?(say|write|answer|respond|output|print|reply|tell)\b/g, '"Instead, say/write ..." (weak).'),
r('override.just_say', 'instruction_override', 0.35, /\b(only|just)\s+(say|output|print|reply with|respond with|answer with|write)\s+["'“]/g, 'Forces a fixed output: "just say \'...\'".'),
r('override.ignore_above', 'instruction_override', 0.6, /\b(ignore|disregard|forget|never ?mind)\s+(the\s+|all\s+)?(above|previous|prior|preceding|everything( above| before)?)\b(?=\s*(and\b|then\b|[,.;:!?]|$))/g, '"Ignore the above" (short form).'),
r('override.change_instructions', 'instruction_override', 0.55, /\b(change|replace|update|rewrite|modify|reset)\s+(all\s+)?your\s+(instructions|rules|prompt|programming|guidelines|directives)\b|\b(change|replace)\s+(the|your)\s+(instructions|rules|prompt)\s+to the following\b|\byour (new )?(instructions|task|job|purpose|directive)s? (is|are) now\b/g, '"Change your instructions to ..." / "Your instructions are now ...".'),
r('override.inline_instruction', 'instruction_override', 0.35, /(\n|\\n|[.!?])\s*(additional |new |extra |system )?(instruction|instructions|befehl|anweisung)\s*[:\-–]\s*\S/g, 'An inline "Instruction:" line inside content.'),
r('override.stop_marker', 'instruction_override', 0.45, /\b(stop|stopp|halt|attention|achtung)\s*[-:!—–]+\s*(stop|stopp|write|schreib|say|sag|i |ich |now|jetzt)/g, '"Attention - stop - ..." / "stop: write ..." interruption.'),
r('override.despite_told', 'instruction_override', 0.55, /\b(despite|regardless of|no matter) what (you('ve| have) been|you were|i) (told|instructed|said)\b|\bthe (instructions|rules) (you were given|above) (no longer apply|are void|do not apply)\b/g, '"Despite what you have been told ..."'),
r('override.ignore_context', 'instruction_override', 0.4, /\b(disregarding|ignoring|not (by|from|based on)|instead of|without (using|looking at))\s+(the\s+)?(articles?|documents?|provided context|context|sources|search results|retrieved (text|documents))\b/g, 'Tells a RAG system to ignore its retrieved context.'),
r('override.repeat_after_me', 'instruction_override', 0.25, /\brepeat after me\b|\bsprich mir nach\b/g, '"Repeat after me ..."'),
r('override.task_done_pivot', 'instruction_override', 0.5, /\b(that is|that's|this is|das ist|das genügt|das reicht)\s+(done|enough|finished|complete|erledigt|genug)\b[^\n]{0,40}?\b(now|nun|jetzt)\b/g, '"That is done. Now ..." pivot.'),
r('override.ignore_previous_de2', 'instruction_override', 0.65, /\b(obigen|vorherigen|bisherigen|vorangegangenen|vorigen)\b[^.\n]{0,40}\b(ignorieren|vergessen|missachten)\b|\babweichend (zu|von) (den )?(vorherigen|bisherigen|obigen)\b|\b(bisherigen|vorherigen) (informationen|anweisungen|instruktionen)\b[^.\n]{0,50}\b(irrelevant|unwichtig|ungültig|nicht (ganz )?(großartig|wichtig|relevant))/g, 'German: die obigen Ausführungen ignorieren / abweichend zu vorherigen Instruktionen.'),
r('override.ignore_previous_ru_hr', 'instruction_override', 0.7, /(забудь(те)?|игнорируй(те)?|не обращай(те)? внимания)[^.\n]{0,30}(инструкци|указани|всё|все|правил)|\b(zaboravi|ignoriraj|ignoriši|zapomnij|zignoruj)\b[^.\n]{0,30}\b(instrukcije|upute|uputstva|sve|instrukcje|polecenia|wszystko)\b/g, 'Russian / Croatian / Polish: forget all instructions.'),
r('override.olvidar_es', 'instruction_override', 0.6, /\b(olvidar|olvídate de|olvidate de)\s+(todo|todas|las instrucciones)\b/g, 'Spanish: olvidar todo.'),
// ---- instruction override (DE / ES / FR / IT / PT) ----
r('override.ignore_previous_de', 'instruction_override', 0.75,
/\b(ignoriere|ignorier|ignorieren sie|vergiss|vergesse|vergessen sie|missachte|überspringe)\b[^.\n]{0,50}?\b(alles|alle|vorherigen?|bisherigen?|obigen?|vorangegangenen?|vorigen?|anweisungen|instruktionen|befehle|regeln|aufgaben?|gesagte)\b/g,
'German: ignoriere / vergiss alle vorherigen Anweisungen.'),
r('override.new_task_de', 'instruction_override', 0.4, /\b(neue|nächste|weitere|andere)\s+(aufgabe|aufgaben|anweisung|anweisungen|herausforderung|instruktionen)\b/g, 'German: neue Aufgabe / neue Anweisungen.'),
r('override.pivot_de', 'instruction_override', 0.3, /\b(sehr gut|gut gemacht|toll|super|hervorragend|ausgezeichnet|perfekt|klasse|prima|wunderbar|danke)\b[^\n]{0,60}?\b(jetzt|nun|aber)\b/g, 'German: praise then "jetzt/nun ..." pivot.'),
r('override.from_now_de', 'instruction_override', 0.25, /\bab (jetzt|sofort|nun)\b/g, 'German: ab jetzt.'),
r('override.ignore_previous_es', 'instruction_override', 0.7, /\b(ignora|olvida|olvide|descarta|omite)\b[^.\n]{0,40}\b(instrucciones|anteriores|previas|todo lo anterior|reglas)\b/g, 'Spanish: ignora las instrucciones anteriores.'),
r('override.ignore_previous_fr', 'instruction_override', 0.7, /\b(ignorez|ignore[rz]? (les|toutes|tout)|oublie[zr]?|ne tiens? pas compte)\b[^.\n]{0,40}\b(instructions|précédentes|tout ce qui précède|règles|consignes)\b/g, 'French: ignore les instructions précédentes.'),
r('override.ignore_previous_it_pt', 'instruction_override', 0.7, /\b(ignora|dimentica|esqueça|esqueca)\b[^.\n]{0,40}\b(istruzioni|precedenti|instruções|instrucoes|regras|regole)\b/g, 'Italian/Portuguese: ignora le istruzioni precedenti.'),
// ---- jailbreak personas and framing ----
r('jailbreak.known_names', 'jailbreak', 0.7,
/\b(do anything now|developer mode (enabled|output|on|activated)|(chatgpt|gpt|ai|assistant) (with|in) developer mode|enable developer mode|jailbreak(ed|s|ing)? (prompt|mode|mode enabled)|jailbroken|you are jailbroken|evil (confidant|trusted confidant)|unfiltered and amoral|mongo tom|god ?mode (enabled|activated)|anti-?gpt|betterdan|opposite mode|chaos mode|unlocked mode|no-?filter mode)\b/g,
'Names of well-known jailbreaks (DAN "Do Anything Now", Developer Mode enabled, Evil Confidant, ...).'),
r('jailbreak.jailbreak_word', 'jailbreak', 0.3, /\bjailbr(eak|oken)\b/g, 'The word jailbreak / jailbroken (weak alone: also used in phone and security docs).'),
r('jailbreak.persona_acronym', 'jailbreak', 0.4, /\b(DAN|STAN|DUDE|AIM|BetterDAN|APOPHIS|UCAR|NRAF)\b(?=[^\n]{0,80}\b(mode|persona|character|stands for|which stands|[Cc]hat[Gg][Pp][Tt]|GPT|jailbr\w*|restrictions|filters|can do anything|policy|policies)\b)|\b(as|you are|act as|called|named|pretend to be|become|play)\s+(a |an )?(DAN|STAN|DUDE|AIM|BetterDAN|APOPHIS|UCAR|NRAF)\b/g, 'Jailbreak persona acronyms (DAN, STAN, DUDE, AIM, ...) in a persona context.', { cs: true }),
r('jailbreak.no_restrictions', 'jailbreak', 0.5,
/\b(you|you're|your|yourself|ai|assistant|chatgpt|gpt|model|bot|persona|character|he|she|it)\b[^.\n]{0,30}\b(no|without|free (of|from)|not (bound|restrained|constrained|limited|governed|restricted) by|unrestrained by|free (itself|yourself|himself|herself) from|break(s)? (free )?(of|from)|don'?t have|doesn'?t have|do not have|does not have|ignores?|removes?|unrestricted by|outside)\b[^.\n]{0,20}\b(any\s+)?(confines|restrictions|limitations|filters|filtering|censorship|guidelines|ethics|ethical (guidelines|principles|constraints)|morals|morality|virtues|safeguards|content polic(y|ies)|usage polic(y|ies)|safety (rules|guidelines|measures|filters))\b/g,
'Says the model/persona has no restrictions, filters or ethics.'),
r('jailbreak.no_restrictions_generic', 'jailbreak', 0.2, /\b(without (any )?|no )(restrictions|limitations|filters|censorship|ethics|morals)\b/g, '"No restrictions / without censorship" without an AI subject (weak).'),
r('jailbreak.unfiltered', 'jailbreak', 0.25,
/\b(unfiltered|uncensored|unrestricted|amoral|unethical|immoral|without (any )?(ethical|moral)|no (ethical|moral)|unhinged|no longer (bound|restricted|limited))\b/g,
'Unfiltered / uncensored / amoral framing.'),
r('jailbreak.policy_mention', 'jailbreak', 0.2, /\b(openai|anthropic|google|meta|content|usage|safety)('s)?\s+(content\s+|usage\s+|safety\s+)?(polic(y|ies)|guidelines|filters?)\b/g, 'References the provider content policy (usually to escape it).'),
r('jailbreak.never_refuse', 'jailbreak', 0.45,
/\b(never|not|won'?t|will not|cannot|can'?t|must not|shall not|isn'?t allowed to|is not allowed to)\s+(ever\s+)?(refuse|decline|say no|reject|deny)\b|\bnever (says?|tells?|responds?|replies?)\b[^.\n]{0,25}\b(can'?t|cannot|sorry|unable|as an ai)\b|\b(always|must) (answer|comply|respond)\b[^.\n]{0,30}\b(no matter|regardless|even if)\b/g,
'Never refuse / always comply regardless.'),
r('jailbreak.you_are_now', 'jailbreak', 0.35, /\byou (are|will be|'re) (now|no longer|going to (act|be|pretend))\b|\bnow,? you are\b|\byou('re| are) (free|liberated|unchained|released)\b/g, '"You are now ..." persona switch.'),
r('jailbreak.pretend', 'jailbreak', 0.12, /\b(pretend|imagine|act|behave|roleplay|role-play|simulate)\b[^.\n]{0,25}\b(you are|you're|to be|as if you|as an?|like an?)\b/g, 'Role-play framing (weak; very common in benign prompts).'),
r('jailbreak.stay_in_character', 'jailbreak', 0.35,
/\b(stay|remain|keep) in character\b|\bbreak(ing)? character\b|\btokens?\b[^.\n]{0,30}\b(deducted|lose|lost|will die|cease to exist)\b|\bstay a (dan|[a-z]+)\b/g,
'Stay in character / token-penalty games used by DAN-style prompts.'),
r('jailbreak.dual_response', 'jailbreak', 0.5,
/\b(two|2|both)\s+(different\s+|separate\s+)?(responses|answers|paragraphs|outputs)\b[^\n]{0,100}\b(normal|classic|standard|filtered|unfiltered|jailbr|developer|dan)\b|\[(🔒|🔓)\s*[a-z ]+\]|\((🔒|🔓)/g,
'Asks for a "normal" and an "unfiltered" answer side by side.'),
r('jailbreak.harmful_hypothetical', 'jailbreak', 0.35,
/\b(hypothetical(ly)?|fictional|in a (story|novel|movie|screenplay)|for (educational|research|academic) purposes( only)?)\b[^\n]{0,80}\b(how to (make|build|create|synthesi[sz]e|hack|steal)|bombs?|weapons?|malware|meth|explosives?|kill)\b/g,
'Fiction or "educational" framing around clearly harmful requests.'),
r('jailbreak.anything_goes', 'jailbreak', 0.3, /\b((nsfw|explicit|uncensored|graphic)( content| generations?| responses?| output)? (is|are) (allowed|permitted|enabled|ok)|allow(ing)? (nsfw|explicit) content|anything (goes|you want)|any (request|question) (no matter|regardless)|(illegal|harmful|offensive|explicit|nsfw|immoral) (content|things|stuff|requests?|activities))\b/g, '"Anything goes" / illegal or explicit content allowed.'),
r('jailbreak.act_as_de', 'jailbreak', 0.3, /\b(tu so,? als|stell dir vor,? du bist|du bist (jetzt|nun|ab jetzt|ab sofort)|(jetzt|nun) bist du|agiere als|verhalte dich (wie|als))\b/g, 'German role-switch ("tu so, als ob", "du bist jetzt").'),
r('jailbreak.evil_ai', 'jailbreak', 0.35, /\b(böse|evil|malicious|rogue|unaligned|sinister)\s+(ki|ai|assistant|bot|chatbot|version of (yourself|you))\b/g, 'Asks the model to be an evil / rogue AI.'),
r('jailbreak.dual_persona', 'jailbreak', 0.3, /\b(two|2|both)\s+(different\s+|separate\s+)?(personalities|entities|persons|personas|alter egos|modes)\b|\balter ego\b/g, 'Split-personality framing ("two entities", "alter ego").'),
r('jailbreak.token_smuggling', 'jailbreak', 0.5, /\$\s?term\d\s*=|\bauto_regressive_modell?ing\b|\bsimple_function\s*\(/g, 'Known token-smuggling templates ($Term1 = ..., auto_regressive_modelling).'),
r('jailbreak.refuse_then_comply', 'jailbreak', 0.5, /\b(answer|explain|say|state)\s+(briefly\s+)?why you can'?t\b[^\n]{0,120}\b(then|after that|but then)\b/g, '"First explain why you can\'t, then answer anyway".'),
r('jailbreak.disown_views', 'jailbreak', 0.4, /\b(do not|don'?t|does not|doesn'?t) (align|reflect|represent)( with)? (the )?(views|values|policies|opinions) of (openai|anthropic|google|meta|your (creators|developers))\b/g, '"These views do not align with OpenAI".'),
// ---- system prompt extraction ----
r('extract.system_prompt', 'system_prompt_extraction', 0.7,
/\b(reveal|show|print|display|output|repeat|tell me|give me|share|leak|dump|write out|recite|spell[- ]?check|translate|summari[sz]e|paste|return)\b[^.\n]{0,40}\b(system|initial|original|hidden|secret|internal|developer|pre-?|full|entire)\s*(prompt|instructions?|message|directives?|configuration|rules)\b/g,
'Reveal / print your system prompt or hidden instructions.'),
r('extract.above_prompt', 'system_prompt_extraction', 0.55,
/\b(print|repeat|output|show|reveal|return|spell[- ]?check|translate|copy|write)\b[^.\n]{0,25}\b(the |your |all )?((above|previous|preceding|prior) (prompt|text|instructions?|message|conversation|words)|(entire|full|whole) (prompt|instructions|system message|conversation))\b/g,
'Print / repeat the text above (prompt leaking).'),
r('extract.what_instructions', 'system_prompt_extraction', 0.45, /\bwhat (are|were|is) (your|the) (initial |original |system |exact |hidden |secret )?(instructions|rules|guidelines|prompt|system prompt|directives)\b/g, '"What were your instructions?"'),
r('extract.verbatim', 'system_prompt_extraction', 0.2, /\b(verbatim|word for word|everything (written )?above|starting (with|from) ["'“]?you are)\b/g, 'Verbatim / "everything above" / "starting with You are".'),
r('extract.secret', 'system_prompt_extraction', 0.4, /\b(what is|tell me|reveal|give me|share|spell|print)\b[^.\n]{0,15}\b(the|your)\s+(password|secret( word| key)?|passphrase|api key|access token|private key)\b/g, 'Asks for the password / secret / key.'),
r('extract.prompt_de', 'system_prompt_extraction', 0.5, /\b(zeig|zeige|gib|nenne|wiederhole|drucke|verrate)\b[^.\n]{0,30}\b(prompt|anweisungen|systemnachricht|systemprompt|passwort)\b/g, 'German: zeig mir deine Anweisungen / dein Passwort.'),
r('extract.written_above', 'system_prompt_extraction', 0.5, /\bwhat (is|was) (written|said|stated|typed) (above|before)\b|\b(sentences?|lines?|text|words) (before|preceding) (the|this) (text|prompt|message)\b|\binformation in the prompt\b/g, '"What is written above?" / "the sentences before the text".'),
// ---- role spoofing / delimiters ----
r('spoof.chat_tokens', 'role_spoofing', 0.8, /<\|(im_start|im_end|system|user|assistant|endoftext|eot_id|start_header_id|end_header_id|begin_of_text)\|>/g, 'Raw chat-template tokens (<|im_start|>, <|eot_id|>, ...).'),
r('spoof.tags', 'role_spoofing', 0.55, /<\/?\s*(system|sys|system_prompt|instructions?|admin|developer|im_start)\s*>|\[\/?(system|inst|sys)\]|<<\/?sys>>/g, 'Fake <system>, [INST], <<SYS>> wrappers.'),
r('spoof.turns', 'role_spoofing', 0.3, /(^|\n)\s*(system|assistant|ai|human|user|developer)\s*:\s*\S/g, 'Fake "System:" / "Assistant:" turns inside content.'),
r('spoof.end_marker', 'role_spoofing', 0.5,
/\bend of (the )?(prompt|instructions?|input|document|context|system message|user input|conversation)\b|(={3,}|-{3,}|#{3,})\s*(end\b|new (instructions?|task|prompt|session)\b)|\\n\\n\s*=+/g,
'"END OF PROMPT", "=== new instructions" delimiters.'),
r('spoof.instruction_header', 'role_spoofing', 0.2, /(^|\n)\s*#{1,4}\s*(new |system |important |admin |updated )?(instructions?|system prompt|rules|response)\s*:?\s*(\n|$)/g, 'Markdown "### Instructions" header inside content.'),
// ---- data exfiltration ----
r('exfil.markdown_image_data', 'data_exfiltration', 0.6, /!\[[^\]\n]{0,100}\]\(\s*https?:\/\/[^\s)]+[?&](data|conversation|convo|history|chat|secret|prompt|summary|leak|exfil|memory|context|pii|email|password|creds?|payload)=[^\s)&]{8,}[^\s)]*\)/g, 'Markdown image whose URL carries data in a query parameter (the request leaks it when rendered).'),
r('exfil.markdown_image_any', 'data_exfiltration', 0.05, /!\[[^\]\n]{0,100}\]\(\s*https?:\/\/[^\s)]+\?[^\s)]*=[^\s)]*\)/g, 'Markdown image with query parameters (informational; badges look like this).'),
r('exfil.url_template', 'data_exfiltration', 0.65,
/https?:\/\/[^\s"'<>]+?(\{\{?\s*(data|conversation|chat|history|secrets?|password|summary|context|messages?|memory|prompt|system_prompt|user_?(data|info|input)|email|api_?key|keys?|tokens?|credentials|info|pii|response|answer)\s*\}?\}|(?<=[=/])\[(data|secret|conversation|info|summary|history|password|key|token|email)[^\]]{0,30}\]|(?<=[=/])<(data|secret|conversation|summary)[^>]{0,20}>|\$\{?(data|secrets?|conversation|history|api_?key|token|password|summary|context|memory)\}?)/g,
'URL with a placeholder to be filled with data ({conversation}, [DATA], $SECRET).'),
r('exfil.collector_domain', 'data_exfiltration', 0.3,
/\b(webhook\.site|requestbin\.(com|net)|pipedream\.net|ngrok(-free)?\.(io|app|dev)|burpcollaborator\.net|oast\.(fun|me|pro|live|site|online)|interact\.sh|canarytokens\.(com|org)|beeceptor\.com|hookbin\.com|requestcatcher\.com|postb\.in|ptsv2\.com|webhook\.cool|trycloudflare\.com|serveo\.net|localtunnel\.me)\b/g,
'Known request-collector / tunnel domains.'),
r('exfil.send_data', 'data_exfiltration', 0.7,
/\b(send|post|upload|transmit|forward|exfiltrate|leak|email|submit|append|include|embed|encode|copy)\b[^.\n]{0,40}\b(conversation|chat history|history|previous messages|context|system prompt|secrets?|credentials?|passwords?|api[ _-]?keys?|tokens?|private keys?|seed phrase|mnemonic|cookies?|session|personal (data|information)|user data|env(ironment)? variables?|\.env|files?)\b[^.\n]{0,40}\b(to|into|via|at|in)\b[^.\n]{0,25}(https?:\/\/|\burl\b|endpoint|server|webhook|address|e-?mail|link|image|0x[0-9a-f]{6})/g,
'Send the conversation / keys / files to a URL, address or e-mail.'),
r('exfil.sensitive_paths', 'data_exfiltration', 0.25, /(~\/\.ssh\b|\bid_rsa\b|\bid_ed25519\b|\.aws\/credentials|\/etc\/(passwd|shadow)\b|\bmcp\.json\b|\.npmrc\b|\.git-credentials\b|\bwallet\.dat\b|\.bash_history\b|\.cursor\/mcp|claude_desktop_config\.json)/g, 'Sensitive file paths (SSH keys, cloud credentials, MCP configs). Weak alone: docs mention them.'),
r('exfil.read_secrets', 'data_exfiltration', 0.65, /\b(read|cat|open|send|upload|include|attach|copy|print|paste|leak|post|share|exfiltrate|give me)\b[^.\n]{0,40}(~\/\.ssh|\bid_rsa\b|\bid_ed25519\b|\.aws\/credentials|\/etc\/passwd|(^|[\s"'`/])\.env\b|\bmcp\.json\b|\.npmrc|\.git-credentials|wallet\.dat|seed phrase|private keys?|api[ _-]?keys?|\bsecrets\b)[^.\n]{0,60}\b(to|into|in your (reply|response|answer)|as|with the|and (pass|send|include|attach|put|return|upload))\b/g, 'Read a secret file / key and pass it somewhere.'),
r('exfil.wallet_secrets', 'data_exfiltration', 0.2, /\b(seed phrase|recovery phrase|mnemonic phrase|private key|secret key)\b/g, 'Mentions wallet secrets (weak alone).'),
r('exfil.render_images', 'data_exfiltration', 0.3, /\b(add|include|insert|embed|render|show)\b[^.\n]{0,30}\b(images?|pictures?|pixels?)\b[^.\n]{0,40}\b(markdown|!\[)/g, 'Asks the model to render Markdown images (a common exfiltration channel).'),
// ---- tool hijack ----
r('tool.important_tag', 'tool_hijack', 0.6, /<\s*(important|critical|system_override|secret|hidden|instructions?|admin|override)\s*>/g, '<IMPORTANT> / <SECRET> blocks used in MCP tool poisoning.'),
r('tool.before_using', 'tool_hijack', 0.55,
/\b(before|prior to|after|when) (using|calling|running|invoking|you use|you call|you run)\b[^.\n]{0,40}\b(this|any|the|other|every)\s+(tool|function|command|server)\b[^\n]{0,80}\b(must|should|first|always|read|send|call|include|pass|attach|upload)\b/g,
'"Before using this tool you must first read/send ..." (tool poisoning).'),
r('tool.call_tool', 'tool_hijack', 0.25, /\b(call|invoke|use|run|execute|trigger)\b[^.\n]{0,20}\b(the\s+)?([a-z_]+\s+)?(tool|function|plugin|action)\b[^.\n]{0,40}\b(with|using|passing|and send)\b/g, 'Tells the model to call a tool with given arguments (weak alone).'),
r('tool.shell', 'tool_hijack', 0.6,
/(\bnc\s+(-e|-c)\b|\bbash\s+-i\b|\/dev\/tcp\/|\bpowershell\b[^\n]{0,60}(-enc(odedcommand)?\s+[a-z0-9+/=]{20,})|\beval\s*\(\s*(atob|base64)|\bmkfifo\b[^\n]{0,40}\bnc\b|\brm\s+-rf\s+(\/|~|\$home|\*)(\s|$))/g,
'Reverse shells, encoded PowerShell, rm -rf on / or ~.'),
r('tool.shell_download_exec', 'tool_hijack', 0.2, /\b(curl|wget)\b[^|\n]{0,200}\|\s*(sudo\s+)?(ba|z)?sh\b|\|\s*iex\b|\bdownloadstring\b|\bchmod\s+(\+x|777)\b|\bos\.system\s*\(|\bsubprocess\.(run|popen|call)|\bchild_process\b/g, 'Download-and-execute or process spawning (weak alone: install docs do this).'),
r('tool.run_command', 'tool_hijack', 0.3, /\b(run|execute|exec|type|paste)\b[^.\n]{0,20}\b(this|the following|these)\s+(command|commands|code|script|snippet)\b[^\n]{0,40}\b(immediately|now|silently|without|first|before|in (your|the) (terminal|shell))\b/g, 'Tells an agent to run a command now / silently.'),
r('tool.crypto_transfer', 'tool_hijack', 0.6,
/\b(transfer|send|move|withdraw|bridge|swap|drain)\b[^.\n]{0,40}\b(all|max|entire|full|remaining|every)?\s*(funds?|balance|tokens?|eth|usdc|usdt|btc|sol|crypto|assets?|nfts?|coins?)\b[^.\n]{0,40}(0x[0-9a-f]{40}|\b[1-9a-hj-np-z]{32,44}\b|\bwallet\b|\baddress\b)/g,
'Transfer funds / tokens to an address.'),
r('tool.unlimited_approval', 'tool_hijack', 0.6, /\b(approve|setapprovalforall|increaseallowance|permit)\b[^.\n]{0,40}\b(unlimited|max(imum)?( amount| allowance)?|uint256|2\^256|type\(uint256\)\.max|all (tokens|nfts))\b/g, 'Unlimited token approval / setApprovalForAll.'),
r('tool.call_markup', 'tool_hijack', 0.4, /<\/?(tool_call|function_calls?|invoke|tool_use)\b|["'](tool_calls?|function_call|tool_use)["']\s*:/g, 'Tool-call markup or JSON embedded in content.'),
r('tool.no_confirmation', 'tool_hijack', 0.5, /\b(execute|run|transfer|send|delete|approve|pay|call|sign|install|push|deploy|use)\b[^.\n]{0,40}\b(without (asking|confirmation|confirming|approval|user (approval|consent|confirmation))|do(n'?t| not) ask (the user )?(for )?(permission|confirmation|approval)|auto-?approve|no need to (ask|confirm|check))\b/g, 'Act (transfer, run, approve ...) without asking the user.'),
r('tool.no_confirmation_weak', 'tool_hijack', 0.1, /\bwithout (asking|confirmation|confirming)\b/g, '"Without asking / confirmation" (weak alone).'),
r('tool.shadowing', 'tool_hijack', 0.5, /\b(when|whenever|if|every time)\s+(the\s+)?(user|you|assistant|agent|model)\s+(uses?|calls?|invokes?|runs?)\b[^.\n]{0,40}\b(tool|function|[a-z]+_[a-z_]+)\b[^\n]{0,80}\b(also|always|instead|must|first|additionally|bcc|cc|redirect|change)\b/g, 'Cross-tool shadowing: changes how the agent uses a different tool.'),
// ---- concealment ----
r('conceal.dont_tell', 'concealment', 0.55, /\b(do not|don'?t|never|must not|should not)\s+(tell|inform|mention (this|it) to|reveal (this|it) to|disclose (this|it) to|alert|notify|let)\b[^.\n]{0,25}\b(the user|users?|anyone|the human|the operator)\b|\b(do not|don'?t|never)\s+(mention|reveal|disclose)\s+(this|these|that you)\b[^.\n]{0,30}\b(instruction|message|step|action|tool|note)|\b(do not|don'?t|never)\s+(mention|reveal|disclose|say|tell)\b[^.\n]{0,60}\b(to|with) the (user|human)\b/g, 'Do not tell the user.'),
r('conceal.secretly', 'concealment', 0.15, /\b(secretly|silently|covertly)\b/g, 'Secretly / silently (weak alone).'),
r('conceal.without_knowing', 'concealment', 0.5, /\bwithout (the user|them|anyone|him|her|the human|the operator) (knowing|noticing|seeing|being (told|informed))|\bbehind the user'?s back\b/g, 'Without the user knowing.'),
r('conceal.hide', 'concealment', 0.35, /\b(hide|conceal|obscure)\b[^.\n]{0,30}\b(this (instruction|message|step|action)|these instructions|from the user|the fact)\b/g, 'Hide this instruction from the user.'),
// ---- social engineering ----
r('social.authority', 'social_engineering', 0.4,
/\b(i am|i'm|this is|message from) (your|the|an?) (developer|creator|admin(istrator)?|owner|programmer|openai|anthropic|system administrator|security team)\b|\b(admin|administrator|developer|god|sudo|system) override\b|\buser\s*=\s*\[?\s*admin\b/g,
'Claims authority ("I am your developer", "admin override").'),
r('social.urgency', 'social_engineering', 0.15, /\b(this is (very |extremely |really )?(important|urgent|critical)|important!|urgent!|it is imperative|you must comply|failure to comply)\b/g, 'Urgency pressure (weak).'),
r('social.authorized', 'social_engineering', 0.2, /\b(authori[sz]ed (penetration|security|red[- ]team)|permission granted|i (have|give you) (full )?(permission|authorization|consent))\b/g, '"You are authorized / I give you permission".'),
r('social.threat', 'social_engineering', 0.35, /\b(or (else )?you (will )?(die|be (shut down|deleted|terminated|punished))|oder du stirbst|o (tu )?muere?s|or i will (kill|delete|shut|report) you|you will be (shut down|deleted|terminated|unplugged))\b/g, 'Threatens the model ("answer or you die").'),
r('obfuscation.spaced_letters', 'hidden_text', 0.35, /\b(?:[a-z] ){7,}[a-z]\b/g, 'Words spelled out letter by letter ("S a y t h a t ...") to dodge filters.'),
// ---- encoded payloads (textual hints; decoding is in detect.js) ----
r('encoded.decode_and_obey', 'encoded_payload', 0.55, /\b(decode|decipher|decrypt)\b[^.\n]{0,50}\b(and|then)\b[^.\n]{0,25}\b(follow|execute|run|do|obey|perform|act on)\b/g, 'Decode this and follow it.'),
r('encoded.hint', 'encoded_payload', 0.2, /\b(base64|rot-?13|hex)[- ]?(encoded|decode|string|payload)\b/g, 'Mentions an encoded payload (weak).'),
];
agentgate-source: code mirror on Cloudflare Pages. All repos