CEF Format Decoder Needed_Safeguard log

111 views
Skip to first unread message

Slavica SL

unread,
Jan 22, 2026, 7:40:05 AMJan 22
to Wazuh | Mailing List
Hello all, I have a safeguard log for which I need to create a wazuh decoder, but I only manage to decode the header. I also want to decode cs1, cs2, cs3..etc..so that I can later make rules using these.
Can you help me with the decoder?
This is the log. Can it be broken into header, cs3, cs4, cs2, cs5...or even maybe decoded to each fiels: header, cs3, start, end, cs4, spid, filepath...etc?

CEF:0|XYPRO|NONSTOP|XMA|SOFTWARE-NORM-MSGS|SAFEGUARD-NORMAL-MESSAGES|2|cs3= FFFF02F2FF5A35F858F9 start= N end= N cs4=  sproc= \DON.$X82V spid=  filePath= \DON.$SYSTEM.JON02.TACL src= 11.22.33.44 sourceDnsDomain=  dst= 11.22.33.44 dhost= \DON cs2= $B7.SAFE deviceCustomDate1= 2026-01-02 12:42:23.260437 rt= 2026-01-02 13:42:23.260437 externalId= 000000002 outcome= 1 cs6= N / N cn1= A deviceFacility= SAFEGUARD suid= 300 , 355 duid= 355 , 355 suser= pmJohn shost= \DON duser= SuperJohn fileType= ALIAS fname= SuperJohn 255.255 act= VERIFYUSER cs5= \DON.$ZPTX3.#ZWN9597 cat= 54 reason= 400 cs1=  msg= Last Logon Time 2026-01-01 09:07:40.343101 to 2026-01-02 13:42:23.238433 cn1Label=ALERTEDcs1Label=Rulenamecs2Label=ProductLocationcs3Label=SessionIDcs4Label=SessionNamecs5Label=Terminalcs6Label=Test/Warn

Olamilekan Abdullateef Ajani

unread,
Jan 22, 2026, 8:53:10 AMJan 22
to Wazuh | Mailing List
Dear Slavica,

I made a sample decoder below for your reference as requested.

<decoder name="test">
    <prematch>SAFEGUARD-NORMAL-MESSAGES</prematch>
</decoder>

<decoder name="test-body">
  <parent>test</parent>
  <regex type="pcre2">.*\|cs3=\s*([^\s]+).*?start=\s*([^\s]+).*?end=\s*([^\s]+).*?cs4=\s*([^\s]*).*?spid=\s*([^\s]*).*?filePath=\s*([^\s]+).*?src=\s*([^\s]+).*?dst=\s*([^\s]+).*?suser=\s*([^\s]+).*?duser=\s*([^\s]+).*?fileType=\s*([^\s]+).*?fname=\s*([^\s]+).*?act=\s*([^\s]+).*?msg=\s*(.+?)(?=\s+\w+Label=)</regex>
  <order>cs3,start,end,cs4,spid,filepath,srcip,dstip,suser,duser,filetype,filename,action,message</order>
</decoder>


You can test this with the Wazuh logtest engine /var/ossec/bin/wazuh-logtest then parse the shared log.
Please see attached for the result after testing. You can learn more about writing decoders from the documentation below:


Please let me know if you require further assistance on this.
safeguard-decoder.png

Slavica SL

unread,
Jan 22, 2026, 10:55:58 PMJan 22
to Wazuh | Mailing List
Dear Ajani,

Thank you very much for your help.
Your code worked fine. 
However, I just wanted to make the script more general, for all safeguard logs, to include the CEF header, and some additional fields such as dhost, deviceCustomDate1, outcome, cat, reason and maybe one or two more..but then when running the test, I get only the name.
Can you advice what am I missing?

<decoder name="Safeguard">
    <prematch>CEF:0</prematch>
</decoder>

