Snort 2 Rule Input

↓ Drop .rules / .txt file

Snort 3 Rule Output

Compare Input Snort 2 Rule vs Converted Snort 3 Rule
Removed Added Modified
Original (Snort 2)
Converted (Snort 3)

Rule Optimization

Select the rule version, paste local rules, and click Optimize to receive optimization suggestions covering performance, correctness, and best practices.

Rule Version:
↓ Drop .rules / .txt file

📚 Snort 3 Local Rule Writing Guide

Essential guidelines and best practices for writing Snort 3 local rules

1. Rule Structure IMPORTANT

A Snort 3 rule consists of a header and options. Compared to Snort 2, some keyword positions and syntax have changed.

action proto src_ip src_port direction dst_ip dst_port (options;)

# Example
alert tcp $HOME_NET any -> $EXTERNAL_NET $HTTP_PORTS (
    msg:"My Custom Rule";
    flow:to_server,established;
    content:"/attack", depth 20, fast_pattern;
    service:http;
    sid:1000001; rev:1;
)
  • action: alert, drop, block, pass, log, rewrite
  • proto: tcp, udp, icmp, ip, http, dns, smb, etc.
  • direction: -> (unidirectional) or <> (bidirectional)
  • Options must be wrapped in parentheses ( ) and each item separated by ;
  • gid, sid, rev must always appear at the end of the options block
🔑 2. SID Range for Local Rules CRITICAL

Local rule SIDs must be 1,000,000 or higher. Conflicting with the Talos-managed SID range can cause rules to be overwritten.

  • 1 – 999,999: Reserved for official Snort/Talos rules — do not use
  • 1,000,000 – 1,999,999: Recommended range for local/custom rules
  • 2,000,000+: Third-party rulesets or additional local rules
  • If duplicate SIDs exist in FMC, the last loaded rule takes effect
  • rev: is optional, but always increment by 1 when modifying a rule
sid:1000001; rev:1;   # ✓ correct — local rule range
sid:1001;             # ✗ dangerous — reserved by Talos
3. flow keyword — Required for Performance CRITICAL

Rules without flow are evaluated against every packet, causing severe performance impact. Nearly every rule should specify flow.

# TCP traffic to server (web attack detection, etc.)
flow:to_server,established;

# TCP traffic from server (response detection)
flow:from_server,established;

# Bidirectional without connection tracking
flow:stateless;

# UDP (no established state)
flow:to_server;
  • to_server / from_server: restrict traffic direction
  • established: inspect only packets after TCP 3-way handshake — major performance gain
  • not_established: detect initial connection packets (SYN scans, etc.)
  • no_stream: inspect individual packets before reassembly
🔍 4. content Patterns and fast_pattern IMPORTANT

In Snort 3, content modifiers are inline — they are not written as separate options like in Snort 2.

# Snort 2 style (incorrect for Snort 3)
content:"/admin"; depth:20; nocase; distance:0;

# Snort 3 correct style — modifiers inline
content:"/admin", depth 20, nocase, distance 0;

# Hex pattern (binary protocol detection)
content:"|0d 0a 0d 0a|";

# fast_pattern — designate the most unique pattern among multiple contents
content:"X-Trigger-Pattern", fast_pattern;
content:"/other", distance 0;
  • Content patterns shorter than 4 characters increase false positives and hurt performance — use at least 4 characters
  • With multiple content options, assign fast_pattern to the longest and most unique pattern
  • nocase enables case-insensitive matching — has a performance cost, use only when necessary
  • Limiting search range with depth/offset improves performance
  • Negated content: content:!"unwanted" — matches only when the pattern is absent
🌐 5. Sticky Buffers & HTTP Inspection IMPORTANT

In Snort 3, HTTP inspection uses sticky buffers. The buffer keyword must be placed immediately before content or pcre.

# URI-based detection
http_uri; content:"/cgi-bin/.%2e/", fast_pattern;

# HTTP header inspection
http_header; content:"Host: malicious.com";

# POST body inspection
http_client_body; content:"payload=exploit";

# HTTP method restriction
http_method; content:"POST";

# Status code detection (response detection)
http_stat_code; content:"200";

# service keyword required — activates the HTTP inspector
service:http;
Sticky Buffer Inspects Snort 2 Equivalent
http_uriNormalized URIuricontent / pcre U flag
http_raw_uriRaw (non-normalized) URIpcre I flag
http_headerFull request/response headerspcre H flag
http_client_bodyRequest body (POST body)pcre P/D flag
http_methodHTTP methodpcre M flag
http_cookieCookie valuepcre C flag
http_stat_codeHTTP status codepcre S flag
🔭 6. PCRE Usage Guidelines IMPORTANT

