What a Cisco ASA firewall line looks like
The syslog sample below is fed verbatim into the engine to produce every parser on this page.
<166>%ASA-4-106023: Deny tcp src outside:203.0.113.45/51234 dst inside:192.0.2.10/443 by access-group "outside_access_in"
<164>%ASA-4-106023: Deny udp src outside:198.51.100.23/40012 dst inside:192.0.2.20/53 by access-group "outside_access_in" Detected fields
The engine classified this sample as freeform and consolidated 10 fields across 2 lines. Fields marked literal were identical on every sample line, so they are baked into the pattern as anchors rather than captured.
- literal : literal
- _lit1 : literal · literal
- literal2 : literal
- _lit2 : literal · literal
- literal3 : literal
- _lit3 : literal · literal
- literal4 : literal
- _lit4 : literal · literal
- _lit5 : literal · literal
- quoted_string : quoted_string · literal
Regex (named capture groups)
# sample: <166>%ASA-4-106023: Deny tcp src outside:203.0.113.45/51234 dst inside:192.0.2.10/443 by access-group "outside_access_in"
# groups: literal=<166>%ASA-4-106023, literal2=tcp, literal3=outside:203.0.113.45/51234, literal4=inside:192.0.2.10/443
^(?<literal><\d+>%[A-Za-z]+-\d+-\d+): Deny (?<literal2>[A-Za-z]+) src (?<literal3>[A-Za-z]+:\d+\.\d+\.\d+\.\d+/\d+) dst (?<literal4>[A-Za-z]+:\d+\.\d+\.\d+\.\d+/\d+) by access-group "outside_access_in"$ Grok pattern (Logstash / Elastic)
%{DATA:literal}: Deny %{NOTSPACE:literal2} src %{NOTSPACE:literal3} dst %{NOTSPACE:literal4} by access-group "outside_access_in - note constant field "quoted_string" embedded as literal anchor "outside_access_in" (varying=false)
Wazuh decoder (OS_Regex XML)
<!--
Generated by LogForge - Wazuh decoder (OS_Regex dialect, not PCRE)
sample: <166>%ASA-4-106023: Deny tcp src outside:203.0.113.45/51234 dst inside:192.0.2.10/443 by access-group "outside_access_in"
test with: /var/ossec/bin/wazuh-logtest
-->
<decoder name="cisco-asa-freeform">
<prematch>^</prematch>
</decoder>
- note could not derive a distinctive <prematch>; the emitted anchor is permissive — tune before deploying
- note field "literal" has no safe OS_Regex pattern before the ":" terminator — template truncated; field(s) omitted: literal, _lit1, literal2, _lit2, literal3, _lit3, literal4, _lit4, _lit5, quoted_string
- note no varying fields could be captured — parent decoder emitted alone
- note decoder order and prematch specificity may need site-specific tuning (other decoders in your ruleset can shadow these) — validate with /var/ossec/bin/wazuh-logtest
rsyslog template / liblognorm rulebase
version=2
# cisco_asa — liblognorm v2 rulebase (generated by LogForge)
# Usage with rsyslog (mmnormalize runs liblognorm):
# module(load="mmnormalize")
# action(type="mmnormalize" rulebase="/etc/rsyslog.d/cisco_asa.rb" useRawMsg="on")
# Literal "%" is escaped as "%%"; raw tabs are written as \x09.
rule=cisco_asa:%literal:char-to{"extradata":":"}%: Deny %literal2:word% src %literal3:word% dst %literal4:word% by access-group "outside_access_in"
- note trailing literal "\"" reconstructed from line 1
- note chosen parser types: literal=char-to(:), literal2=word, literal3=word, literal4=word
FAQ
- What is the %ASA-x-nnnnnn tag in a Cisco ASA log?
- It is the ASA message identifier. %ASA is the device class, the single digit after it is the syslog severity (0 emergency … 7 debug), and the six-digit number is the message ID that names the specific event — 106023 for an ACL deny, 302013 for a TCP connection built, and so on. The message ID, not the free text, is what you branch on when parsing.
- Why can I not write one regex for all ASA messages?
- Because the text after the mnemonic is free-form and its structure differs per message ID. A 106023 deny, a 302013 connection-built, and a 106100 ACL-hit line arrange their fields differently. Extract the severity and message ID with a common pattern, then apply a per-message-id sub-pattern to the body — order-independent field templates keyed on the ID.
- How are addresses formatted in ASA logs?
- As interface:ip/port. The ASA prepends the interface name (outside, inside, dmz) to the address with a colon and appends the port after a slash — e.g. outside:203.0.113.45/51234. For NAT/xlate messages a translated address often follows in parentheses. This means you get the traffic direction from the interface name without a separate field.
- Which message IDs matter most for security monitoring?
- 106023 (deny by access-group) and 106100 (ACL permit/deny with hit counts) for policy enforcement, 302013/302014 (TCP built/teardown) and 302015/302016 (UDP) for connection tracking, and 305011/305012 for NAT/xlate. Alerting on 106023 grouped by source IP is the classic scan- and blocked-traffic detection.
Try it on your own Cisco ASA firewall lines
Paste a few real lines, review the detected fields, and copy whichever format your stack needs. Free, no account, nothing uploaded.
Open this sample in LogForge →