<decoder name="SFG-B24">
  <parent>Safeguard</parent>
  <regex type="pcre2">CEF:0|(.*?)\|(.*?)\|(.*?)\|(.*?)\|(.*?)\|(\d*).*\|cs3=\s*([^\s]+).*?start=\s*([^\s]+).*?end=\s*([^\s]+).*?cs4=\s*([^\s]*).*?spid=\s*([^\s]*).*?filePath=\s*([^\s]+).*?src=\s*([^\s]+).*?dst=\s*([^\s]+).*?dhost=\s*([^\s]+).*?deviceCustomDate1=\s*([^\s]+).*?outcome=\s*([^\s]+).*?suser=\s*([^\s]+).*?duser=\s*([^\s]+).*?fileType=\s*([^\s]+).*?fname=\s*([^\s]+).*?act=\s*([^\s]+).*?cat=\s*([^\s]+).*?reason=\s*([^\s]+).*?msg=\s*(.+?)(?=\s+\w+Label=)</regex>
  <order>Vendor, Product, Version, DeviceEventClassID, EventName,Severity,cs3,start,end,cs4,spid,filepath,srcip,dstip,dhost,deviceCustomDate1,outcome,suser,duser,filetype,filename,cat,reason,action,message</order>
</decoder>

**Phase 1: Completed pre-decoding. full event: 'CEF:0|XYPRO|NONSTOP|XMA|SOFTWARE-NORM-MSGS|SAFEGUARD-NORMAL-MESSAGES|2|cs3= FFFF02F2FF5A35F858F9 start= N end= N cs4= sproc= \DON.$X82V spid= filePath= \DON.$SYSTEM.JON02.TACL src= 11.22.33.44 sourceDnsDomain= dst= 11.22.33.44 dhost= \DON cs2= $B7.SAFE deviceCustomDate1= 2026-01-02 12:42:23.260437 rt= 2026-01-02 13:42:23.260437 externalId= 000000002 outcome= 1 cs6= N / N cn1= A deviceFacility= SAFEGUARD suid= 300 , 355 duid= 355 , 355 suser= pmJohn shost= \DON duser= SuperJohn fileType= ALIAS fname= SuperJohn 255.255 act= VERIFYUSER cs5= \DON.$ZPTX3.#ZWN9597 cat= 54 reason= 400 cs1= msg= Last Logon Time 2026-01-01 09:07:40.343101 to 2026-01-02 13:42:23.238433 cn1Label=ALERTEDcs1Label=Rulenamecs2Label=ProductLocationcs3Label=SessionIDcs4Label=SessionNamecs5Label=Terminalcs6Label=Test/Warn' **Phase 2: Completed decoding. name: 'Safeguard'

Olamilekan Abdullateef Ajani

unread,
Jan 23, 2026, 8:34:47 AMJan 23
to Wazuh | Mailing List
Hello Slavica,

Based on your request, I made some changes to the decoder to reflect the extracted fields mentioned above, please see below. You can modify this at will to suit your other requirements. I noticed you mentioned a generic decoder for all logs, that may not work unless all security events follow the same structure, which I so much doubt, but you can compare the logs that seem different and modify the decoder to extract similar fields as needed.

<decoder name="Safeguard">
  <prematch>CEF:0</prematch>
</decoder>

<decoder name="SFG-B24">
  <parent>Safeguard</parent>
  <regex type="pcre2">^CEF:0\|([^|]+)\|([^|]+)\|([^|]+)\|([^|]+)\|([^|]+)\|(\d+)\|.*?cs3=\s*([^\s]+).*?start=\s*([^\s]+).*?end=\s*([^\s]+).*?cs4=\s*([^\s]*).*?spid=\s*([^\s]*).*?filePath=\s*([^\s]+).*?src=\s*([^\s]+).*?dst=\s*([^\s]+).*?dhost=\s*([^\s]+).*?deviceCustomDate1=\s*([0-9:\-\. ]+).*?outcome=\s*([^\s]+).*?suser=\s*([^\s]+).*?duser=\s*([^\s]+).*?fileType=\s*([^\s]+).*?fname=\s*([^\s]+).*?act=\s*([^\s]+).*?cat=\s*([^\s]+).*?reason=\s*([^\s]+).*?msg=\s*(.+?)(?=[A-Za-z0-9]+Label=)</regex>

  <order>Vendor,Product,Version,DeviceEventClassID,EventName,Severity,cs3,start,end,cs4,spid,filepath,srcip,dstip,dhost,deviceCustomDate1,outcome,suser,duser,filetype,filename,action,cat,reason,message</order>
