[cisco_ise] Fix NPE in foreach acme-av-pair null guard. - #20622
Conversation
✅ Elastic Docs Style Checker (Vale)No issues found on modified lines! The Vale linter checks documentation changes against the Elastic Docs style guide. To use Vale locally or report issues, refer to Elastic style guide for Vale. |
|
Pinging @elastic/integration-experience (Team:Integration-Experience) |
🚀 Benchmarks reportTo see the full report comment with |
| - foreach: | ||
| tag: foreach_cisco_ise_log_log_details_acme-av-pair_72a6fe4c | ||
| if: "ctx.cisco_ise?.log?.log_details['acme-av-pair'] != null && ctx.cisco_ise?.log?.log_details['acme-av-pair'] instanceof List" | ||
| if: "ctx.cisco_ise?.log?.log_details != null && ctx.cisco_ise.log.log_details['acme-av-pair'] != null && ctx.cisco_ise.log.log_details['acme-av-pair'] instanceof List" |
There was a problem hiding this comment.
Severity: 🟡 Medium confidence: high path: packages/cisco_ise/data_stream/log/elasticsearch/ingest_pipeline/pipeline_failed_attempts.yml:275
The same unguarded log_details map access that is fixed here still exists in two sibling pipelines of this data stream; add the identical log_details != null guard to pipeline_radius_accounting.yml and pipeline_authentication_flow_diagnostics.yml so those categories do not keep hitting the NPE.
Details
The guard added here is correct: ctx.cisco_ise?.log?.log_details returns null when the kv processor that builds log_details was skipped, and Painless then throws on the ['acme-av-pair'] index access because ?. does not propagate through a map subscript. The same expression shape is still present, unguarded, in two other pipelines of the same data stream:
packages/cisco_ise/data_stream/log/elasticsearch/ingest_pipeline/pipeline_radius_accounting.ymlline 261 -ctx.cisco_ise?.log?.log_details['Event-Timestamp'] != nullpackages/cisco_ise/data_stream/log/elasticsearch/ingest_pipeline/pipeline_authentication_flow_diagnostics.ymlline 166 -ctx.cisco_ise?.log?.log_details['NAS-IP-Address'] != null
Both of those pipelines have the identical preconditions that make log_details absent: they grok cisco_ise.log.log_details_raw for segments where cisco_ise.log.segment.number > 0, then feed it to the same kv processor (field_split: ', (?=[^,=]+=)') with ignore_failure: true. A continuation segment starts with a value fragment that has no =, so the kv processor throws on the first token, is swallowed by ignore_failure, and cisco_ise.log.log_details is never created - exactly the case this PR reproduces for CISE_Failed_Attempts. CISE_RADIUS_Accounting and CISE_Authentication_Flow_Diagnostics messages segment the same way, so those two conditions will throw on the same input class and route the event to the pipeline on_failure handler as event.kind: pipeline_error.
Since this PR already bumps the package version and adds the changelog entry, folding the two remaining occurrences in keeps the bug class closed in one release rather than leaving two known NPEs behind.
Recommendation:
Apply the same null guard to the two remaining conditions.
pipeline_radius_accounting.yml (line 261):
if: ctx.cisco_ise?.log?.log_details != null && ctx.cisco_ise.log.log_details['Event-Timestamp'] != nullpipeline_authentication_flow_diagnostics.yml (line 166):
if: ctx.cisco_ise?.log?.log_details != null && ctx.cisco_ise.log.log_details['NAS-IP-Address'] != nullAn equivalent single-expression form that is also null-safe, if you prefer it over the two-part guard:
if: ctx.cisco_ise?.log?.log_details?.get('Event-Timestamp') != null🤖 AI-Generated Review | Vera Review Bot | 📚 Knowledge base: integration-skills
⚠️ Automated review — verify suggestions before applying.
|
✅ All changelog entries have the correct PR link. |
| <182>Apr 27 11:11:47 hijk.xyz.com CISE_RADIUS_Accounting 0000070618 1 0 2020-04-27 11:11:47.028075 -08:00 0091827141 3000 NOTICE Radius-Accounting: RADIUS Accounting start request, ConfigVersionId=33, Device IP Address=81.2.69.145, RequestLatency=6, NetworkDeviceName=WNBU-WLC1, User-Name=nisehorrrrn, NAS-IP-Address=81.2.69.145, NAS-Port=13, Framed-IP-Address=89.160.20.112, Class=CACS:0a2025060001794f52cfa877:hijk.xyz.com/176956368/1092772, Called-Station-ID=00-24-97-69-7a-c0, Calling-Station-ID=d4-ca-6d-14-87-3b, NAS-Identifier=Acme_fe:56:00, Acct-Status-Type=Start, Acct-Session-Id=00000000/d4:ca:6d:14:87:3b/20879, Acct-Authentic=RADIUS, Event-Timestamp=1389340795, NAS-Port-Type=Wireless - IEEE 802.11, Tunnel-Type=(tag=0) VLAN, Tunnel-Medium-Type=(tag=0) 802, Tunnel-Private-Group-ID=(tag=0) 70, Airespace-Wlan-Id=1, AcsSessionID=hijk.xyz.com/176956368/1092777, SelectedAccessService=Default Network Access, Step=11004, Step=11017, Step=15049, Step=15008, Step=15048, Step=15048, Step=15048, Step=15004, Step=15006, Step=11005, NetworkDeviceGroups=Location#All Locations#SJC#WNBU, NetworkDeviceGroups=Device Type#All Device Types#Wireless#WLC, CPMSessionID=0a222bc0000000d123e111f0, AllowedProtocolMatchedRule=Default, Location=Location#All Locations#SJC#WNBU, Device Type=Device Type#All Device Types#Wireless#WLC | ||
| <182>Apr 27 11:18:08 tuv.w.xyz.com CISE_RADIUS_Accounting 0000142722 1 0 2020-04-27 11:18:08.144167 -08:00 0096217580 3001 NOTICE Radius-Accounting: RADIUS Accounting stop request, ConfigVersionId=33, Device IP Address=81.2.69.145, RequestLatency=4, NetworkDeviceName=WNBU-WLC1, User-Name=businesskent, NAS-IP-Address=81.2.69.145, NAS-Port=13, Framed-IP-Address=89.160.20.112, Class=CACS:0a202506000193a252d04b55:tuv.w.xyz.com/176956368/1154568, Called-Station-ID=00-24-97-69-7a-c0, Calling-Station-ID=5c-0a-5b-43-3f-79, NAS-Identifier=Cisco_fe:56:00, Acct-Status-Type=Stop, Acct-Delay-Time=0, Acct-Input-Octets=43000, Acct-Output-Octets=140998, Acct-Session-Id=0000AAAA/5c:0a:5b:43:3f:79/24927, Acct-Authentic=RADIUS, Acct-Session-Time=209, Acct-Input-Packets=471, Acct-Output-Packets=262, Acct-Terminate-Cause=User Request, undefined-52= | ||
| <182>Apr 27 11:18:08 tuv.w.xyz.com CISE_RADIUS_Accounting 0000142672 2 1 ConfigVersionId=35, Device IP Address=81.2.69.144, RequestLatency=8, NetworkDeviceName=WNBU-WLC1, User-Name=businesskent, NAS-IP-Address=81.2.69.145, NAS-Port=17, Framed-IP-Address=89.160.20.112, Class=CACS:0a202506000193a252d04b55:tuv.w.xyz.com/176956368/1154568, Called-Station-ID=00-24-97-69-7a-c0, Calling-Station-ID=5c-0a-5b-43-3f-79, NAS-Identifier=Cisco_fe:56:00, Acct-Status-Type=Stop, Acct-Delay-Time=0, Acct-Input-Octets=43000, Acct-Output-Octets=140998, Acct-Session-Id=0000AAAA/5c:0a:5b:43:3f:79/24927, Acct-Authentic=RADIUS, Acct-Session-Time=209, Acct-Input-Packets=471, Acct-Output-Packets=262, Acct-Terminate-Cause=User Request, undefined-52= | ||
| <182>Jun 27 17:54:40 host-1.example.local CISE_RADIUS_Accounting 000000001234 3 2 alice.johnson, StepData=15=EXAMPLE-AD, TotalAuthenLatency=27, ClientLatency=0, Response={AuthenticationResult=Failed; Authen-Reply-Status=Fail; }, |
There was a problem hiding this comment.
Severity: 🔵 Low confidence: medium path: packages/cisco_ise/data_stream/log/_dev/test/pipeline/test-pipeline-radius-accounting.log:4
The new regression fixtures are continuation segments with no timestamp in the message body, so @timestamp is derived from the year-less syslog header and the expected files pin 2026 - these two tests will fail once the calendar year rolls over. Use a segment-0 line carrying a full ISO timestamp instead.
Details
This line and the matching one in test-pipeline-authentication-flow-diagnostics.log (line 11) are segment 2 of 3, so the sub-pipeline's segment>0 grok extracts only log_details_raw and never a body timestamp. @timestamp therefore comes from default.yml's MMM [ ]d[d] HH:mm:ss parse of the syslog header, which has no year, so the ingest date processor fills in the current year. The regenerated expected files hard-code "2026-06-27T17:54:40.000Z"; from 2027-01-01 the same input parses to 2027-06-27 and both pipeline tests fail.
This is not introduced by the PR - the pre-existing Mar 28 continuation line in the authentication-flow fixture has the same property (expected "2026-03-28T11:23:25.000Z") - but the delta adds two more year-dependent cases. It is avoidable here: the regression only needs cisco_ise.log.log_details to be absent, which happens because the first token of log_details_raw (alice.johnson) has no =, so the kv processor throws and is swallowed by its ignore_failure: true. A segment-0 line reproduces that identically while also carrying a body ISO timestamp that pins the year.
Recommendation:
Make the fixture a first segment so the body timestamp (which includes an explicit year and offset) drives @timestamp, keeping the value-less leading token that makes the kv fail and leaves log_details absent:
<182>Jun 27 17:54:40 host-1.example.local CISE_RADIUS_Accounting 000000001234 1 0 2026-06-27 17:54:40.000 +00:00 000000005678 3000 NOTICE Radius-Accounting: RADIUS Accounting start request, alice.johnson, StepData=15=EXAMPLE-AD,
Apply the same shape to test-pipeline-authentication-flow-diagnostics.log (line 11) and regenerate both -expected.json files with elastic-package test pipeline -g.
🤖 AI-Generated Review | Vera Review Bot | 📚 Knowledge base: integration-skills
⚠️ Automated review — verify suggestions before applying.
Review summaryIssues found across the latest commits f56443a — 1 low
Issues found across earlier commits 87d896f — 1 medium
🤖 AI-Generated Review | Vera Review Bot | 📚 Knowledge base: integration-skills
|
💚 Build Succeeded
History
|
|
Tick the box to add this pull request to the merge queue (same as
|
|
Package cisco_ise - 1.32.11 containing this change is available at https://epr.elastic.co/package/cisco_ise/1.32.11/ |
Executive summary
Four
ifconditions inpipeline_failed_attempts.ymlwere updated to guard againstlog_detailsbeing null before accessing its keys. Previously, expressions likectx.cisco_ise?.log?.log_details['acme-av-pair']would throw a NullPointerException in theforeachprocessor whenlog_detailsitself was absent — the safe-navigation operator?.only protects against null at theloglevel, not when subscript-accessing a null map. The fix adds an explicitctx.cisco_ise?.log?.log_details != nullpre-check to all four affected conditions, preventing the NPE for non-first segments of multi-segmentCISE_Failed_Attemptsmessages that carry nolog_detailspayload.Proposed commit message
Root cause
The
foreachprocessor'sifcondition uses bracket notation (ctx.cisco_ise?.log?.log_details['acme-av-pair']) without first guarding againstlog_detailsitself being null. In Painless,?.only suppresses the null dereference of the property it directly precedes; whencisco_ise.log.log_detailsis absent (as it legitimately is for non-first segments of a multi-segment CISE_Failed_Attempts message, where the KV parser produces no output),null['acme-av-pair']throws a NullPointerException that causes theforeachprocessor to fail and propagates to the pipeline'son_failurehandler.Approach
Add an explicit
ctx.cisco_ise?.log?.log_details != nullguard as the first condition in both theforeachand companionkvprocessorifexpressions inpipeline_failed_attempts.yml. Theforeachcondition at line 275 currently goes straight to bracket accessctx.cisco_ise?.log?.log_details['acme-av-pair']— Painless's?.only protects the immediate property step, so whenlog_detailsis absent the subsequent bracket dereference throws a NullPointerException. Adding the null guard mirrors the pattern already used inpipeline_passed_authentications.ymlandpipeline_tacacs_accounting.ymlfor the equivalentcisco-av-pairandUser-Namefields. A new test fixture line for the multi-segment (segment > 0, nolog_details) case will be added to exercise the fixed path.Implementation
packages/cisco_ise/data_stream/log/elasticsearch/ingest_pipeline/pipeline_failed_attempts.yml, change theforeachprocessorifcondition at line 275 fromctx.cisco_ise?.log?.log_details['acme-av-pair'] != null && ctx.cisco_ise?.log?.log_details['acme-av-pair'] instanceof Listtoctx.cisco_ise?.log?.log_details != null && ctx.cisco_ise.log.log_details['acme-av-pair'] != null && ctx.cisco_ise.log.log_details['acme-av-pair'] instanceof List.kvprocessorifcondition at line 290 fromctx.cisco_ise?.log?.log_details['acme-av-pair'] != null && !(ctx.cisco_ise?.log?.log_details['acme-av-pair'] instanceof List)toctx.cisco_ise?.log?.log_details != null && ctx.cisco_ise.log.log_details['acme-av-pair'] != null && !(ctx.cisco_ise.log.log_details['acme-av-pair'] instanceof List).acme-av-pairand nolog_details) as a new entry at the end ofpackages/cisco_ise/data_stream/log/_dev/test/pipeline/test-pipeline-failed-attempts.log.packages/cisco_ise/data_stream/log/_dev/test/pipeline/test-pipeline-failed-attempts.log-expected.jsonfor the new test case, verifyingevent.kindisevent(notpipeline_error) and noerror.messageis set.packages/cisco_ise/manifest.yml(1.32.6 → 1.32.7) and prepend abugfixchangelog entry inpackages/cisco_ise/changelog.yml.elastic-package test pipeline -C packages/cisco_iseto validate the fix and confirm all test cases pass.Pipeline changes
foreachprocessor (tagforeach_cisco_ise_log_log_details_acme-av-pair_72a6fe4c)ifcondition: prependctx.cisco_ise?.log?.log_details != null &&before the existing bracket access, and change remaining?.log?.log_details[references in that condition to.log.log_details[(safe after the null guard).kvprocessor (tagkv_cisco_ise_log_log_details_acme-av-pair_to_cisco_ise_log_acme-av-pair_6cc5cb52)ifcondition: apply the same null guard prepend so both processors are consistent.Field / mapping changes
—
Sanitized error message
Processor 'foreach' with tag 'foreach_cisco_ise_log_log_details_acme-av-pair_72a6fe4c' in pipeline 'logs-cisco_ise.log-pipeline_failed_attempts' failed with message '[on_failure_message]'Sanitized log (
event_sanitizedexcerpt)<181>Jun 27 17:54:40 host-1.example.local CISE_Failed_Attempts 000000001234 3 2 alice.johnson, StepData=15=EXAMPLE-AD, TotalAuthenLatency=27, ClientLatency=0, IsMachineIdentity=false, UserAccountControl=512, Model Name=Unknown, Software Version=Unknown, Network Device Profile=Cisco, Location=Location#All Locations, Device Type=Device Type#All Device Types#CORE#Cisco, IPSEC=IPSEC#Is IPSEC Device#No, Migrated_NDGs=Migrated_NDGs#All Migrated_NDGs, Response={AuthenticationResult=Failed; Authen-Reply-Status=Fail; },Reviewer concerns
https://github.com/elastic/integrations/pull/1— this placeholder should be updated to the real PR URL before merge.@timestamp(2026-06-27T17:54:40.000Z) is in the future relative to today (2026-08-06), which is fine functionally but reviewers should be aware the sample log line has a forward-dated timestamp.acme-av-pairandUser-Nameguard conditions were patched; any other processors in the pipeline that similarly subscript intolog_detailswithout a prior null-check could still be vulnerable — worth a broader audit.Self-review findings
—
Risk and classification
Links
5bec7fbc40d5bca1