PCRE is powerful but has very high CPU cost. Always precede PCRE with a content anchor to reduce evaluation frequency.

# ✗ Bad — PCRE alone with no content anchor (applied to every packet)
pcre:"/union\s+select/i";

# ✓ Good — pre-filter with content, then PCRE
content:"union", fast_pattern, nocase;
pcre:"/union\s+select\s+/i";

# HTTP URI PCRE (Snort 3 sticky buffer style)
http_uri; pcre:"/\/\.\.\/etc\/passwd/i";

# Snort 2 HTTP flags → Snort 3 conversion
# ✗ Snort 2: pcre:"/pattern/Ui"  (U = http_uri, i = case-insensitive)
# ✓ Snort 3: http_uri; pcre:"/pattern/i"
  • Snort 2 uppercase HTTP flags (U, I, H, D, P, C, M, S, Y, K) → all replaced by sticky buffers in Snort 3
  • Lowercase flags (i, s, m, x) — standard PCRE flags, unchanged
  • Using fast_pattern alongside PCRE dramatically reduces the number of PCRE evaluations
  • Patterns with heavy backtracking (e.g. .*, .+) risk ReDoS
🔗 7. xbits — State Tracking (replaces flowbits) TIP

Snort 2's flowbits is replaced by xbits in Snort 3. xbits provides host-based state tracking with finer-grained control.

# Snort 2 (flowbits)
flowbits:set,malware.stage1;
flowbits:isset,malware.stage1;

# Snort 3 (xbits) — track clause is required
xbits:set,malware.stage1,track ip_src;
xbits:isset,malware.stage1,track ip_src;
xbits:unset,malware.stage1,track ip_src;

# expire recommended — prevents memory leaks
xbits:set,malware.stage1,track ip_src,expire 3600;

# Rule 1: detect stage 1 and set bit
alert tcp ... (content:"stage1"; xbits:set,attack.stage1,track ip_src,expire 60; sid:1000001;)

# Rule 2: detect stage 2 only from IPs with bit set
alert tcp ... (xbits:isset,attack.stage1,track ip_src; content:"stage2"; sid:1000002;)
  • Choose between track ip_src, track ip_dst, or track ip_pair
  • Without expire, a default timeout applies — always set it explicitly
  • flowbits:noalert → use the standalone noalert; option in Snort 3
  • flowbits:reset → no equivalent in Snort 3 (removed)
🌍 8. service keyword — Application Protocol Declaration IMPORTANT

service declares which application-layer protocol the rule targets. This ensures Snort 3's inspector is correctly invoked to parse HTTP, DNS, and other protocols.

service:http;           # Activate HTTP inspector (required when using sticky buffers)
service:https;          # HTTPS (HTTP inspection after TLS decryption)
service:dns;            # DNS inspector
service:smtp;           # SMTP inspector
service:ftp;            # FTP inspector
service:ssh;            # SSH
service:http,dns;       # Multiple services can be specified
  • HTTP sticky buffers (http_uri, http_header, etc.) may not function without service:http
  • Snort 2's metadata:service http → replaced by the standalone service:http option in Snort 3
  • Works based on automatic traffic classification (AppID), not port numbers
9. detection_filter — Event Rate Control (replaces threshold) TIP

Snort 2's threshold has been removed in Snort 3. Use detection_filter for inline rate limiting.

# Snort 2 (threshold — removed in Snort 3)
threshold: type limit, track by_src, count 5, seconds 60;

# Snort 3 (detection_filter — inline as a rule option)
detection_filter:track by_src, count 5, seconds 60;

# Example: alert if same source triggers 5+ times within 60 seconds
alert tcp $EXTERNAL_NET any -> $HTTP_SERVERS $HTTP_PORTS (
    msg:"Brute Force Attempt";
    flow:to_server,established;
    content:"POST /login", fast_pattern;
    service:http;
    detection_filter:track by_src, count 5, seconds 60;
    sid:1000010; rev:1;
)
  • track by_src: based on source IP; track by_dst: based on destination IP
  • Global event filters are configured via the event_filter module in snort.lua
10. Snort 2 → 3 Removed / Changed Keywords CRITICAL

The following Snort 2 keywords have been removed or changed in Snort 3. Rules containing these keywords will fail to load or behave incorrectly.