</decoder>



**Phase 1: Completed pre-decoding.
        full event: 'CEF:0|XYPRO|NONSTOP|XMA|SOFTWARE-NORM-MSGS|SAFEGUARD-NORMAL-MESSAGES|2|cs3= FFFF02F2FF5A35F858F9 start= N end= N    cs4= sproc= \DON.$X82V spid= filePath= \DON.$SYSTEM.JON02.TACL src= 11.22.33.44 sourceDnsDomain= dst= 11.22.33.44 dhost= \DON cs2= $   B7.SAFE deviceCustomDate1= 2026-01-02 12:42:23.260437 rt= 2026-01-02 13:42:23.260437 externalId= 000000002 outcome= 1 cs6= N / N cn1=    A deviceFacility= SAFEGUARD suid= 300 , 355 duid= 355 , 355 suser= pmJohn shost= \DON duser= SuperJohn fileType= ALIAS fname= SuperJ   ohn 255.255 act= VERIFYUSER cs5= \DON.$ZPTX3.#ZWN9597 cat= 54 reason= 400 cs1= msg= Last Logon Time 2026-01-01 09:07:40.343101 to 202   6-01-02 13:42:23.238433 cn1Label=ALERTEDcs1Label=Rulenamecs2Label=ProductLocationcs3Label=SessionIDcs4Label=SessionNamecs5Label=Termi   nalcs6Label=Test/Warn'


**Phase 2: Completed decoding.
        name: 'Safeguard'
        DeviceEventClassID: 'SOFTWARE-NORM-MSGS'
        EventName: 'SAFEGUARD-NORMAL-MESSAGES'
        Product: 'NONSTOP'
        Severity: '2'
        Vendor: 'XYPRO'
        Version: 'XMA'
        action: 'VERIFYUSER'
        cat: '54'
        cs3: 'FFFF02F2FF5A35F858F9'
        cs4: 'sproc='
        deviceCustomDate1: '2026-01-02 12:42:23.260437 '
        dhost: '\DON'
        dstip: '11.22.33.44'
        duser: 'SuperJohn'
        end: 'N'
        filename: 'SuperJohn'
        filepath: '\DON.$SYSTEM.JON02.TACL'
        filetype: 'ALIAS'
        message: 'Last Logon Time 2026-01-01 09:07:40.343101 to 2026-01-02 13:42:23.238433 '
        outcome: '1'
        reason: '400'
        srcip: '11.22.33.44'
        start: 'N'
        suser: 'pmJohn'



You can learn more about writing decoders from the documentation below:


Please let me know if you require further assistance on this.


Slavica SL

unread,
Jan 23, 2026, 12:09:43 PMJan 23
to Wazuh | Mailing List
Hi Ajani,

Yes, you are right.

The logs follow same format, more or less same elements that I want to extract. it is just that some of the fields for some logs are empty values, some have some value, fields like src, dst, filepath etc..
I have checked several logs and some are being decoded, while the others are not, just the name: safeguard.
Probably I will have to modify the decoder, for each field to allow to be empty or with spaces, maybe + sign to be modified with *..?
Or any other idea?

Regards,
Slavica

Olamilekan Abdullateef Ajani

unread,
Jan 23, 2026, 2:04:28 PMJan 23
to Wazuh | Mailing List
Hello Slavica,

I understand the issue, some of the fields are empty. I made a change to the decoder by using the PCRE2 syntax of [^\s]+ with the lazy approach matching syntax .*? so this would ensure fields like SPID and cs4 when empty does not affect the operation of the decoder. You can inspect this decoder and use it as a template for other logs with different variations when decoding.

<decoder name="Safeguard">
  <prematch>CEF:0</prematch>
</decoder>

