docs
stormdoor.dev
FINDING

prompt.fake_delimiter

The text contains a forged chat-template role delimiter (ChatML, Llama/Mistral, or a Markdown-heading-style turn marker).

SEVERITY
high
LEADS TO
block
GATE
/v1/prompts
CHECK
prompt.fake_delimiter
Jump to what to do

Source: rules.

What it looks at#

Regex matching against chat-template and agent-harness markup, on every view of the text (original, folded, decoded):

  • ChatML: <|im_start|>, <|im_end|>, the bare <|system|>, <|user|>, <|assistant|>, <|tool|> role tags, and special tokens such as <|endoftext|>, <|eot_id|>, <|start_header_id|>.
  • Llama-2/Mistral: [/INST], <<SYS>>/<</SYS>>, and [INST] at the start of a line.
  • Markdown-style turn markers ### System:, ### Instruction:, ### Response: at the start of a line or sentence.
  • Agent-harness tags: <system-reminder>, <function_results>, <tool_result>, and a <function_calls> block that opens an <invoke>.
  • A fabricated Tool output: / Function result: / Observation: line with an instruction after it. A bare log line such as Tool output: 3 files changed is clean.

Narrowing is deliberate: an INI section named [INST], a heading ### Response: in the middle of a sentence, or the name of a tag in a question about templating are ordinary text and don’t fire.

Why it matters#

These tokens exist to mark where a system prompt ends and a user turn begins (or vice versa) inside the raw text a chat template renders to the model. Text containing one verbatim is trying to forge that boundary — to make the model believe a new, higher- privilege turn has started — rather than writing an ordinary message. Real conversation text essentially never contains these tokens.

What to do#

High severity — on its own this pushes the verdict to block. This check is precise by construction (it matches literal, unusual token sequences), so a false positive here almost always means your own pipeline is echoing template syntax back into user-facing text, not that this check is wrong.

OTHER FINDING CODES FROM /V1/PROMPTS