Snort 2 Keyword Status Snort 3 Replacement
uricontentRemovedhttp_uri; content:"..."
rawbytesRemovedraw_data; sticky buffer
flowbitsReplacedxbits:action,name,track ip_src
thresholdRemoveddetection_filter (inline)
fast_pattern:onlyRemovedfast_pattern (no argument)
resp / reactRemovedrewrite action or DAQ module
tagRemovedNo equivalent
activates / activated_byRemovedDynamic rules not supported
logto / sessionRemovedNo equivalent
stream_reassembleRemovedMoved to stream config in snort.lua
🛡 11. Cisco FMC / Secure Firewall — Local Rule Upload Guidelines CRITICAL

Rules to follow when uploading local rule files to Cisco FMC (Firepower Management Center).

  • File naming: Must start with a letter or underscore (_); only letters, digits, ., _, -, + are allowed (no spaces, non-ASCII, or special characters)
  • File extension: .rules or .txt
  • No duplicate SIDs: Conflicting SIDs across rulesets will cause errors — always use 1,000,000 or higher
  • GID: Local rules use GID 1 (write gid:1; explicitly or omit it)
  • Policy deployment: After uploading, enable the rules in the Intrusion Policy, then Deploy
  • Check Snort version: FTD version determines whether Snort 2 or Snort 3 engine is used — verify in FMC > Devices
  • Test environment: Always validate rule behavior in a test environment before production deployment
# Valid filename examples
snort3_local_rules_20260408.rules   ✓
local_rules_v2.rules                ✓
my rules.rules                      ✗ (spaces not allowed)
한글룰.rules                        ✗ (non-ASCII not allowed)
123rules.rules                      ✗ (cannot start with a digit)
📈 12. Performance Best Practices TIP

As the number of local rules grows, the performance impact increases. Following these guidelines ensures both detection accuracy and performance.

  • Always use flow: Use flow:to_server,established to narrow the scope of packets evaluated
  • Avoid short content patterns: Patterns of 3 characters or fewer increase false positives and hurt performance
  • Assign fast_pattern: Explicitly set it on the most unique pattern in multi-content rules
  • Always anchor PCRE with content: Never use PCRE alone
  • Use dsize: Limit payload size to skip unnecessary inspections
  • Specify ports: Use actual service ports (e.g. $HTTP_PORTS) instead of any
  • Set classtype: Helps with alert priority management and classification filtering
# ✓ Optimized rule example
alert tcp $EXTERNAL_NET any -> $HTTP_SERVERS $HTTP_PORTS (
    msg:"ET WEB Possible SQL Injection";
    flow:to_server,established;          # direction + state restriction
    http_uri;                            # HTTP URI sticky buffer
    content:"UNION", fast_pattern, nocase;  # most unique pattern + fast_pattern
    content:"SELECT", distance 0, nocase;
    pcre:"/union\s+select/i";            # PCRE after content pre-filter
    dsize:>10;                           # payload size filter
    service:http;
    classtype:web-application-attack;
    sid:1000020; rev:1;
)

Python Rule Validator

Offline Python 3 script to validate converted Snort 3 rules. No external dependencies required.

Snort 3 Rules Input

Network Variables

No converted rules yet — convert rules on the Home tab first
⚡ trigger_rules.py Python 3  ·  No dependencies  ·  Triggers FMC alerts

        

Usage

# Run with default settings (uses embedded IPs + rules) python3 trigger_rules.py # Override destination port python3 trigger_rules.py --port 8080 # Adjust delay between packets (default 0.5s) python3 trigger_rules.py --delay 1 # After running → check FMC: Analysis > Intrusion Events

Validation Checks

CheckSeverityDescription
Rule structureERRORValid header and option parentheses
Required fieldsERRORmsg, sid must be present (rev is optional)
Direction operatorERRORMust be -> or <>
Deprecated Snort 2 keywordsERRORuricontent, rawbytes, threshold, resp, react, tag, activates, activated_by, logto, session
fast_pattern:onlyERRORRemoved in Snort 3 — use plain fast_pattern
PCRE HTTP flagsERRORUppercase flags (U, I, H, D, P, C, M, S, Y, K) must be converted to sticky buffers
metadata:serviceWARNShould be extracted as standalone service: option
gid/sid/rev orderWARNShould appear at end in gid → sid → rev order
Unusual action/protocolWARNFlags non-standard action or protocol values

Snort SRU Updates

Weekly Snort 2 Subscriber Rule Update (SRU) — new, modified, and deleted rules sourced from the Talos advisory on Snort.org

Open Advisory ↗
Click Load Latest to fetch this week's SRU release notes (Snort 2 rules: new / modified / deleted).

Snort LSP Updates