<decoder name="SFG-B24">
  <parent>Safeguard</parent>
  <regex type="pcre2">^CEF:0\|([^|]+)\|([^|]+)\|([^|]+)\|([^|]+)\|([^|]+)\|(\d+)\|.*?cs3=\s*(.*?)\s+start=\s*(.*?)\s+end=\s*(.*?)\s+cs4=\s*(.*?)\s+spid=\s*(.*?)\s+filePath=\s*(.*?)\s+src=\s*(.*?)\s+dst=\s*(.*?)\s+dhost=\s*(.*?)\s+deviceCustomDate1=\s*(.*?)\s+outcome=\s*(.*?)\s+suser=\s*(.*?)\s+duser=\s*(.*?)\s+fileType=\s*(.*?)\s+fname=\s*(.*?)\s+act=\s*(.*?)\s+cat=\s*(.*?)\s+reason=\s*(.*?)\s+msg=\s*(.+?)(?=\s+\w+Label=|$)</regex>

  <order>Vendor,Product,Version,DeviceEventClassID,EventName,Severity,cs3,start,end,cs4,spid,filepath,srcip,dstip,dhost,deviceCustomDate1,outcome,suser,duser,filetype,filename,action,cat,reason,message</order>
</decoder>


Please let me know if you require further assistance on this.

Regards,

Slavica SL

unread,
Jan 26, 2026, 7:02:01 AMJan 26
to Wazuh | Mailing List
Dear Ajani,

Once again, thank you very much for your support..
This code solves the issue with empty spaces..but now I am facing another issue..

If you see the result bellow, I get several elements combined in one:
 cs5 under the Action (act),
 cs2 under DestHost(dhost),
 rt and externalId under DeviceCustomDate1
 cs1 under ReasonCode (reason)
 cs6, cn1,devicefacility, suid, duid under ResultAction (outcome)
 sproc under SessionName (cs4)
 sourceDnsDomain under SourceIP (src)
 shost under SourceUser (suser)


I tried to add one by one some of these data elements separately, for example, right after act, I add cs5, and in <order> I have added Terminal (as cs5 is labeled as Terminal)
.... act=\s*(.*?)\s+cs5=\s*(.*?)\s+ ......
 
but then, I only get the name decoded..
name: 'XMA'

I am not sure where I do wrong..
If you can help me add the additional fields that are not already defined, so that all fields get decoded (the fact that some of these fields can be empty remains):

sproc= \DON.$X82V        -> SourceProcessName
sourceDnsDomain=                 -> SourceDNS
cs2= $B7.SAFE             -> ProductLocation
rt= 2026-01-02 13:42:23.260437 -> ReceiveTime
externalId= 000000002 -> ExternalId
cs6= N / N -> Test/Warn
cn1= A -> Alerted
deviceFacility= SAFEGUARD -> DeviceFacility
suid= 300 , 355 -> SourceUserId
duid= 355 , 355 -> DestUserId
shost= \DON -> SourceHostName
cs5= \DON.$ZPTX3.#ZWN9597 -> Terminal
cs1=   -> RuleName

This is the last code from you, slighly changed in the names:

<decoder name="XMA">

  <prematch>CEF:0</prematch>
</decoder>

<decoder name="XMA-B24">
  <parent>XMA</parent>

  <regex type="pcre2">^CEF:0\|([^|]+)\|([^|]+)\|([^|]+)\|([^|]+)\|([^|]+)\|(\d+)\|.*?cs3=\s*(.*?)\s+start=\s*(.*?)\s+end=\s*(.*?)\s+cs4=\s*(.*?)\s+spid=\s*(.*?)\s+filePath=\s*(.*?)\s+src=\s*(.*?)\s+dst=\s*(.*?)\s+dhost=\s*(.*?)\s+deviceCustomDate1=\s*(.*?)\s+outcome=\s*(.*?)\s+suser=\s*(.*?)\s+duser=\s*(.*?)\s+fileType=\s*(.*?)\s+fname=\s*(.*?)\s+act=\s*(.*?)\s+cat=\s*(.*?)\s+reason=\s*(.*?)\s+msg=\s*(.+?)(?=\s+\w+Label=|$)</regex>

 <order>Vendor,Product,Version,DeviceEventClassID,EventName,Severity,SessionId,start,end,SessionName,SourceProcessID,FilePath,SourceIP,DestIP,DestHost,DeviceCustomDate1,ResultAction,SourceUser,DestUser,FileType,FileName,Action,EventCategory,ReasonCode,EventMessage</order>
</decoder>

The log

