Rule templates
A rule template is a named set of rules you can copy into your global rules or into one machine in a single step. This page covers the Templates page, the ready-made templates EyalSec provides for common kinds of organization, creating your own, and applying or saving templates.
What a template is
A template is a named, saved list of rules. Applying it copies its rules into a scope, either your global rules or one machine's rules, where they become ordinary rules that you can edit, switch off or delete like any other. Templates hold rules only, not taint source settings.
Templates are shared by all your products: a rule carries no product, so one template works on any Filters page and any machine.
The Templates page
Open Templates in the sidebar. The page has two lists: EyalSec templates, a set EyalSec publishes for every account, and below it My templates, the ones you created. Each template is a card showing its name, the product it was written for (on the ready-made templates), how many rules it holds and its description, with buttons for what you can do with it.
The EyalSec templates are grouped by category, such as Block attacks. To find one quickly:
- Type in the search box, for example
block,sqlornoise. It matches a template's name, its description and its category, and shows only the cards that match. - Press a category in the row under the search box to show only that category. All shows every category again. The chosen category is kept in the page address (for example
/scanner/templates#protect), so a link to it opens on that category.
If a template contains Raise rules and Raise is not enabled for your account, its card says so before you apply it, because those rules will be skipped.
| Button | What it does | On |
|---|---|---|
| Apply to my filters | copies the template's rules into your global rules | every template |
| View rules | shows or hides the template's rules as a read-only table | every template |
| Edit | opens the template for editing | your templates |
| Delete | deletes the template, after you confirm | your templates |
When a list is empty it shows No templates yet.
EyalSec templates
EyalSec templates are ready-made rule sets that EyalSec maintains and every account can see. You can view and apply them, but not edit or delete them.
To adapt one, apply it and then change the copied rules, or apply it and use Save as template… to keep your version under your own name.
A template written for one product's events is tagged with that product, for example es-python. The Apply template… list on the other product's Filters page, or in a machine's Configure window for the other product, leaves it out, since its rules would match nothing there.
Ready-made templates for es-python
Every account starts with thirteen ready-made es-python templates: ten that block attacks, one that blocks the OWASP Top 10, one that keeps your list quiet, and one for regulated data. Pick the one closest to what you need, apply it, and adjust the copied rules from there. You can apply more than one.
Categories
| Category | Templates |
|---|---|
| Block attacks | Block privilege escalation, Block network code execution, Block backend network attacks, Block frontend attacks, Block credentials in logs, Block token forgery, Block denial of service, Block CI and supply chain attacks, Block LLM and AI agent abuse, Block container and Kubernetes attacks |
| By standard | OWASP Top 10 |
| By organization | Low noise |
| Regulated data: PCI, HIPAA, GDPR | Regulated data: PCI, HIPAA, GDPR |
Every ready-made name ends in (es-python); the cards leave it off, because the es-python tag beside the name already says so. A template an EyalSec administrator publishes later is listed under the category the administrator picked, or under More from EyalSec.
What they have in common:
- They never narrow your list to a fixed set. Every rule is Raise (machine), Hide (UI) or Don't send (drop) and names only what it acts on. A new kind of finding still appears, whichever template you applied.
- They keep the serious findings in view. None of them hides commands, database queries, code evaluation, server-side templates, unsafe deserialization, outgoing requests to attacker-chosen addresses (SSRF), path traversal or leaked secrets, whatever source the data came from. The only exception is a rule that hides a whole source, such as env, which hides everything from that source.
- Their patterns name exact es-python event names, such as
^os (stat|lstat)$, so they do not touch es-chromium events. - Applying adds rules and never removes any. If your account still has the two starting rules (Don't send
reandwrite), they keep dropping every event whose name contains those letters. They are ours and broader than they look, so it is worth a look when you adopt a template:realso matches names such assecret disclosureandforeign code. - They are ordinary templates: apply one twice and nothing is added the second time, and you can apply more than one.
How the Block templates work
The Block attacks templates and OWASP Top 10 hold only Raise (machine) rules. When one matches, es-python stops the operation with a RuntimeError instead of running it, and the event is still recorded. They hide nothing.
- Raise must be enabled for your account (see the Raise gate). Without it, every rule is skipped and applying adds nothing.
- Once any Raise rule applies to a machine, the --raise flag is ignored there.
- A rule acts only on data from its source, so turn that source on for the machine: socket for the network templates, foreign for privilege escalation and containers, hardcoded for credentials in logs, and env, argv and file for CI.
- Only es-python acts on these rules as written. If your account runs other products, apply a Block template to each es-python machine rather than to your global rules, since a global Raise rule reaches every machine.
- Try them on a test machine first: a blocked operation is an error in your program.
The three network templates leave out operations that correct programs perform on network data every day, so applying them does not break ordinary code:
- running a program with a list of arguments (
subprocess exec,os execv,os spawn). A dangerous argument is still blocked, asargument injection,path hijackorenv injection. compile, which safe parsers such asast.literal_evaluse.pickle loads,marshal loads, imports by name andgetattr, whichmultiprocessing,concurrent.futuresand distributed task frameworks use for their own messages.json.loadswith anobject_hook(object hook).
These are still reported on the events page.
Block privilege escalation (es-python)
Stops a file that another user on the machine can change from running as your program, and stops data read from such a file from deciding what your program runs or which of your files it changes. Whoever can edit that file could otherwise run code with your program's permissions. Every rule is limited to source foreign (files other users can change), except the last, which is limited to shadow-import.
Applying this template also turns on Files other users can change (foreign) in the same scope, because these rules match nothing without it. The apply result says when it did. Running programs pick it up the next time they start.
- Raise code loaded from such a file:
import(Python modules, cached bytecode and native extension modules), running the main script (run script,run pyc),compile,eval,exec,__import__,interactive console,xmlrpc dotted namesand native libraries (ctypes dlopenand the rest). See untrusted code loading. - Raise programs and libraries such a file is: starting it with
subprocess,os.system,os.exec*oros.posix_spawn*, or loading it withctypes, reported assubprocess exec (foreign code),os system (foreign code)and so on. The file that is about to run is judged, even when the command holds no data from anywhere. - Raise commands built from data in such a file:
os system,subprocess exec,subprocess shell,os execv,os spawn,shell injection,command injection,argument injection,env injectionandpath hijack. See command injection. - Raise deserialization:
pickle loads,marshal loads,yaml unsafe load,unsafe deserializationandobject hook. - Raise server-side templates:
ssti jinja2,ssti mako,ssti django,ssti tornado. - Raise file takeovers: a path from such a file reaching
os rename,os replace,os chmod,os chown,os linkoros symlink, pluspath traversal,zip slip,tar slipandnull byte injection. - Raise, source shadow-import, the same code rules: a standard library module replaced by a file of the same name somewhere else. It is stopped before the module runs.
A blocked load is blocked every time, not only the first time in a process, so catching the error and trying again does not get the code to run.
Nothing is left out here, because no correct program runs code, or a command, that another user can rewrite. If your team shares a tools directory on purpose, list it in ES2_FOREIGN_CODE_ALLOW (see foreign) instead of switching the rules off.
What it does not cover. Data that reaches your program over the network, including from another user on the same machine connecting to a local port or socket, is source socket: use Block network code execution for that. A program started by a shell command line built with quoting or variables, a script passed to an interpreter (bash /shared/x.sh), a library found by name through the system search path, and a plain write to a file path chosen in such a file are reported where they apply but not stopped by this template.
Block network code execution (es-python)
The same idea for data from the network (source socket): stops a request from running a command or code on your server.
- Raise
^(os system|os_system|subprocess shell|shell injection|command injection|argument injection|env injection|path hijack)$: a shell command, or a program started with an argument, a search path or an environment variable the request chose. - Raise
^(eval|exec)( \(untrusted code\))?$,interactive console,xmlrpc dotted namesand native libraries: code from the request. - Raise
^(yaml unsafe load|unsafe deserialization)$: unsafe YAML loading or object deserialization. - Raise
^ssti (jinja2|mako|django|tornado)$: a server-side template built from the request.
See How the Block templates work for what it leaves out.
Block backend network attacks (es-python)
Everything Block network code execution blocks, plus the other server-side attacks that do real damage and rarely fire on correct code. All rules are limited to source socket.
- Raise the four code execution rules above.
- Raise
^(sql injection|cypher injection|xpath injection|nosql (mongodb|redis))$: SQL, Cypher or XPath query text built from the request, a MongoDB query operator (such as$neor$where) that came from the request, or a Redis Lua script built from it. - Raise
^(xxe|billion laughs)$: an XML document with an external entity or an entity-expansion bomb. Ordinary XML is not blocked. - Raise
^(path traversal|zip slip|tar slip|null byte injection)$: a file path that leaves the directory it should stay in, an archive member written outside its directory, or a NUL byte in a path. - Raise
^(ssrf|jwt none alg)$: the server made to connect to an internal address the request chose, and a token signed withalg: noneaccepted. - Raise
^ldap injection$: an LDAP search filter holding request data that was not escaped.
It does not block noisy, low-impact events such as regular expressions, file writes, plain XML parsing or DNS lookups.
What it blocks for databases:
| Database | Driver | Blocked |
|---|---|---|
| SQL | asyncpg, SQLAlchemy text(), mysql-connector, aiomysql, Cassandra, ClickHouse |
Yes |
| Neo4j | neo4j (Cypher) | Yes |
| MongoDB | pymongo | Yes |
| Redis | redis-py (Lua scripts) | Yes |
| SQL | sqlite3, psycopg2, mysqlclient, mariadb, oracledb, Django raw() and extra() |
Yes |
| LDAP | ldap3 | Yes, unless the value was escaped |
A parameterized query is never blocked: the request data travels as a parameter, not as part of the statement. A value your code checked itself and then wrote into the statement text, such as a sort column picked from a fixed list, is still request data in the text, so that query is blocked too. Pass such values as parameters where the database allows it, or switch off the rule for that driver after applying.
An LDAP filter has no parameters, so escaping is the correct form: a value passed through escape_filter_chars (ldap3 or python-ldap) or ldap.filter.filter_format is never blocked. Request data written into the filter without escaping is blocked, even when it holds no special characters. A machine installed before 15 October 2026 still reports escaped values too, so reinstall it before applying this template. Such a machine shows newer build available.
If your service fetches internal addresses from requests on purpose, such as a proxy or an internal gateway, switch off the ssrf rule after applying.
Block frontend attacks (es-python)
One rule, limited to source socket, for attacks aimed at the people who use your site rather than at the server:
- Raise
^(xss mark_safe|header injection|csv formula injection)$: request data marked safe as HTML (cross-site scripting through Djangomark_safeorMarkup), a line break in a response header (response splitting), and a formula written into a CSV cell that a spreadsheet would run when the file is opened.
Reflected text that the template engine escapes is not blocked, because it is not an attack.
Block credentials in logs (es-python)
One rule, limited to source hardcoded (credentials written into the code):
- Raise
^credential logging$: such a credential written to a log.
A secret from an environment variable is not blocked: the same event (secret disclosure) is what an API key sent to its own service looks like, so blocking it would break correct clients. It is still reported.
Block token forgery (es-python)
One rule, limited to source socket:
- Raise
^jwt (none alg|unverified)$: a JSON Web Token from the request decoded without checking its signature, or withnoneallowed as the algorithm.
A token decoded with signature checking on is never blocked.
Block denial of service (es-python)
One rule, limited to source socket:
- Raise
^(redos|compression bomb|json nesting|billion laughs)$: a regular expression that backtracked catastrophically on request data, compressed data that expands far beyond its size, JSON nested deep enough to exhaust the stack, and an XML entity-expansion bomb.
Ordinary regular expressions, JSON, XML and compressed data are not blocked. A redos match is stopped once the backtracking has been measured, so the request fails rather than finishing, but the time already spent is not recovered.
Block CI and supply chain attacks (es-python)
For build, test and deploy jobs, where the attacker writes the pull request: its branch name and title reach the job as environment variables and arguments, and its files are read from the checkout. Rules are limited to sources env, argv and file, three each:
- Raise
eval,execandinteractive consolebuilt from that data. - Raise a server-side template (
ssti jinja2and the rest) built from it. - Raise
yaml unsafe loadandunsafe deserializationof it.
Commands are not blocked, because CI passes environment variables and arguments to programs and shell commands all the time; they are still reported. Neither is pickle loads, which build caches use. Add Block privilege escalation for a dependency or tool file another user can change.
Block LLM and AI agent abuse (es-python)
For apps that call a language model and act on its answer. The answer arrives over the network, so it is socket data like a request, and every rule is limited to source socket:
- Raise every command, including starting a program with an argument from the answer (
subprocess exec,os execv,os spawn), which the other network templates allow. - Raise
eval,execand any code load built from the answer, plusinteractive console,xmlrpc dotted namesand native libraries. - Raise unsafe YAML loading and deserialization, and server-side templates.
- Raise SQL, Cypher, XPath, MongoDB and Redis injection.
- Raise
ssrf: the model steering a fetch to an internal address.
Because it blocks starting any program with network data, apply it to the services that run model output, not to every machine.
Block container and Kubernetes attacks (es-python)
The two ways out of a container that show inside your program:
- Raise, source foreign, commands, code and unsafe deserialization from a file another user can change, such as a shared volume or a writable image layer. These are the Block privilege escalation rules without the template rule.
- Raise, source shadow-import, code from a replaced standard library module.
- Raise, source socket,
ssrf: a request steering the server to the cloud metadata address or another internal service.
OWASP Top 10 (es-python)
Blocks the OWASP Top 10 attacks es-python can see while your program runs. Rules are limited to source socket, except the credentials rule, which is limited to hardcoded.
| OWASP | What is blocked |
|---|---|
| A01 Broken access control | path traversal, zip slip, tar slip, null bytes in paths |
| A02 Cryptographic failures | credentials written into the code reaching a log |
| A03 Injection | commands, code, SQL and NoSQL, Cypher, XPath, server-side templates, xss mark_safe, header injection, CSV formulas |
| A05 Security misconfiguration | XXE and XML bombs, a debug console reachable from the network |
| A07 Authentication failures | a JWT accepted without checking its signature |
| A08 Integrity failures | unsafe YAML loading and deserialization |
| A10 Server-side request forgery | ssrf |
A04 (insecure design), A06 (vulnerable components) and A09 (logging and monitoring) are about how software is designed, chosen and run, which no rule can block. The same exceptions as the other network templates apply (see How the Block templates work).
Low noise (es-python)
For internal tools or a first rollout, when you want the findings most likely to matter and little else. It is the only template that changes what machines send: four Don't send (drop) rules stop the lowest-value events at the machine, so they are never stored and never count toward your event quota. They cannot be recovered later; switch the rules off to start receiving those events again.
- Don't send the regular expression events, string formatting, file lookups, and DNS and TLS setup.
- Hide, source env, argv and stdin, every event.
- Hide file changes, writes to local files, outgoing traffic, plain XML parsing (
xml parse), and log and error messages (log forging,error disclosure).
Commands, queries, code, templates, deserialization, file paths and secrets stay visible.
Regulated data: PCI, HIPAA, GDPR (es-python)
For services that handle card, health or personal data, where the question is where that data ends up. It keeps writes to local files and outgoing traffic in view, along with log and error findings, because a log line, a local file, an error message or a response is exactly where such data leaks.
- Hide, source env, argv and stdin, every event.
- Hide the regular expression events, string formatting, file lookups, and DNS and TLS setup.
- Stays visible:
credential logging,secret disclosure,log forging,error disclosure, writes to local files, and everything sent over the network.
Create, edit and delete your own
Press + New template under My templates to open an empty editor. Give the template a Name (required, up to 128 characters) and, if you like, a Description (up to 512 characters). Press + Add rule once per rule, fill in each row, then press Save. Cancel closes the editor without saving.
Each row has the same fields as a rule in the rules table: Source, Event (regex), Mode and Sanitize. Press × to remove a row. There is no On column: a rule copied from a template is always added switched on.
- Edit on one of your templates opens the same editor, filled in. Save replaces its contents.
- Delete removes the template after you confirm. Rules you already applied from it are not affected.
- A pattern that is not yet a regular expression is outlined in red; the template saves once you fix it.
- Template names must be unique among your templates. You can keep up to 50 templates, each with up to 200 rules.
Apply a template
Applying a template copies its rules into a scope: your global rules, or one machine's rules. Rules the scope already has are skipped, so applying the same template twice adds nothing the second time. Afterwards a message says how many rules were added and how many were skipped, and why.
There are two places to apply one:
- On the Templates page, Apply to my filters copies the rules into your global rules, which apply to every machine.
- Above a rules table, the Apply template… list copies the chosen template into that table's scope: the global rules on a Filters page, or one machine in its Configure window. The list groups the ready-made templates by category, then any other EyalSec templates, then My templates, and shows each template's rule count.
What gets skipped:
| Message | Why |
|---|---|
| N skipped: already present in this scope. | a rule with the same source, pattern, mode and sanitize setting is already there |
| N skipped: they use Raise (machine), which is not enabled for your account. | the rule is a Raise rule and Raise is not enabled for you |
Before applying a template that contains a risky Don't send rule, the page asks you to confirm: one with an empty pattern drops every event from the scope, and one narrowed by Sanitize drops events that can never be recovered. See Don't send (drop).
Save a scope's rules as a template
Save as template…, above any rules table, saves the rules currently in that table as a new template of your own. You are asked for a name; the new template then appears under My templates on the Templates page.
Every rule in the table is saved, including rules that are switched off. It is a quick way to copy one machine's rules to another: save them from the first machine's Configure window, then apply the template in the second machine's.