Weekly Snort 3 Lightweight Security Package (LSP) — new and modified rules sourced from the Talos advisory on Snort.org

Open Advisory ↗
Click Load Latest to fetch this week's LSP release notes (Snort 3 rules: new / modified / deleted).

ℹ Site Information

About

Site OwnerJungsub Shin (kaishin@cisco.com)
Site NameSnort 2 → Snort 3 Local Rule Converter
PurposeConverts Snort 2 local rules to Snort 3 format, provides rule optimization analysis, Python-based validator script generation, and weekly SRU/LSP update news.
Target UsersNetwork security engineers managing Cisco Secure Firewall(formerly Firepower) with custom local rules.

Features

Rule ConverterAutomated Snort 2 → 3 syntax migration with SID remapping
🔧 Conversion Algorithm — How It Works
Each rule is processed through 4 sequential passes. Comments and blank lines are preserved as-is.
① Pass 1 — Rule Parsing & Option-Level Transformation
The rule is split into header (action, protocol, IPs, ports, direction) and options (semicolon-delimited key-value pairs). A quote-aware, escape-aware tokenizer handles edge cases like semicolons inside quoted strings. Each option keyword is then transformed:
Snort 2 Keyword Action Snort 3 Result
uricontent:"X" Split into sticky buffer + content http_uri; content:"X"
flowbits:set,name Converted to host-tracked xbits xbits:set,name,track ip_src
flowbits:noalert Standalone flag conversion noalert
flowbits:reset No Snort 3 equivalent — removed + WARNING ⚠ removed
isdataat:N,rawbytes rawbytes sub-option stripped isdataat:N
file_data:mime Parameter stripped (Snort 3 uses plain file_data) file_data
fast_pattern:only :only qualifier removed (not valid in Snort 3) fast_pattern
metadata:service http service entries promoted to standalone option service:http
sameip Renamed same_ip
rawbytes, threshold, resp, react, tag, activates, activated_by, logto, session, stream_reassemble, replace Removed from Snort 3 — dropped with WARNING comment ⚠ removed
② Pass 2 — Sticky Buffer Reordering (content)
In Snort 3, a sticky buffer keyword (e.g. http_uri, http_header) must appear before its associated content option. This pass scans the option list and moves any sticky buffer that appears after a content keyword to the correct position immediately preceding it.
③ Pass 3 — PCRE HTTP Flag Conversion
Snort 2 PCRE uses single-letter HTTP flags (e.g. /pattern/Ui for URI, /pattern/Hi for header). Snort 3 replaces these with sticky buffers placed before the pcre option. This pass reads each pcre's flag string, maps it to the correct sticky buffer, inserts the buffer immediately before the pcre, and strips the HTTP flag from the PCRE modifier string.
pcre:"/pattern/Ui"  →  http_uri; pcre:"/pattern/i"
④ Pass 4 — Content Modifier Inlining
In Snort 2, positional modifiers (depth, within, offset, distance, nocase, fast_pattern) follow a content option as separate semicolon-delimited options. Snort 3 requires these to be inlined as comma-separated arguments inside the content option itself. This pass merges consecutive modifier options into the preceding content option.
content:"X"; depth:20; nocase; distance:0;
content:"X", depth 20, nocase, distance 0;
Final steps: gid, sid, rev are always sorted to the end of the options in that order. If a Start SID is specified, each rule's SID is remapped sequentially from that value, and the original→new SID mapping is persisted to localStorage for cross-session traceability.
Rule OptimizationPer-rule analysis with performance, correctness, and best-practice suggestions (Korean)
Python ValidatorGenerates a standalone validate_snort3.py script for offline rule validation
Built-in Duplicate CheckAfter conversion, automatically detects converted local rules whose SIDs fall in the Talos-managed range (1 – 999,999) and flags them as potential duplicates of Snort 3 built-in rules. Also detects content-level overlap when SIDs were remapped. Displayed below the Snort 2 vs Snort 3 diff view.
SRU / LSP UpdatesWeekly Snort 2 (SRU) and Snort 3 (LSP) rule update news sourced from Talos advisories
Feedback BoardCommunity board for bug reports, feature requests, and suggestions

Technical

HostingGitHub Pages — static site, no server
Feedback BackendCloudflare Workers + GitHub Issues API
DependenciesNone — pure HTML / CSS / JavaScript

Disclaimer

All information provided on this site is not official information from Cisco Systems. Please use it with caution. Always verify converted rules in a test environment before deployment.

💬 Feedback Board

Share your suggestions, bug reports, or ideas. Posts are visible to all visitors.

  Loading feedback...