CEF:0|XYPRO|NONSTOP|XMA|SOFTWARE-NORM-MSGS|SAFEGUARD-NORMAL-MESSAGES|2|cs3= FFFF02F2FF5A35F858F9 start= N end= N cs4=  sproc= \DON.$X82V spid=  filePath= \DON.$SYSTEM.JON02.TACL src= 11.22.33.44 sourceDnsDomain=  dst= 11.22.33.44 dhost= \DON cs2= $B7.SAFE deviceCustomDate1= 2026-01-02 12:42:23.260437 rt= 2026-01-02 13:42:23.260437 externalId= 000000002 outcome= 1 cs6= N / N cn1= A deviceFacility= SAFEGUARD suid= 300 , 355 duid= 355 , 355 suser= pmJohn shost= \DON duser= SuperJohn fileType= ALIAS fname= SuperJohn 255.255 act= VERIFYUSER cs5= \DON.$ZPTX3.#ZWN9597 cat= 54 reason= 400 cs1=  msg= Last Logon Time 2026-01-01 09:07:40.343101 to 2026-01-02 13:42:23.238433 cn1Label=ALERTEDcs1Label=Rulenamecs2Label=ProductLocationcs3Label=SessionIDcs4Label=SessionNamecs5Label=Terminalcs6Label=Test/Warn

The result

**Phase 1: Completed pre-decoding.
full event: 'CEF:0|XYPRO|NONSTOP|XMA|SOFTWARE-NORM-MSGS|SAFEGUARD-NORMAL-MESSAGES|2|cs3= FFFF02F2FF5A35F858F9 start= N end= N cs4=  sproc= \DON.$X82V spid=  filePath= \DON.$SYSTEM.JON02.TACL src= 11.22.33.44 sourceDnsDomain=  dst= 11.22.33.44 dhost= \DON cs2= $B7.SAFE deviceCustomDate1= 2026-01-02 12:42:23.260437 rt= 2026-01-02 13:42:23.260437 externalId= 000000002 outcome= 1 cs6= N / N cn1= A deviceFacility= SAFEGUARD suid= 300 , 355 duid= 355 , 355 suser= pmJohn shost= \DON duser= SuperJohn fileType= ALIAS fname= SuperJohn 255.255 act= VERIFYUSER cs5= \DON.$ZPTX3.#ZWN9597 cat= 54 reason= 400 cs1=  msg= Last Logon Time 2026-01-01 09:07:40.343101 to 2026-01-02 13:42:23.238433 cn1Label=ALERTEDcs1Label=Rulenamecs2Label=ProductLocationcs3Label=SessionIDcs4Label=SessionNamecs5Label=Terminalcs6Label=Test/Warn'

**Phase 2: Completed decoding.
name: 'XMA'
Action: 'VERIFYUSER cs5= \DON.$ZPTX3.#ZWN9597'
DestHost: '\DON cs2= $B7.SAFE'
DestIP: '11.22.33.44'
DestUser: 'SuperJohn'
DeviceCustomDate1: '2026-01-02 12:42:23.260437 rt= 2026-01-02 13:42:23.260437 externalId= 000000002'
DeviceEventClassID: 'SOFTWARE-NORM-MSGS'
EventCategory: '54'
EventMessage: 'Last Logon Time 2026-01-01 09:07:40.343101 to 2026-01-02 13:42:23.238433'
EventName: 'SAFEGUARD-NORMAL-MESSAGES'
FileName: 'SuperJohn 255.255'
FilePath: '\DON.$SYSTEM.JON02.TACL'
FileType: 'ALIAS'
Product: 'NONSTOP'
ReasonCode: '400 cs1='
ResultAction: '1 cs6= N / N cn1= A deviceFacility= SAFEGUARD suid= 300 , 355 duid= 355 , 355'
SessionId: 'FFFF02F2FF5A35F858F9'
SessionName: 'sproc= \DON.$X82V'
Severity: '2'
SourceIP: '11.22.33.44 sourceDnsDomain='
SourceUser: 'pmJohn shost= \DON'
Vendor: 'XYPRO'
Version: 'XMA'
end: 'N'
start: 'N'

Olamilekan Abdullateef Ajani

