[Security Solution][Endpoint Exceptions] Fixes bug where behavior alerts do not show nested code signatures with subject name and trusted field#212325
Conversation
|
Pinging @elastic/security-defend-workflows (Team:Defend Workflows) |
rylnd
left a comment
There was a problem hiding this comment.
I gave a quick review on behalf of Detection Engine; I can't really speak to the logic involved in the helpers here (either before or after this change), but the tests are comprehensive and do a good job of documentation.
I did notice some type issues (which it looks like CI caught), so just request another review when this is green 👍 .
P.S. should we maybe create a separate file for endpoint-specific exceptions helpers? That way Detection Engine wouldn't need to co-own this large helpers file.
| export const getFileCodeSignature = ( | ||
| alertData: Flattened<Ecs> | ||
| ): Array<{ subjectName: string; trusted: string }> => { | ||
| ): Array<{ field: string; type: 'nested'; entries: EntriesArray }> => { |
There was a problem hiding this comment.
Is this return type correct? The explicit object being returned below doesn't seem to conform to this type.
tomsonpl
left a comment
There was a problem hiding this comment.
Hey, sorry for coming late with the review, but I was waiting until all cases mentioned by @sukhwindersingh-qasource are fixed. Maybe I should have done more thorough review earlier, sorry!
I have a few issues I've found in this PR that I would suggest you take a look at:
1. Code Duplication
There's significant duplication across the following functions:
getFileCodeSignature
getProcessCodeSignature
getDllCodeSignature
Each function follows the same pattern:
- Check if the entity exists
- Check if it has an Ext property with code_signature
- If yes, call getCodeSignatureValue with the code signature
- Otherwise, check if it has a direct code_signature property with trusted === true
- If yes, return a specific array structure
2. Complex Conditional Checks
Multiple nested checks like dll && dll.Ext && dll.Ext.code_signature or if ('entries' in entry && entry.entries !== undefined) { make the code harder to read and maintain.
3. entriesToAdd
- Nested Conditionals: The function contains multiple nested if-else statements, making it hard to follow the logic.
- Repetitive Code: The pattern of calling addIdToEntries(filterEmptyExceptionEntries(...)) is repeated in each branch.
- Implicit Dependencies: The function relies on variables from the outer scope (isLinux, processCodeSignature, dllCodeSignature, commonFields).
Conclusion
I've put some recommendations closer to the code, however I haven't really run these changes so please take a look, verify and apply if you feel they make sense.
Although there are some places to consider improving, in general I think you did a great job with covering all these crazy edge cases 👍
| export const getFileCodeSignature = ( | ||
| alertData: Flattened<Ecs> | ||
| ): Array<{ subjectName: string; trusted: string }> => { | ||
| export const getFileCodeSignature = (alertData: Flattened<Ecs>): EntriesArrayOrUndefined => { |
There was a problem hiding this comment.
I believe all the 3 similar functions can be replaced with a single generic function, similar to this one: please verify your all edge cases.
/**
* Generic function to get code signature entries from any entity
*/
export const getEntityCodeSignature = <T extends { Ext?: { code_signature?: CodeSignature[] | CodeSignature }, code_signature?: CodeSignature }>(
entity: T | undefined,
fieldPrefix: string
): EntriesArrayOrUndefined => {
if (!entity) return undefined;
// Check Ext.code_signature first
if (entity.Ext?.code_signature) {
return getCodeSignatureValue(entity.Ext.code_signature, `${fieldPrefix}.Ext.code_signature`);
}
// Then check direct code_signature
if (entity.code_signature?.trusted === true) {
return [
{
field: `${fieldPrefix}.code_signature.subject_name`,
operator: 'included' as const,
type: 'match' as const,
value: entity.code_signature?.subject_name ?? '',
},
{
field: `${fieldPrefix}.code_signature.trusted`,
operator: 'included' as const,
type: 'match' as const,
value: entity.code_signature.trusted.toString(),
},
];
}
return undefined;
};
There was a problem hiding this comment.
Then use it like this:
export const getFileCodeSignature = (alertData: Flattened<Ecs>): EntriesArrayOrUndefined =>
getEntityCodeSignature(alertData.file, 'file');
| export const getProcessCodeSignature = ( | ||
| alertData: Flattened<Ecs> | ||
| ): Array<{ subjectName: string; trusted: string }> => { | ||
| export const getProcessCodeSignature = (alertData: Flattened<Ecs>): EntriesArrayOrUndefined => { |
There was a problem hiding this comment.
Use the generic function:
export const getProcessCodeSignature = (alertData: Flattened<Ecs>): EntriesArrayOrUndefined =>
getEntityCodeSignature(alertData.process, 'process');
| * `dll.Ext.code_signature` or 'dll.code_signature` | ||
| * as long as the `trusted` field is `true`. | ||
| */ | ||
| export const getDllCodeSignature = (alertData: Flattened<Ecs>): EntriesArrayOrUndefined => { |
There was a problem hiding this comment.
Use the generic function:
export const getDllCodeSignature = (alertData: Flattened<Ecs>): EntriesArrayOrUndefined =>
getEntityCodeSignature(alertData.dll, 'dll');
| */ | ||
| export const getDllCodeSignature = (alertData: Flattened<Ecs>): EntriesArrayOrUndefined => { | ||
| const { dll } = alertData; | ||
| const codeSignature = dll && dll.Ext && dll.Ext.code_signature; |
There was a problem hiding this comment.
Try something like this:
const codeSignature = alertData.dll?.Ext?.code_signature;
| * Pre 7.10 `Ext.code_signature` fields were mistakenly populated as | ||
| * a single object with subject_name and trusted. | ||
| */ | ||
| export const getCodeSignatureValue = ( |
There was a problem hiding this comment.
The current implementation has complex logic for handling both array and single object cases. Consider simplifying:
export const getCodeSignatureValue = (
codeSignature: Flattened<CodeSignature> | FlattenedCodeSignature[] | undefined,
field: string
): EntryNested[] | undefined => {
// Convert to array if it's a single object
const signatures = Array.isArray(codeSignature) ? codeSignature : codeSignature ? [codeSignature] : [];
// Filter and map in one operation
const entries = signatures
.filter(signature => signature?.trusted === true)
.map(signature => ({
field,
type: 'nested' as const,
entries: [
{
field: 'subject_name',
operator: 'included' as const,
type: 'match' as const,
value: signature?.subject_name ?? '',
},
{
field: 'trusted',
operator: 'included' as const,
type: 'match' as const,
value: signature.trusted.toString(),
},
],
}));
return entries.length > 0 ? entries : undefined;
};
Not sure if I covered all the edge cases again, so please verify. But I think this might improve the maintainability of the code.
| for (const entry of entries) { | ||
| if (entry.entries !== undefined) { | ||
| entry.entries = entry.entries.filter((el) => el.value !== undefined && el.value.length > 0); | ||
| if ('entries' in entry && entry.entries !== undefined) { |
There was a problem hiding this comment.
I assume these 'entries' in entry and 'value' in entry checks are only here acting as Type Guards? If so, maybe it would be clearer to move them outside:
function hasEntries(entry: any): entry is { entries: any[] } {
return 'entries' in entry && entry.entries !== undefined;
}
function hasValue(entry: any): entry is { value: string } {
return 'value' in entry && entry.value !== undefined && entry.value.length > 0;
}
There was a problem hiding this comment.
And even further, we can use the optional chaining operator ?. to simplify things eg.:
el?.value?.length > 0
| ]); | ||
| ]; | ||
|
|
||
| const entriesToAdd = () => { |
There was a problem hiding this comment.
This is a tricky one, what do you think about something like this? :
function prepareEntries(...fieldArrays: EntriesArray[]): EntriesArray {
// Combine all field arrays
const combinedFields = fieldArrays.flat();
// Filter empty entries and add IDs
return addIdToEntries(filterEmptyExceptionEntries(combinedFields));
}
const entriesToAdd = () => {
if (!isLinux) {
const signatures = [];
if (processCodeSignature) signatures.push(processCodeSignature);
if (dllCodeSignature) signatures.push(dllCodeSignature);
if (signatures.length > 0) {
return prepareEntries(commonFields, ...signatures);
}
}
return prepareEntries(commonFields);
};
This could be used in both: getPrepopulatedBehaviorException and getPrepopulatedRansomwareException
There was a problem hiding this comment.
The reason for doing it is to limit the number of if/else statements, not sure again if I covered all edge cases though.
|
@elasticmachine merge upstream |
Hi Ryland - Thanks, yeah we are going to try to move all endpoint related code out at some point, but it will probably have to be for another PR |
💛 Build succeeded, but was flaky
Failed CI StepsMetrics [docs]Public APIs missing comments
Async chunks
History
|
|
Starting backport for target branches: 8.19 https://github.com/elastic/kibana/actions/runs/14912315842 |
…rts do not show nested code signatures with subject name and trusted field (elastic#212325) ## Summary When navigating to the endpoint exceptions form from an alert, we pre-populate certain exceptions fields based on the type of alert. There was a bug for behavior alerts where we did not use the proper nested `code_signature` field for windows and mac endpoints. Instead of showing the nested `code_signature` field that has the `subject_name` and `trusted` sub-fields, we only showed non-nested `code_signature subject field. This PR also refactors the code to account for the following behaviors that we want: - [x] If `field.Ext.code_signature` is present, we want to use the nested `code_signature` subject field with the `subject_name` and `trusted` sub-fields for - [x] If `field.Ext.code_signature` is not present, we will default to the non-nested `field.code_signature.subject_name` and `field.code_signature.trusted` field pair. - [x] We will only show non-empty pre-populated values and also only code signature values with the `trusted` field set to `true` - [x] Pre-populated code signature fields are only present in windows and mac OSes. - [x] Behavior, ransomware and default alerts had the code_signature adjustments - [x] Previously the code duplicated a set of the pre-populated fields PER code signature. Now, each pre-populated field is only shown once, followed by all valid code_signatures. - [x] Does not allow duplicate code signatures # SCREENSHOTS Behavior alert w/ nested `process.Ext.code_signature` and non-nested `dll.code_signature` fields  Malware alert w/ nested `file.Ext.code_signature` <img width="1281" alt="image" src="https://github.com/user-attachments/assets/4845c6e5-5567-49df-b66a-1b9a2e6410db" /> --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com> (cherry picked from commit 76e256c)
💚 All backports created successfully
Note: Successful backport PRs will be merged automatically after passing CI. Questions ?Please refer to the Backport tool documentation |
|
Looks like this PR has a backport PR but it still hasn't been merged. Please merge it ASAP to keep the branches relatively in sync. |
4 similar comments
|
Looks like this PR has a backport PR but it still hasn't been merged. Please merge it ASAP to keep the branches relatively in sync. |
|
Looks like this PR has a backport PR but it still hasn't been merged. Please merge it ASAP to keep the branches relatively in sync. |
|
Looks like this PR has a backport PR but it still hasn't been merged. Please merge it ASAP to keep the branches relatively in sync. |
|
Looks like this PR has a backport PR but it still hasn't been merged. Please merge it ASAP to keep the branches relatively in sync. |
…ior alerts do not show nested code signatures with subject name and trusted field (#212325) (#220553) # Backport This will backport the following commits from `main` to `8.19`: - [[Security Solution][Endpoint Exceptions] Fixes bug where behavior alerts do not show nested code signatures with subject name and trusted field (#212325)](#212325) <!--- Backport version: 9.6.6 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) <!--BACKPORT [{"author":{"name":"Candace Park","email":"56409205+parkiino@users.noreply.github.com"},"sourceCommit":{"committedDate":"2025-05-08T17:22:42Z","message":"[Security Solution][Endpoint Exceptions] Fixes bug where behavior alerts do not show nested code signatures with subject name and trusted field (#212325)\n\n## Summary\n\nWhen navigating to the endpoint exceptions form from an alert, we\npre-populate certain exceptions fields based on the type of alert. There\nwas a bug for behavior alerts where we did not use the proper nested\n`code_signature` field for windows and mac endpoints. Instead of showing\nthe nested `code_signature` field that has the `subject_name` and\n`trusted` sub-fields, we only showed non-nested `code_signature subject\nfield. This PR also refactors the code to account for the following\nbehaviors that we want:\n- [x] If `field.Ext.code_signature` is present, we want to use the\nnested `code_signature` subject field with the `subject_name` and\n`trusted` sub-fields for\n- [x] If `field.Ext.code_signature` is not present, we will default to\nthe non-nested `field.code_signature.subject_name` and\n`field.code_signature.trusted` field pair.\n- [x] We will only show non-empty pre-populated values and also only\ncode signature values with the `trusted` field set to `true`\n- [x] Pre-populated code signature fields are only present in windows\nand mac OSes.\n- [x] Behavior, ransomware and default alerts had the code_signature\nadjustments\n- [x] Previously the code duplicated a set of the pre-populated fields\nPER code signature. Now, each pre-populated field is only shown once,\nfollowed by all valid code_signatures.\n- [x] Does not allow duplicate code signatures \n\n\n\n# SCREENSHOTS \n\nBehavior alert w/ nested `process.Ext.code_signature` and non-nested\n`dll.code_signature` fields\n\n\n\nMalware alert w/ nested `file.Ext.code_signature`\n<img width=\"1281\" alt=\"image\"\nsrc=\"https://github.com/user-attachments/assets/4845c6e5-5567-49df-b66a-1b9a2e6410db\"\n/>\n\n---------\n\nCo-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>\nCo-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>","sha":"76e256ccffd6fb59fd4212be68e5a1da9915a9fb","branchLabelMapping":{"^v9.1.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","Team:Defend Workflows","ci:project-deploy-security","Team:obs-ux-management","backport:version","v9.1.0","v8.19.0"],"title":"[Security Solution][Endpoint Exceptions] Fixes bug where behavior alerts do not show nested code signatures with subject name and trusted field","number":212325,"url":"https://github.com/elastic/kibana/pull/212325","mergeCommit":{"message":"[Security Solution][Endpoint Exceptions] Fixes bug where behavior alerts do not show nested code signatures with subject name and trusted field (#212325)\n\n## Summary\n\nWhen navigating to the endpoint exceptions form from an alert, we\npre-populate certain exceptions fields based on the type of alert. There\nwas a bug for behavior alerts where we did not use the proper nested\n`code_signature` field for windows and mac endpoints. Instead of showing\nthe nested `code_signature` field that has the `subject_name` and\n`trusted` sub-fields, we only showed non-nested `code_signature subject\nfield. This PR also refactors the code to account for the following\nbehaviors that we want:\n- [x] If `field.Ext.code_signature` is present, we want to use the\nnested `code_signature` subject field with the `subject_name` and\n`trusted` sub-fields for\n- [x] If `field.Ext.code_signature` is not present, we will default to\nthe non-nested `field.code_signature.subject_name` and\n`field.code_signature.trusted` field pair.\n- [x] We will only show non-empty pre-populated values and also only\ncode signature values with the `trusted` field set to `true`\n- [x] Pre-populated code signature fields are only present in windows\nand mac OSes.\n- [x] Behavior, ransomware and default alerts had the code_signature\nadjustments\n- [x] Previously the code duplicated a set of the pre-populated fields\nPER code signature. Now, each pre-populated field is only shown once,\nfollowed by all valid code_signatures.\n- [x] Does not allow duplicate code signatures \n\n\n\n# SCREENSHOTS \n\nBehavior alert w/ nested `process.Ext.code_signature` and non-nested\n`dll.code_signature` fields\n\n\n\nMalware alert w/ nested `file.Ext.code_signature`\n<img width=\"1281\" alt=\"image\"\nsrc=\"https://github.com/user-attachments/assets/4845c6e5-5567-49df-b66a-1b9a2e6410db\"\n/>\n\n---------\n\nCo-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>\nCo-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>","sha":"76e256ccffd6fb59fd4212be68e5a1da9915a9fb"}},"sourceBranch":"main","suggestedTargetBranches":["8.19"],"targetPullRequestStates":[{"branch":"main","label":"v9.1.0","branchLabelMappingKey":"^v9.1.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/212325","number":212325,"mergeCommit":{"message":"[Security Solution][Endpoint Exceptions] Fixes bug where behavior alerts do not show nested code signatures with subject name and trusted field (#212325)\n\n## Summary\n\nWhen navigating to the endpoint exceptions form from an alert, we\npre-populate certain exceptions fields based on the type of alert. There\nwas a bug for behavior alerts where we did not use the proper nested\n`code_signature` field for windows and mac endpoints. Instead of showing\nthe nested `code_signature` field that has the `subject_name` and\n`trusted` sub-fields, we only showed non-nested `code_signature subject\nfield. This PR also refactors the code to account for the following\nbehaviors that we want:\n- [x] If `field.Ext.code_signature` is present, we want to use the\nnested `code_signature` subject field with the `subject_name` and\n`trusted` sub-fields for\n- [x] If `field.Ext.code_signature` is not present, we will default to\nthe non-nested `field.code_signature.subject_name` and\n`field.code_signature.trusted` field pair.\n- [x] We will only show non-empty pre-populated values and also only\ncode signature values with the `trusted` field set to `true`\n- [x] Pre-populated code signature fields are only present in windows\nand mac OSes.\n- [x] Behavior, ransomware and default alerts had the code_signature\nadjustments\n- [x] Previously the code duplicated a set of the pre-populated fields\nPER code signature. Now, each pre-populated field is only shown once,\nfollowed by all valid code_signatures.\n- [x] Does not allow duplicate code signatures \n\n\n\n# SCREENSHOTS \n\nBehavior alert w/ nested `process.Ext.code_signature` and non-nested\n`dll.code_signature` fields\n\n\n\nMalware alert w/ nested `file.Ext.code_signature`\n<img width=\"1281\" alt=\"image\"\nsrc=\"https://github.com/user-attachments/assets/4845c6e5-5567-49df-b66a-1b9a2e6410db\"\n/>\n\n---------\n\nCo-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>\nCo-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>","sha":"76e256ccffd6fb59fd4212be68e5a1da9915a9fb"}},{"branch":"8.19","label":"v8.19.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"}]}] BACKPORT--> Co-authored-by: Candace Park <56409205+parkiino@users.noreply.github.com> Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
…rts do not show nested code signatures with subject name and trusted field (elastic#212325) ## Summary When navigating to the endpoint exceptions form from an alert, we pre-populate certain exceptions fields based on the type of alert. There was a bug for behavior alerts where we did not use the proper nested `code_signature` field for windows and mac endpoints. Instead of showing the nested `code_signature` field that has the `subject_name` and `trusted` sub-fields, we only showed non-nested `code_signature subject field. This PR also refactors the code to account for the following behaviors that we want: - [x] If `field.Ext.code_signature` is present, we want to use the nested `code_signature` subject field with the `subject_name` and `trusted` sub-fields for - [x] If `field.Ext.code_signature` is not present, we will default to the non-nested `field.code_signature.subject_name` and `field.code_signature.trusted` field pair. - [x] We will only show non-empty pre-populated values and also only code signature values with the `trusted` field set to `true` - [x] Pre-populated code signature fields are only present in windows and mac OSes. - [x] Behavior, ransomware and default alerts had the code_signature adjustments - [x] Previously the code duplicated a set of the pre-populated fields PER code signature. Now, each pre-populated field is only shown once, followed by all valid code_signatures. - [x] Does not allow duplicate code signatures # SCREENSHOTS Behavior alert w/ nested `process.Ext.code_signature` and non-nested `dll.code_signature` fields  Malware alert w/ nested `file.Ext.code_signature` <img width="1281" alt="image" src="https://github.com/user-attachments/assets/4845c6e5-5567-49df-b66a-1b9a2e6410db" /> --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
…rts do not show nested code signatures with subject name and trusted field (elastic#212325) ## Summary When navigating to the endpoint exceptions form from an alert, we pre-populate certain exceptions fields based on the type of alert. There was a bug for behavior alerts where we did not use the proper nested `code_signature` field for windows and mac endpoints. Instead of showing the nested `code_signature` field that has the `subject_name` and `trusted` sub-fields, we only showed non-nested `code_signature subject field. This PR also refactors the code to account for the following behaviors that we want: - [x] If `field.Ext.code_signature` is present, we want to use the nested `code_signature` subject field with the `subject_name` and `trusted` sub-fields for - [x] If `field.Ext.code_signature` is not present, we will default to the non-nested `field.code_signature.subject_name` and `field.code_signature.trusted` field pair. - [x] We will only show non-empty pre-populated values and also only code signature values with the `trusted` field set to `true` - [x] Pre-populated code signature fields are only present in windows and mac OSes. - [x] Behavior, ransomware and default alerts had the code_signature adjustments - [x] Previously the code duplicated a set of the pre-populated fields PER code signature. Now, each pre-populated field is only shown once, followed by all valid code_signatures. - [x] Does not allow duplicate code signatures # SCREENSHOTS Behavior alert w/ nested `process.Ext.code_signature` and non-nested `dll.code_signature` fields  Malware alert w/ nested `file.Ext.code_signature` <img width="1281" alt="image" src="https://github.com/user-attachments/assets/4845c6e5-5567-49df-b66a-1b9a2e6410db" /> --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
Summary
When navigating to the endpoint exceptions form from an alert, we pre-populate certain exceptions fields based on the type of alert. There was a bug for behavior alerts where we did not use the proper nested
code_signaturefield for windows and mac endpoints. Instead of showing the nestedcode_signaturefield that has thesubject_nameandtrustedsub-fields, we only showed non-nested `code_signature subject field. This PR also refactors the code to account for the following behaviors that we want:field.Ext.code_signatureis present, we want to use the nestedcode_signaturesubject field with thesubject_nameandtrustedsub-fields forfield.Ext.code_signatureis not present, we will default to the non-nestedfield.code_signature.subject_nameandfield.code_signature.trustedfield pair.trustedfield set totrueSCREENSHOTS
Behavior alert w/ nested

process.Ext.code_signatureand non-nesteddll.code_signaturefieldsMalware alert w/ nested

file.Ext.code_signature