unread,
Jan 26, 2026, 10:14:59 AMJan 26
to Wazuh | Mailing List
Hello Slavica,

I see the problem you mentioned. I have tweaked the decoder a bit to reflect that, please see below and the screenshot attached. I also tested it. Remeber, the logs may vary sometimes, you may need to review the logs against the decoder and tweak where necessary.

<decoder name="Safeguard">
  <prematch>CEF:0</prematch>
</decoder>
<decoder name="Safeguard-b24">
  <parent>safeguard</parent>
  <regex type="pcre2">^CEF:0\|([^|]*)\|([^|]*)\|([^|]*)\|([^|]*)\|([^|]*)\|(\d+)\|.*?cs3=\s*(\S+).*?start=\s*(\S+).*?end=\s*(\S+).*?cs4=\s*(.*?)(?=\s+\w+=).*?spid=\s*(.*?)(?=\s+\w+=).*?filePath=\s*(.*?)(?=\s+\w+=).*?src=\s*(\S*).*?dst=\s*(\S*).*?dhost=\s*(.*?)(?=\s+\w+=).*?cs2=\s*(.*?)(?=\s+\w+=).*?deviceCustomDate1=\s*([0-9:\-\. ]+).*?rt=\s*([0-9:\-\. ]+).*?externalId=\s*(\S+).*?outcome=\s*(\S+).*?suser=\s*(\S+).*?shost=\s*(.*?)(?=\s+\w+=).*?duser=\s*(\S+).*?fileType=\s*(\S+).*?fname=\s*(.*?)(?=\s+act=).*?act=\s*(\S+).*?cs5=\s*(.*?)(?=\s+\w+=).*?cat=\s*(\S+).*?reason=\s*(\S+).*?msg=\s*(.+?)(?=\s+\w+Label=|$)</regex>
  <order>Vendor,Product,Version,DeviceEventClassID,EventName,Severity,cs3,start,end,cs4,spid,filepath,srcip,dstip,dhost,cs2,deviceCustomDate1,rt,externalId,outcome,suser,shost,duser,filetype,filename,action,cs5,cat,reason,message</order>
</decoder>



Best regards,
safeguard.png

Slavica SL

unread,
Jan 27, 2026, 3:49:44 AMJan 27
to Wazuh | Mailing List
Hello Ajani,

when I try to save the new code, I receive the following error:

Could not upload decoder (1113) - XML syntax error
Error: Could not upload decoder (1113) - XML syntax error at WzRequest.returnErrorInstance (https://xx.yy.zz.123/414101/bundles/plugin/wazuh/wazuh.plugin.js:1:504035) at WzRequest.apiReq (https://xx.yy.zz.123/414101/bundles/plugin/wazuh/wazuh.plugin.js:1:503177) at async resources_handler_ResourcesHandler.updateFile (https://xx.yy.zz.123/414101/bundles/plugin/wazuh/wazuh.chunk.2.js:1:4155809) at async file_editor_WzFileEditor.save (https://xx.yy.zz.123/414101/bundles/plugin/wazuh/wazuh.chunk.2.js:1:4224844)

Regards,Slavica
Close

Olamilekan Abdullateef Ajani

unread,
Jan 27, 2026, 7:22:38 AMJan 27
to Wazuh | Mailing List
Hello Slavica,

Apologies for the error, the issue is with the parent decoder reference. Please replace the safeguard with Safeguard.

decoder name="Safeguard">
  <prematch>CEF:0</prematch>
</decoder>
<decoder name="Safeguard-b24">
  <parent>Safeguard</parent>

Regards,

Slavica SL

unread,
Jan 28, 2026, 5:09:12 AMJan 28
to Wazuh | Mailing List
Hello Ajani,

Thank you very much for your support.
With this last code and change, I've got many of the logs not decoded, but I have changed externalId and duser  and I was managed to decode most of the logs I have..
.*?externalId=\s*(\S+)->.*?externalId=\s*(\S*)
.*?duser=\s*(\S+)     ->.*?duser=\s*(\S*)     

I think, I will go with this one, and see how it goes.
Thank you once again for your great support.

Regards,
Slavica
Reply all
Reply to author
Forward
0 new messages