indicator-enrichment
Enriches indicators from a provided list or a block of free text. This script detects the indicator type and runs the correct underlying enrichment script. Currently supports: IP, URL, Domain, CVE, and File.
python · Aggregated Scripts
Details
| ID | indicator-enrichment |
|---|---|
| Language | python |
| From Version | 8.0.0 |
| Docker Image | demisto/python3:3.12.13.10116658 |
| Tags | basescript enrichment |
README
Enriches indicators from a provided list or a block of free text. This script detects the indicator type and runs the correct underlying enrichment script. Currently supports: IP, URL, Domain, CVE, and File.
Script Data
| Name | Description |
|---|---|
| Script Type | python3 |
| Tags | basescript, enrichment |
| Cortex XSOAR Version | 6.10.0 |
Inputs
| Argument Name | Description |
|---|---|
| indicator_list | Accepts a list of indicators to enrich. - From CLI: Provide a comma-separated list. If an indicator contains a comma, wrap the indicators in a JSON array. Example: “[\“https://example.com/search?tags=red,yellow,green\”, \“https://example2.com\”]”. - From Context: Pass JSON arrays directly, without modification. |
| text | Free text to be parsed for indicators. The script will run !extractIndicators to retrieve the underlying indicators within the text. |
| external_enrichment | Whether to call external integrations for enrichment: - ‘true’: enrich using enabled external integrations (e.g., VirusTotal (API v3), AlienVault OTX v2) and run internal commands. - ‘false’: use only existing TIM data and run internal commands; skip external integrations. If the ‘brands’ argument is provided, this flag is ignored and enrichment/internal commands will run only on the brands provided. |
| brands | A comma separated list of integration brands to run enrichment against. Example: `“VirusTotal (API v3), AlienVault OTX v2”`. - If provided, only the selected brands are used. Specifying brands will force enable external_enrichment. - If left empty, the script runs enrichment on all enabled integrations. |
| additional_fields | When set to true, the output for each enrichment command includes an `AdditionalFields` object for each of the indicator results. `AdditionalFields` contains all fields returned by TIM or the integrations that are not part of the standard output keys: `Address`, `DetectionEngines`, `PositiveDetections`, `Score`, and `Brand`. When set to false, only the standard keys are returned. |
| raw_context | If true, will also append the underlying enrichment command outputs to the context. (For backwards compatibility). |
| ignore_indicator_limit | By default, the script enforces a 100 indicator limit to maintain performance. If more than 100 unique indicators are found, the script will stop and return an error. Set this argument to true to bypass this limit and process all found indicators. Note: Bypassing the limit is not recommended as it may impact performance. |
Outputs
| Path | Description | Type |
|---|---|---|
| IndicatorEnrichment.Status | The overall status of the script execution. “Success”, “Failed”. | String |
| IndicatorEnrichment.Message | A success message if the command runs successfully, otherwise a message that contains the error. | String |
| IndicatorEnrichment.Results | A list of all indicators found. | Array |
| IndicatorEnrichment.Results.Type | The detected indicator type (e.g., “IP”, “URL”) that triggered this enrichment. | String |
| IndicatorEnrichment.Results.Value | The indicator value. (e.g, IP, URL). | string |
| IndicatorEnrichment.Results.MaxScore | The max score of all the indicators found. | number |
| IndicatorEnrichment.Results.MaxVerdict | The max verdict of all the indicators found. | string |
| IndicatorEnrichment.Results.TIMScore | The TIM score of the indicator. | number |
| IndicatorEnrichment.TIMCVSS | The max CVSS of the indicator. | number |
| IndicatorEnrichment.Results.Status | The status of the indicator: “Manual” if the score was changed manually, “Fresh” if modified within the last week, “Stale” if modified more than a week ago, and “None” if never modified. | string |
| IndicatorEnrichment.Results.ModifiedTime | The time the indicator was last modified. | Date |
| IndicatorEnrichment.Results.Results | A list of all the underlying script results for the valid indicators. | array |
| IndicatorEnrichment.Results.Results.Source | The source of the indicator. | string |
| IndicatorEnrichment.Results.Results.Brand | The brand of the indicator. | string |
| IndicatorEnrichment.Results.Results.DetectionEngines | The detection engines of the indicator. | number |
| IndicatorEnrichment.Results.Results.PositiveDetections | The positive detections of the indicator. | number |
| IndicatorEnrichment.Results.Results.ASOwner | Registered owner of the Autonomous System announcing the IP prefix. | string |
| IndicatorEnrichment.Results.Results.Score | The score of the indicator. | number |
| IndicatorEnrichment.Results.Results.Verdict | The verdict of the indicator. | string |
| IndicatorEnrichment.Results.Results.Address | The IP address of the indicator. | string |
| IndicatorEnrichment.Results.Data | The URL of the indicator. | string |
| IndicatorEnrichment.Results.Name | The Domain of the indicator. | string |
| IndicatorEnrichment.Results.Results.Reliability | The reliability of the Brand. | string |
| IndicatorEnrichment.Results.Results.AdditionalFields | All fields extracted from the indicator other then the main keys (“Brand”, “Score”, “Verdict”, “DetectionEngines”, “PositiveDetections”, “Address”). | list |
| IndicatorEnrichment.Results.Results.AdditionalFields.Relationships.EntityA | The source of the relationship. | string |
| IndicatorEnrichment.Results.Results.AdditionalFields.Relationships.EntityB | The destination of the relationship. | string |
| IndicatorEnrichment.Results.Results.AdditionalFields.Relationships.Relationship | The name of the relationship. | string |
| IndicatorEnrichment.Results.Results.AdditionalFields.Relationships.EntityAType | The type of the source of the relationship. | string |
| IndicatorEnrichment.Results.Results.AdditionalFields.Relationships.EntityBType | The type of the destination of the relationship. | string |
| IndicatorEnrichment.Results.Results.AdditionalFields.Category | The category associated with the indicator. | String |
| IndicatorEnrichment.Results.Results.AdditionalFields.ASN | The autonomous system name for the IP address, for example: “AS8948”. | String |
| IndicatorEnrichment.Results.Results.AdditionalFields.Hostname | The hostname that is mapped to this IP address. | String |
| IndicatorEnrichment.Results.Results.AdditionalFields.DNS | A list of IP objects resolved by DNS. | String |
| IndicatorEnrichment.Results.Results.AdditionalFields.Geo.Location | The geolocation where the IP address or Domain is located, in the format: latitude:longitude. | String |
| IndicatorEnrichment.Results.Results.AdditionalFields.Geo.Country | The country in which the IP address is located. | String |
| IndicatorEnrichment.Results.Results.AdditionalFields.Geo.Description | Additional information about the location. | String |
| IndicatorEnrichment.Results.Results.AdditionalFields.Malicious.Vendor | The vendor reporting the IP address as malicious. | String |
| IndicatorEnrichment.Results.Results.AdditionalFields.Malicious.Description | A description explaining why the IP address was reported as malicious. | String |
| IndicatorEnrichment.Results.Results.AdditionalFields.Tags | (List) Tags of the Indicator. | Unknown |
| IndicatorEnrichment.Results.Results.AdditionalFields.FeedRelatedIndicators.value | Indicators that are associated with the given indicator value. | String |
| IndicatorEnrichment.Results.Results.AdditionalFields.FeedRelatedIndicators.type | The type of the indicators that are associated with the given indicator value. | String |
| IndicatorEnrichment.Results.Results.AdditionalFields.FeedRelatedIndicators.description | The description of the indicators that are associated with the given indicator value. | String |
| IndicatorEnrichment.Results.Results.AdditionalFields.MalwareFamily | The malware family associated with the given indicator. | String |
| IndicatorEnrichment.Results.Results.AdditionalFields.Organization.Name | The organization of the IP. | String |
| IndicatorEnrichment.Results.Results.AdditionalFields.Organization.Type | The organization type of the IP. | String |
| IndicatorEnrichment.Results.Results.AdditionalFields.Region | The region in which the IP is located. | String |
| IndicatorEnrichment.Results.Results.AdditionalFields.Port | Ports that are associated with the Indicator. | String |
| IndicatorEnrichment.Results.Results.AdditionalFields.Internal | Whether or not the indicator is internal or external. | Bool |
| IndicatorEnrichment.Results.Results.AdditionalFields.UpdatedDate | The date that the indicator was last updated. | Date |
| IndicatorEnrichment.Results.Results.AdditionalFields.Billing | Billing address of the domain. | String |
| IndicatorEnrichment.Results.Results.AdditionalFields.Tech.Country | The country of the domain technical contact. | String |
| IndicatorEnrichment.Results.Results.AdditionalFields.Tech.Name | The name of the domain technical contact. | String |
| IndicatorEnrichment.Results.Results.AdditionalFields.Tech.Organization | The organization of the domain technical contact. | String |
| IndicatorEnrichment.Results.Results.AdditionalFields.Tech.Email | The email address of the domain technical contact. | String |
| IndicatorEnrichment.Results.Results.AdditionalFields.DomainIDNName | The internationalized domain name (IDN) of the domain. | String |
| IndicatorEnrichment.Results.Results.AdditionalFields.ExpirationDate | The expiration date of the domain. | Date |
| IndicatorEnrichment.Results.Results.AdditionalFields.DomainStatus | The status of the domain. | Date |
| IndicatorEnrichment.Results.Results.AdditionalFields.NameServers | (List<String>) Name servers of the domain. | Unknown |
| IndicatorEnrichment.Results.Results.AdditionalFields.Organization | The organization of the domain. | String |
| IndicatorEnrichment.Results.Results.AdditionalFields.Subdomains | (List<String>) Subdomains of the domain. | Unknown |
| IndicatorEnrichment.Results.Results.AdditionalFields.Admin.Country | The country of the domain administrator. | String |
| IndicatorEnrichment.Results.Results.AdditionalFields.Admin.Email | The email address of the domain administrator. | String |
| IndicatorEnrichment.Results.Results.AdditionalFields.Admin.Name | The name of the domain administrator. | String |
| IndicatorEnrichment.Results.Results.AdditionalFields.Admin.Phone | The phone number of the domain administrator. | String |
| IndicatorEnrichment.Results.Results.AdditionalFields.Registrant.Country | The country of the registrant. | String |
| IndicatorEnrichment.Results.Results.AdditionalFields.Registrant.Email | The email address of the registrant. | String |
| IndicatorEnrichment.Results.Results.AdditionalFields.Registrant.Name | The name of the registrant. | String |
| IndicatorEnrichment.Results.Results.AdditionalFields.Registrant.Phone | The phone number to receive abuse reports. | String |
| IndicatorEnrichment.Results.Results.AdditionalFields.WHOIS.NameServers | (List<String>) Name servers of the domain. | String |
| IndicatorEnrichment.Results.Results.AdditionalFields.WHOIS.CreationDate | The date that the domain was created. | Date |
| IndicatorEnrichment.Results.Results.AdditionalFields.WHOIS.UpdatedDate | The date that the domain was last updated. | Date |
| IndicatorEnrichment.Results.Results.AdditionalFields.WHOIS.ExpirationDate | The expiration date of the domain. | Date |
| IndicatorEnrichment.Results.Results.AdditionalFields.WHOIS.Registrant.Name | The name of the registrant. | String |
| IndicatorEnrichment.Results.Results.AdditionalFields.WHOIS.Registrant.Email | The email address of the registrant. | String |
| IndicatorEnrichment.Results.Results.AdditionalFields.WHOIS.Registrant.Phone | The phone number of the registrant. | String |
| IndicatorEnrichment.Results.Results.AdditionalFields.WHOIS.Registrar.Name | The name of the registrar, for example, GoDaddy. | String |
| IndicatorEnrichment.Results.Results.AdditionalFields.WHOIS.Registrar.AbuseEmail | The email address of the contact to report abuse. | String |
| IndicatorEnrichment.Results.Results.AdditionalFields.WHOIS.Registrar.AbusePhone | The phone number of the contact to report abuse. | String |
| IndicatorEnrichment.Results.Results.AdditionalFields.WHOIS.Admin.Name | The name of the domain administrator. | String |
| IndicatorEnrichment.Results.Results.AdditionalFields.WHOIS.Admin.Email | The email address of the domain administrator. | String |
| IndicatorEnrichment.Results.Results.AdditionalFields.WHOIS.Admin.Phone | The phone number of the domain administrator. | String |
| IndicatorEnrichment.Results.Results.AdditionalFields.WHOIS.History | List of Whois objects. | String |
| IndicatorEnrichment.Results.Results.CVSS | The CVSS of the indicator. | number |
| IndicatorEnrichment.Results.Results.Description | The description of the indicator. | string |
| IndicatorEnrichment.Results.Results.Published | The published date of the indicator. | string |
| IndicatorEnrichment.Results.Results.AdditionalFields.CreationDate | The date when the domain was created. | Date |
| IndicatorEnrichment.Results.Results.AdditionalFields.ExpirationDate | The expiration date of the domain. | Date |
| IndicatorEnrichment.Results.Results.AdditionalFields.Registrar.Abuse.Name | The name of the contact for reporting abuse. | String |
| IndicatorEnrichment.Results.Results.AdditionalFields.Registrar.Abuse.Address | The address of the contact for reporting abuse. | String |
| IndicatorEnrichment.Results.Results.AdditionalFields.Registrar.Abuse.Country | The country of the contact for reporting abuse. | String |
| IndicatorEnrichment.Results.Results.AdditionalFields.Registrar.Abuse.Network | The network of the contact for reporting abuse. | String |
| IndicatorEnrichment.Results.Results.AdditionalFields.Registrar.Abuse.Phone | The phone number of the contact for reporting abuse. | String |
| IndicatorEnrichment.Results.Results.AdditionalFields.Registrar.Abuse.Email | The email address of the contact for reporting abuse. | String |
| IndicatorEnrichment.Results.Results.AdditionalFields.Campaign | The campaign associated with the Indicator. | String |
| IndicatorEnrichment.Results.Results.AdditionalFields.TrafficLightProtocol | The Traffic Light Protocol (TLP) color that is suitable for the IP/Domain. | String |
| IndicatorEnrichment.Results.Results.AdditionalFields.CommunityNotes.note | Notes on the IP that were given by the community. | String |
| IndicatorEnrichment.Results.Results.AdditionalFields.CommunityNotes.timestamp | The time in which the note was published. | Date |
| IndicatorEnrichment.Results.Results.AdditionalFields.Publications.source | The source in which the article was published. | String |
| IndicatorEnrichment.Results.Results.AdditionalFields.Publications.title | The name of the article. | String |
| IndicatorEnrichment.Results.Results.AdditionalFields.Publications.link | A link to the original article. | String |
| IndicatorEnrichment.Results.Results.AdditionalFields.Publications.timestamp | The time in which the article was published. | Date |
| IndicatorEnrichment.Results.Results.AdditionalFields.ThreatTypes.threatcategory | The threat category associated to this indicator by the source vendor, for example, Phishing, Control, TOR, etc. | String |
| IndicatorEnrichment.Results.Results.AdditionalFields.ThreatTypes.threatcategoryconfidence | Threat Category Confidence is the confidence level provided by the vendor for the threat type category. For example, a confidence level of 90 for the ‘malware’ threat type category means that the vendor is confident that its 90% malware. | String |
| Core.AnalyticsPrevalence.Ip.value | Whether the IP address is prevalent or not. | Boolean |
| Core.AnalyticsPrevalence.Ip.data.global_prevalence.value | The global prevalence of the IP. | Number |
| Core.AnalyticsPrevalence.Ip.data.local_prevalence.value | The local prevalence of the IP. | Number |
| Core.AnalyticsPrevalence.Ip.data.prevalence.value | The prevalence of the IP. | Number |
| EndpointData.Hostname.value | The endpoint’s hostname. | String |
| EndpointData.Hostname.source | The vendor from which the hostname of this endpoint was retrieved. | String |
| EndpointData.EntityA.value | The source of the relationship. | String |
| EndpointData.EntityA.source | The vendor from which EntityA of this endpoint was retrieved. | String |
| EndpointData.EntityB.value | The destination of the relationship. | String |
| EndpointData.EntityB.source | The vendor from which EntityB of this endpoint was retrieved. | String |
| EndpointData.Relationship.value | The name of the relationship. | String |
| EndpointData.Relationship.source | The vendor from which the relationship of this endpoint was retrieved. | String |
| EndpointData.EntityAType.value | The type of the source of the relationship. | String |
| EndpointData.EntityAType.source | The vendor from which the type of the source of the relationship of this endpoint was retrieved. | String |
| EndpointData.EntityBType.value | The type of the destination of the relationship. | String |
| EndpointData.EntityBType.source | The vendor from which the type of the destination of the relationship of this endpoint was retrieved. | String |
| EndpointData.ID.value | The endpoint’s ID. | String |
| EndpointData.ID.source | The vendor from which the ID of this endpoint was retrieved. | String |
| EndpointData.IPAddress | The endpoint’s IP address. | String |
| EndpointData.Domain.value | The endpoint’s domain. | String |
| EndpointData.Domain.source | The vendor from which the domain of this endpoint was retrieved. | String |
| EndpointData.MACAddress.value | The endpoint’s MAC address. | String |
| EndpointData.MACAddress.source | The vendor from which the MAC address of this endpoint was retrieved. | String |
| EndpointData.DHCPServer.value | The DHCP server of the endpoint. | String |
| EndpointData.DHCPServer.source | The vendor from which the DHCP server of this endpoint was retrieved. | String |
| EndpointData.OS.value | The endpoint’s operating system. | String |
| EndpointData.OS.source | The vendor from which the operating system of this endpoint was retrieved. | String |
| EndpointData.OSVersion.value | The endpoint’s operating system version. | String |
| EndpointData.OSVersion.source | The vendor from which the operating system version of this endpoint was retrieved. | String |
| EndpointData.BIOSVersion.value | The endpoint’s BIOS version. | String |
| EndpointData.BIOSVersion.source | The vendor from which the BIOS version of this endpoint was retrieved. | String |
| EndpointData.Model.value | The model of the machine or device. | String |
| EndpointData.Model.source | The vendor from which the model of this endpoint was retrieved. | String |
| EndpointData.Memory.value | Amount of memory on this endpoint. | Integer |
| EndpointData.Memory.source | The vendor from which the amount of memory of this endpoint was retrieved. | String |
| EndpointData.Processors.value | The number of processors. | Integer |
| EndpointData.Processors.source | The vendor from which the processors of this endpoint was retrieved. | String |
| EndpointData.Processor.value | The model of the processor. | String |
| EndpointData.Processor.source | The vendor from which the processor of this endpoint was retrieved. | String |
| EndpointData.IsIsolated.value | The endpoint’s isolation status. | String |
| EndpointData.IsIsolated.source | The vendor from which the isolation of this endpoint was retrieved. | String |
| EndpointData.Status.value | The endpoint’s status. | String |
| EndpointData.Status.source | The vendor from which the status of this endpoint was retrieved. | String |
| EndpointData.Vendor.value | The integration name of the endpoint vendor. | String |
| EndpointData.Vendor.source | The vendor from which the Vendor of this endpoint was retrieved. | String |
| IndicatorEnrichment.Failed | Audit log of all the inputs/indicators that were not successfully sent to an enrichment script. Weather the type is unsupported, unknown or some internal fatal error. | Array |
| IndicatorEnrichment.Failed.Value | The indicator value that failed. | String |
| IndicatorEnrichment.Failed.Type | The detected type of the indicator that failed. | String |
| IndicatorEnrichment.Failed.Error | The reason for the failure (e.g., “Unsupported indicator type”). | String |
| IPEnrichment.Value | The IP address. | string |
| IPEnrichment.MaxScore | The max score of all the indicators found. | number |
| IPEnrichment.MaxVerdict | The max verdict of all the indicators found. | string |
| IPEnrichment.TIMScore | The TIM score of the IP address. | number |
| IPEnrichment.Results | A list of all indicators found for the IP address. | array |
| IPEnrichment.Status | The status of the indicator: “Manual” if the score was changed manually, “Fresh” if modified within the last week, “Stale” if modified more than a week ago, and “None” if never modified. | string |
| IPEnrichment.ModifiedTime | The time the indicator was last modified. | Date |
| IPEnrichment.Results.Source | The source of the indicator. | string |
| IPEnrichment.Results.Brand | The brand of the indicator. | string |
| IPEnrichment.Results.DetectionEngines | The detection engines of the indicator. | number |
| IPEnrichment.Results.PositiveDetections | The positive detections of the indicator. | number |
| IPEnrichment.Results.ASOwner | Registered owner of the Autonomous System announcing the IP prefix. | string |
| IPEnrichment.Results.Score | The score of the indicator. | number |
| IPEnrichment.Results.Verdict | The verdict of the indicator. | string |
| IPEnrichment.Results.Address | The IP address of the indicator. | string |
| IPEnrichment.Results.Reliability | The reliability of the Brand. | string |
| IPEnrichment.Results.AdditionalFields | All fields extracted from the indicator other then the main keys (“Brand”, “Score”, “Verdict”, “DetectionEngines”, “PositiveDetections”, “Address”). | list |
| IPEnrichment.Results.AdditionalFields.Relationships.EntityA | The source of the relationship. | string |
| IPEnrichment.Results.AdditionalFields.Relationships.EntityB | The destination of the relationship. | string |
| IPEnrichment.Results.AdditionalFields.Relationships.Relationship | The name of the relationship. | string |
| IPEnrichment.Results.AdditionalFields.Relationships.EntityAType | The type of the source of the relationship. | string |
| IPEnrichment.Results.AdditionalFields.Relationships.EntityBType | The type of the destination of the relationship. | string |
| IPEnrichment.Results.AdditionalFields.ASN | The autonomous system name for the IP address, for example: “AS8948”. | String |
| IPEnrichment.Results.AdditionalFields.Hostname | The hostname that is mapped to this IP address. | String |
| IPEnrichment.Results.AdditionalFields.Geo.Location | The geolocation where the IP address is located, in the format: latitude:longitude. | String |
| IPEnrichment.Results.AdditionalFields.Geo.Country | The country in which the IP address is located. | String |
| IPEnrichment.Results.AdditionalFields.Geo.Description | Additional information about the location. | String |
| IPEnrichment.Results.AdditionalFields.Malicious.Vendor | The vendor reporting the IP address as malicious. | String |
| IPEnrichment.Results.AdditionalFields.Malicious.Description | A description explaining why the IP address was reported as malicious. | String |
| IPEnrichment.Results.AdditionalFields.Tags | (List) Tags of the IP. | Unknown |
| IPEnrichment.Results.AdditionalFields.FeedRelatedIndicators.value | Indicators that are associated with the IP. | String |
| IPEnrichment.Results.AdditionalFields.FeedRelatedIndicators.type | The type of the indicators that are associated with the IP. | String |
| IPEnrichment.Results.AdditionalFields.FeedRelatedIndicators.description | The description of the indicators that are associated with the IP. | String |
| IPEnrichment.Results.AdditionalFields.MalwareFamily | The malware family associated with the IP. | String |
| IPEnrichment.Results.AdditionalFields.Organization.Name | The organization of the IP. | String |
| IPEnrichment.Results.AdditionalFields.Organization.Type | The organization type of the IP. | String |
| IPEnrichment.Results.AdditionalFields.Region | The region in which the IP is located. | String |
| IPEnrichment.Results.AdditionalFields.Port | Ports that are associated with the IP. | String |
| IPEnrichment.Results.AdditionalFields.Internal | Whether or not the IP is internal or external. | Bool |
| IPEnrichment.Results.AdditionalFields.UpdatedDate | The date that the IP was last updated. | Date |
| IPEnrichment.Results.AdditionalFields.Registrar.Abuse.Name | The name of the contact for reporting abuse. | String |
| IPEnrichment.Results.AdditionalFields.Registrar.Abuse.Address | The address of the contact for reporting abuse. | String |
| IPEnrichment.Results.AdditionalFields.Registrar.Abuse.Country | The country of the contact for reporting abuse. | String |
| IPEnrichment.Results.AdditionalFields.Registrar.Abuse.Network | The network of the contact for reporting abuse. | String |
| IPEnrichment.Results.AdditionalFields.Registrar.Abuse.Phone | The phone number of the contact for reporting abuse. | String |
| IPEnrichment.Results.AdditionalFields.Registrar.Abuse.Email | The email address of the contact for reporting abuse. | String |
| IPEnrichment.Results.AdditionalFields.Campaign | The campaign associated with the IP. | String |
| IPEnrichment.Results.AdditionalFields.TrafficLightProtocol | The Traffic Light Protocol (TLP) color that is suitable for the IP. | String |
| IPEnrichment.Results.AdditionalFields.CommunityNotes.note | Notes on the IP that were given by the community. | String |
| IPEnrichment.Results.AdditionalFields.CommunityNotes.timestamp | The time in which the note was published. | Date |
| IPEnrichment.Results.AdditionalFields.Publications.source | The source in which the article was published. | String |
| IPEnrichment.Results.AdditionalFields.Publications.title | The name of the article. | String |
| IPEnrichment.Results.AdditionalFields.Publications.link | A link to the original article. | String |
| IPEnrichment.Results.AdditionalFields.Publications.timestamp | The time in which the article was published. | Date |
| IPEnrichment.Results.AdditionalFields.ThreatTypes.threatcategory | The threat category associated to this indicator by the source vendor, for example, Phishing, Control, TOR, etc. | String |
| IPEnrichment.Results.AdditionalFields.ThreatTypes.threatcategoryconfidence | Threat Category Confidence is the confidence level provided by the vendor for the threat type category. For example, a confidence level of 90 for the ‘malware’ threat type category means that the vendor is confident that its 90% malware. | String |
| DomainEnrichment.Value | The Domain. | string |
| DomainEnrichment.MaxScore | The max score of all the indicators found. | number |
| DomainEnrichment.MaxVerdict | The max verdict of all the indicators found. | string |
| DomainEnrichment.Results | List of all indicators found for the domain. | array |
| DomainEnrichment.TIMScore | The TIM score of the domain. | number |
| DomainEnrichment.Status | The status of the indicator: “Manual” if the score was changed manually, “Fresh” if modified within the last week, “Stale” if modified more than a week ago, and “None” if never modified. | string |
| DomainEnrichment.ModifiedTime | The time the indicator was last modified. | Date |
| DomainEnrichment.Results.Brand | The brand of the indicator. | string |
| DomainEnrichment.Results.Score | The score of the indicator. | number |
| DomainEnrichment.Results.Verdict | The verdict of the indicator. | string |
| DomainEnrichment.Results.DetectionEngines | The detection engines of the indicator. | number |
| DomainEnrichment.Results.PositiveDetections | The positive detections of the indicator. | number |
| DomainEnrichment.Results.Name | The Domain. | string |
| DomainEnrichment.Results.Reliability | The reliability of the Brand. | string |
| DomainEnrichment.Results.AdditionalFields | All fields extracted from the indicator other then the main keys (“Brand”, “Score”, “Verdict”, “DetectionEngines”, “PositiveDetections”, “Name”). | Object |
| DomainEnrichment.Results.AdditionalFields.Relationships.EntityA | The source of the relationship. | string |
| DomainEnrichment.Results.AdditionalFields.Relationships.EntityB | The destination of the relationship. | string |
| DomainEnrichment.Results.AdditionalFields.Relationships.Relationship | The name of the relationship. | string |
| DomainEnrichment.Results.AdditionalFields.Relationships.EntityAType | The type of the source of the relationship. | string |
| DomainEnrichment.Results.AdditionalFields.Relationships.EntityBType | The type of the destination of the relationship. | string |
| DomainEnrichment.Results.AdditionalFields.DNS | A list of IP objects resolved by DNS. | String |
| DomainEnrichment.Results.AdditionalFields.CreationDate | The date when the domain was created. | Date |
| DomainEnrichment.Results.AdditionalFields.UpdatedDate | The date when the domain was last updated. | String |
| DomainEnrichment.Results.AdditionalFields.ExpirationDate | The expiration date of the domain. | Date |
| DomainEnrichment.Results.AdditionalFields.DomainStatus | The status of the domain. | Date |
| DomainEnrichment.Results.AdditionalFields.NameServers | (List<String>) Name servers of the domain. | Unknown |
| DomainEnrichment.Results.AdditionalFields.Organization | The organization of the domain. | String |
| DomainEnrichment.Results.AdditionalFields.Subdomains | (List<String>) Subdomains of the domain. | Unknown |
| DomainEnrichment.Results.AdditionalFields.Admin.Country | The country of the domain administrator. | String |
| DomainEnrichment.Results.AdditionalFields.Admin.Email | The email address of the domain administrator. | String |
| DomainEnrichment.Results.AdditionalFields.Admin.Name | The name of the domain administrator. | String |
| DomainEnrichment.Results.AdditionalFields.Admin.Phone | The phone number of the domain administrator. | String |
| DomainEnrichment.Results.AdditionalFields.Registrant.Country | The country of the registrant. | String |
| DomainEnrichment.Results.AdditionalFields.Registrant.Email | The email address of the registrant. | String |
| DomainEnrichment.Results.AdditionalFields.Registrant.Name | The name of the registrant. | String |
| DomainEnrichment.Results.AdditionalFields.Registrant.Phone | The phone number to receive abuse reports. | String |
| DomainEnrichment.Results.AdditionalFields.Tags | (List) Tags of the domain. | Unknown |
| DomainEnrichment.Results.AdditionalFields.FeedRelatedIndicators.value | Indicators that are associated with the domain. | String |
| DomainEnrichment.Results.AdditionalFields.FeedRelatedIndicators.type | The type of the indicators that are associated with the domain. | String |
| DomainEnrichment.Results.AdditionalFields.FeedRelatedIndicators.description | The description of the indicators that are associated with the domain. | String |
| DomainEnrichment.Results.AdditionalFields.MalwareFamily | The malware family associated with the domain. | String |
| DomainEnrichment.Results.AdditionalFields.WHOIS.DomainStatus | The status of the domain. | String |
| DomainEnrichment.Results.AdditionalFields.WHOIS.NameServers | (List<String>) Name servers of the domain. | String |
| DomainEnrichment.Results.AdditionalFields.WHOIS.CreationDate | The date that the domain was created. | Date |
| DomainEnrichment.Results.AdditionalFields.WHOIS.UpdatedDate | The date that the domain was last updated. | Date |
| DomainEnrichment.Results.AdditionalFields.WHOIS.ExpirationDate | The expiration date of the domain. | Date |
| DomainEnrichment.Results.AdditionalFields.WHOIS.Registrant.Name | The name of the registrant. | String |
| DomainEnrichment.Results.AdditionalFields.WHOIS.Registrant.Email | The email address of the registrant. | String |
| DomainEnrichment.Results.AdditionalFields.WHOIS.Registrant.Phone | The phone number of the registrant. | String |
| DomainEnrichment.Results.AdditionalFields.WHOIS.Registrar.Name | The name of the registrar, for example, GoDaddy. | String |
| DomainEnrichment.Results.AdditionalFields.WHOIS.Registrar.AbuseEmail | The email address of the contact to report abuse. | String |
| DomainEnrichment.Results.AdditionalFields.WHOIS.Registrar.AbusePhone | The phone number of the contact to report abuse. | String |
| DomainEnrichment.Results.AdditionalFields.WHOIS.Admin.Name | The name of the domain administrator. | String |
| DomainEnrichment.Results.AdditionalFields.WHOIS.Admin.Email | The email address of the domain administrator. | String |
| DomainEnrichment.Results.AdditionalFields.WHOIS.Admin.Phone | The phone number of the domain administrator. | String |
| DomainEnrichment.Results.AdditionalFields.WHOIS.History | List of Whois objects. | String |
| DomainEnrichment.Results.AdditionalFields.Malicious.Vendor | The vendor reporting the domain as malicious. | String |
| DomainEnrichment.Results.AdditionalFields.Malicious.Description | Reason the domain was reported as malicious. | String |
| DomainEnrichment.Results.AdditionalFields.DomainIDNName | The internationalized domain name (IDN) of the domain. | String |
| DomainEnrichment.Results.AdditionalFields.Port | Ports associated with the domain. | String |
| DomainEnrichment.Results.AdditionalFields.Internal | Whether the domain is internal or external. | Bool |
| DomainEnrichment.Results.AdditionalFields.Category | The category associated with the indicator. | String |
| DomainEnrichment.Results.AdditionalFields.Campaign | The campaign associated with the domain. | String |
| DomainEnrichment.Results.AdditionalFields.TrafficLightProtocol | The Traffic Light Protocol (TLP) color that is suitable for the domain. | String |
| DomainEnrichment.Results.AdditionalFields.ThreatTypes.threatcategory | The threat category associated to this indicator by the source vendor, for example, Phishing, Control, TOR, etc. | String |
| DomainEnrichment.Results.AdditionalFields.ThreatTypes.threatcategoryconfidence | Threat Category Confidence is the confidence level provided by the vendor for the threat type category. For example, a confidence of 90 for the threat type category ‘malware’ means the vendor estimates a 90% likelihood that it is malware. | String |
| DomainEnrichment.Results.AdditionalFields.Geo.Location | The geolocation where the domain address is located, in the format: latitude:longitude. | String |
| DomainEnrichment.Results.AdditionalFields.Geo.Country | The country in which the domain address is located. | String |
| DomainEnrichment.Results.AdditionalFields.Geo.Description | Additional information about the location. | String |
| DomainEnrichment.Results.AdditionalFields.Tech.Country | The country of the domain technical contact. | String |
| DomainEnrichment.Results.AdditionalFields.Tech.Name | The name of the domain technical contact. | String |
| DomainEnrichment.Results.AdditionalFields.Tech.Organization | The organization of the domain technical contact. | String |
| DomainEnrichment.Results.AdditionalFields.Tech.Email | The email address of the domain technical contact. | String |
| DomainEnrichment.Results.AdditionalFields.CommunityNotes.note | Notes on the domain that were given by the community. | String |
| DomainEnrichment.Results.AdditionalFields.CommunityNotes.timestamp | Time the note was published. | Date |
| DomainEnrichment.Results.AdditionalFields.Publications.source | The source where the article was published. | String |
| DomainEnrichment.Results.AdditionalFields.Publications.title | The name of the article. | String |
| DomainEnrichment.Results.AdditionalFields.Publications.link | A link to the original article. | String |
| DomainEnrichment.Results.AdditionalFields.Publications.timestamp | Time the article was published. | Date |
| DomainEnrichment.Results.AdditionalFields.Billing | Billing address of the domain. | String |
| URLEnrichment.Value | The URL. | string |
| URLEnrichment.MaxScore | The max score of all the indicators found. | number |
| URLEnrichment.MaxVerdict | The max verdict of all the indicators found. | string |
| URLEnrichment.Results | List of all indicators found for the URL. | array |
| URLEnrichment.TIMScore | The TIM score of the URL. | number |
| URLEnrichment.Status | The status of the indicator: “Manual” if the score was changed manually, “Fresh” if modified within the last week, “Stale” if modified more than a week ago, and “None” if never modified. | string |
| URLEnrichment.ModifiedTime | The time the indicator was last modified. | Date |
| URLEnrichment.Results.Brand | The brand of the indicator. | string |
| URLEnrichment.Results.Score | The score of the indicator. | number |
| URLEnrichment.Results.Verdict | The verdict of the indicator. | string |
| URLEnrichment.Results.DetectionEngines | The detection engines of the indicator. | number |
| URLEnrichment.Results.PositiveDetections | The positive detections of the indicator. | number |
| URLEnrichment.Results.Data | The URL it self. | string |
| URLEnrichment.Results.Reliability | The reliability of the Brand. | string |
| URLEnrichment.Results.AdditionalFields | All fields extracted from the indicator other then the main keys (“Brand”, “Score”, “Verdict”, “DetectionEngines”, “PositiveDetections”, “Data”). | Object |
| URLEnrichment.Results.AdditionalFields.Relationships.EntityA | The source of the relationship. | string |
| URLEnrichment.Results.AdditionalFields.Relationships.EntityB | The destination of the relationship. | string |
| URLEnrichment.Results.AdditionalFields.Relationships.Relationship | The name of the relationship. | string |
| URLEnrichment.Results.AdditionalFields.Relationships.EntityAType | The type of the source of the relationship. | string |
| URLEnrichment.Results.AdditionalFields.Relationships.EntityBType | The type of the destination of the relationship. | string |
| URLEnrichment.Results.AdditionalFields.Category | The category associated with the indicator. | String |
| URLEnrichment.Results.AdditionalFields.Malicious.Vendor | The vendor reporting the URL as malicious. | String |
| URLEnrichment.Results.AdditionalFields.Malicious.Description | A description of the malicious URL. | String |
| URLEnrichment.Results.AdditionalFields.Tags | (List) Tags of the URL. | Unknown |
| URLEnrichment.Results.AdditionalFields.FeedRelatedIndicators.value | Indicators that are associated with the URL. | String |
| URLEnrichment.Results.AdditionalFields.FeedRelatedIndicators.type | The type of the indicators that are associated with the URL. | String |
| URLEnrichment.Results.AdditionalFields.FeedRelatedIndicators.description | The description of the indicators that are associated with the URL. | String |
| URLEnrichment.Results.AdditionalFields.MalwareFamily | The malware family associated with the URL. | String |
| URLEnrichment.Results.AdditionalFields.Port | Ports that are associated with the URL. | String |
| URLEnrichment.Results.AdditionalFields.Internal | Whether or not the URL is internal or external. | Bool |
| URLEnrichment.Results.AdditionalFields.Campaign | The campaign associated with the URL. | String |
| URLEnrichment.Results.AdditionalFields.TrafficLightProtocol | The Traffic Light Protocol (TLP) color that is suitable for the URL. | String |
| URLEnrichment.Results.AdditionalFields.ThreatTypes.threatcategory | The threat category associated to this indicator by the source vendor. For example, Phishing, Control, TOR, etc. | String |
| URLEnrichment.Results.AdditionalFields.ThreatTypes.threatcategoryconfidence | Threat Category Confidence is the confidence level provided by the vendor for the threat type category For example a confidence of 90 for threat type category ‘malware’ means that the vendor rates that this is 90% confidence of being a malware. | String |
| URLEnrichment.Results.AdditionalFields.ASN | The autonomous system name for the URL, for example: ‘AS8948’. | String |
| URLEnrichment.Results.AdditionalFields.ASOwner | The autonomous system owner of the URL. | String |
| URLEnrichment.Results.AdditionalFields.GeoCountry | The country in which the URL is located. | String |
| URLEnrichment.Results.AdditionalFields.Organization | The organization of the URL. | String |
| URLEnrichment.Results.AdditionalFields.CommunityNotes.note | Notes on the URL that were given by the community. | String |
| URLEnrichment.Results.AdditionalFields.CommunityNotes.timestamp | The time in which the note was published. | Date |
| URLEnrichment.Results.AdditionalFields.Publications.source | The source in which the article was published. | String |
| URLEnrichment.Results.AdditionalFields.Publications.title | The name of the article. | String |
| URLEnrichment.Results.AdditionalFields.Publications.link | A link to the original article. | String |
| URLEnrichment.Results.AdditionalFields.Publications.timestamp | The time in which the article was published. | Date |
| CVEEnrichment.Value | The CVE. | string |
| CVEEnrichment.TIMCVSS | The max CVSS of the indicator. | number |
| CVEEnrichment.Results | List of all indicators found for the CVE. | array |
| CVEEnrichment.Status | The status of the indicator. | string |
| CVEEnrichment.Results.Brand | The brand of the indicator. | string |
| CVEEnrichment.Results.CVSS | The CVSS of the indicator. | number |
| CVEEnrichment.Results.Description | The description of the indicator. | string |
| CVEEnrichment.Results.Published | The published date of the indicator. | string |
| CVEEnrichment.Results.Status | The status of the indicator: “Manual” if the score was changed manually, “Fresh” if modified within the last week, “Stale” if modified more than a week ago, and “None” if never modified. | string |
| CVEEnrichment.Results.ModifiedTime | The time the indicator was last modified. | Date |
| CVEEnrichment.Results.AdditionalFields | All fields extracted from the indicator other then the main keys (“ID”, “Brand”, “CVSS”, “Description”, “Published”, “CVSS”). | Object |
| CVEEnrichment.Results.AdditionalFields.Relationships.EntityA | The source of the relationship. | string |
| CVEEnrichment.Results.AdditionalFields.Relationships.EntityB | The destination of the relationship. | string |
| CVEEnrichment.Results.AdditionalFields.Relationships.Relationship | The name of the relationship. | string |
| CVEEnrichment.Results.AdditionalFields.Relationships.EntityAType | The type of the source of the relationship. | string |
| CVEEnrichment.Results.AdditionalFields.Relationships.EntityBType | The type of the destination of the relationship. | string |
| CVEEnrichment.Results.AdditionalFields.Modified | The timestamp of when the CVE was last modified. | Date |
import demistomock as demisto from CommonServerPython import * from AggregatedCommandApiModule import * from enum import Enum from typing import NamedTuple, Any, Optional from collections import defaultdict import traceback MAX_INDICATORS = 100 MSG_NO_VALID_INDICATORS = ( "No valid indicators provided. You must provide at least one valid indicator " "in arguments: indicator_list or text." ) ERR_LIMIT_TEMPLATE = ( "Error: Indicator limit exceeded. Found {found} indicators, but the limit is {limit}. " "To process all indicators, set the ignore_indicator_limit argument to true. " "Note: This should be avoided if possible." ) MSG_FATAL_EXECUTION_ERROR = "Fatal error while executing enrichment. View the logs or try again.\n{error}" class ValidationError(Exception): """ Raised when business logic constraints are violated. This exception should result in a return_error action. """ class AllExecutionsFailedError(Exception): """ Raised when none of the executions of the underlying enrichment scripts have succeeded. """ class GracefulExit(Exception): """ Raised when the script should stop execution and return a status message. This exception should result in a return_results action (success status), not an error. """ class IndicatorType(Enum): """ Configuration registry for supported indicator types. Acts as the single source of truth for command mapping, argument keys, and context prefixes. """ IP = ("ip_list", "IP", "ip-enrichment", "IPEnrichment", ["ip", "ipv4"]) URL = ("url_list", "URL", "url-enrichment", "URLEnrichment", ["url"]) DOMAIN = ("domain_list", "Domain", "domain-enrichment", "DomainEnrichment", ["domain"]) CVE = ("cve_list", "CVE", "cve-enrichment", "CVEEnrichment", ["cve"]) FILE = ("file_hash", "File", "file-enrichment", "FileEnrichment", ["file"]) def __init__(self, argument_key: str, display_name: str, command_name: str, context_prefix: str, aliases: list[str]): """ Initializes the IndicatorType configuration. Args: argument_key: The argument name expected by the child command (e.g., 'ip_list'). display_name: The human-readable name for headers (e.g., 'IP'). command_name: The XSOAR command to execute (e.g., 'ip-enrichment'). context_prefix: The prefix used in EntryContext (e.g., 'IPEnrichment'). aliases: A list of string representations used for type detection. """ self.argument_key = argument_key self.display_name = display_name self.command_name = command_name self.context_prefix = context_prefix self.aliases = aliases @classmethod def resolve_from_string(cls, value: str) -> Optional["IndicatorType"]: """ Maps a raw string type (e.g., 'IPv4', 'sha256') to the corresponding IndicatorType Enum. Args: value: The raw type string to resolve. Returns: The matching IndicatorType member, or None if the type is not supported. """ if not value: return None normalized_value = value.lower() for member in cls: if normalized_value in member.aliases: return member return None class UnsupportedIndicator(NamedTuple): """ Represents an indicator that was detected but is not supported by the configured Enrichment commands. """ type: str value: str class EnrichmentTask(NamedTuple): """ Represents a unit of work: a specific XSOAR command configured for a specific indicator type. """ indicator_type: IndicatorType command: Command class EnrichmentRequest: """ Immutable Data Transfer Object (DTO) representing the sanitized, deduplicated, and validated input data ready for processing. """ def __init__( self, valid_indicators_by_type: defaultdict[IndicatorType, list[str]], unsupported_items: list[UnsupportedIndicator], unknown_items: list[str], duplicates_removed_count: int, sub_command_arguments: dict[str, Any], include_raw_context: bool, ): """ Initializes the EnrichmentRequest. Args: valid_indicators_by_type: A mapping of IndicatorType to a list of valid indicator values. unsupported_items: A list of items that have a type but are not supported by this script. unknown_items: A list of items where type detection failed. duplicates_removed_count: The count of duplicate items filtered out during building. sub_command_arguments: Arguments to be passed down to child commands (e.g., brands). include_raw_context: Whether to include the raw enrichment keys in the final output. """ self.valid_indicators_by_type = valid_indicators_by_type self.unsupported_items = unsupported_items self.unknown_items = unknown_items self.duplicates_removed_count = duplicates_removed_count self.sub_command_arguments = sub_command_arguments self.include_raw_context = include_raw_context @property def total_valid_count(self) -> int: """Returns the total number of valid indicators across all types.""" return sum(len(indicators) for indicators in self.valid_indicators_by_type.values()) class EnrichmentResult: """ Accumulator for the results of the enrichment execution phase. """ def __init__(self): self.enriched_data: list[ContextResult] = [] self.raw_context: ContextResult = {} self.markdown_sections: list[str] = [] self.execution_errors: List[str] = [] class EnrichmentRequestBuilder: """ Responsible for parsing raw XSOAR arguments, extracting indicators from text and lists, deduplicating inputs, and enforcing business validation rules. """ def __init__(self, raw_arguments: dict[str, Any]): """ Args: raw_arguments: The dictionary of arguments provided to the command (demisto.args()). """ self.raw_arguments = raw_arguments # this is for the deduplication tracking self._seen_indicators: set[str] = set() self.valid_indicators_by_type: defaultdict[IndicatorType, list[str]] = defaultdict(list) self.unsupported_items: list[UnsupportedIndicator] = [] self.unknown_items: list[str] = [] self.duplicates_count: int = 0 def build_and_validate(self) -> EnrichmentRequest: """ Orchestrates the creation of an EnrichmentRequest. Returns: A fully populated and validated EnrichmentRequest. Raises: ValidationError: If inputs are invalid or limits are exceeded. GracefulExit: If valid inputs are provided but result in no actionable work. """ self._extract_indicators_from_text_argument() self._extract_indicators_from_list_argument() self._enforce_enrichment_arg_rules() return EnrichmentRequest( valid_indicators_by_type=self.valid_indicators_by_type, unsupported_items=self.unsupported_items, unknown_items=self.unknown_items, duplicates_removed_count=self.duplicates_count, sub_command_arguments=self._filter_passthrough_arguments(), include_raw_context=argToBoolean(self.raw_arguments.get("raw_context", False)), ) def _classify_and_store(self, raw_type: str, value: str) -> None: """ Normalizes, deduplicates, and classifies a single indicator value. Populates the internal state buckets (valid, unknown, unsupported). Args: raw_type: The string type representation (e.g., 'IP', 'Unknown'). value: The indicator value string. """ if not value: return clean_value = str(value).strip() if not clean_value: return if clean_value in self._seen_indicators: self.duplicates_count += 1 return self._seen_indicators.add(clean_value) indicator_type = IndicatorType.resolve_from_string(raw_type) if indicator_type: self.valid_indicators_by_type[indicator_type].append(clean_value) elif not raw_type or raw_type.lower() == "unknown": self.unknown_items.append(clean_value) else: self.unsupported_items.append(UnsupportedIndicator(raw_type, clean_value)) def _extract_indicators_from_text_argument(self) -> None: """ Extracts indicators from the 'text' argument using the 'extractIndicators' command. Example of Response of the extractIndicators command: { "IP": ["1.1.1.1"], "Domain": ["google.com"] } """ text_argument = self.raw_arguments.get("text", "") if not text_argument: return res = execute_command("extractIndicators", {"text": text_argument}, extract_contents=False) if not res or not isinstance(res, list): return entry_context = res[0].get("EntryContext", {}) or {} extracted_indicators = entry_context.get("ExtractedIndicators", {}) or {} for type_str, values in extracted_indicators.items(): items = values if isinstance(values, list) else [values] for val in items: self._classify_and_store(type_str, val) def _extract_indicators_from_list_argument(self) -> None: """ Parses the 'indicator_list' argument and attempts to auto-detect the type of each item. """ raw_list = argToList(self.raw_arguments.get("indicator_list")) for item in raw_list: detected_type = auto_detect_indicator_type(item) # type: ignore self._classify_and_store(detected_type or "Unknown", item) def _enforce_enrichment_arg_rules(self) -> None: """ Validates the state of collected indicators against business rules. Raises: ValidationError: If: - indicator_list and text are not given - indicator_list given with no valid indicators - Over 100 indicators given (after clearing invalid and duplicates) GracefulExit: If text input yields no valid indicators (non-error state). """ total_valid = sum(len(v) for v in self.valid_indicators_by_type.values()) has_invalid = bool(self.unsupported_items or self.unknown_items) text_provided = bool(self.raw_arguments.get("text", "").strip()) list_key_present = "indicator_list" in self.raw_arguments list_has_values = bool(argToList(self.raw_arguments.get("indicator_list"))) if not text_provided and not list_has_values and not list_key_present: raise ValidationError(MSG_NO_VALID_INDICATORS) if list_key_present and (not list_has_values or total_valid == 0): raise ValidationError(MSG_NO_VALID_INDICATORS) if text_provided and not list_key_present and total_valid == 0 and not has_invalid: raise GracefulExit(MSG_NO_VALID_INDICATORS) ignore_limit = argToBoolean(self.raw_arguments.get("ignore_indicator_limit", False)) if not ignore_limit and total_valid > MAX_INDICATORS: raise ValidationError(ERR_LIMIT_TEMPLATE.format(found=total_valid, limit=MAX_INDICATORS)) def _filter_passthrough_arguments(self) -> dict[str, Any]: """ Filters the raw arguments to include only those intended for child commands. Returns: A dictionary of arguments to pass to the enrichment commands. """ keys = ["external_enrichment", "brands", "additional_fields"] return {k: self.raw_arguments.get(k) for k in keys if self.raw_arguments.get(k) is not None} class EnrichmentService: """ Coordinates the execution of child enrichment commands based on the request. """ def __init__(self, request: EnrichmentRequest): self._result = EnrichmentResult() self._request = request def execute(self) -> EnrichmentResult: """ Executes the enrichment plan. Args: request: The EnrichmentRequest containing grouped indicators. Returns: An EnrichmentResult object containing aggregated outputs. """ if not self._request.valid_indicators_by_type: return self._result tasks = self._create_enrichment_tasks() batch_output = BatchExecutor().execute_batch([t.command for t in tasks], brands_to_run=None, verbose=False) for task, output in zip(tasks, batch_output): self._parse_task_output(task, output) return self._result def _create_enrichment_tasks(self) -> list[EnrichmentTask]: """Creates a list of tasks mapping indicator types to configured Commands.""" tasks = [] for type_enum, indicators in self._request.valid_indicators_by_type.items(): cmd = self._build_command(type_enum, indicators) tasks.append(EnrichmentTask(type_enum, cmd)) return tasks def _build_command(self, type_enum: IndicatorType, indicators: list[str]) -> Command: """ Constructs a single XSOAR Command pointing to the corresponding underlying script based on the type given.. Args: type_enum: IndicatorType IP, Domain, etc.. indicators: List of indicators to pass to this command extra_args: any other args to pass to this command (i.e. additional_fields) Returns: Command: A command object which can later be executed. """ cmd_args = {type_enum.argument_key: indicators} cmd_args.update(self._request.sub_command_arguments) return Command( name=type_enum.command_name, args=cmd_args, command_type=CommandType.INTERNAL, ignore_using_brand=True, is_multi_input=True, is_aggregated_output=True, ) def _parse_task_output(self, task: EnrichmentTask, task_output: CommandProcessResults) -> None: """ Parses the output of a BatchExecutor task and updates the result object. Handles Error extraction, HumanReadable aggregation, and Context extraction. """ human_readable_strings = [] for entry, hr, err in task_output: if err: self._result.execution_errors.append(err) self._result.markdown_sections.append(f"### Error from {task.command.name}\n{err}") continue valid_hr = hr if not valid_hr and isinstance(entry, dict): valid_hr = entry.get("HumanReadable", "") if valid_hr: human_readable_strings.append(valid_hr) entry_context = entry.get("EntryContext") or entry.get("Contents") or {} if isinstance(entry_context, dict): self._result.raw_context.update(entry_context) self._add_new_keys_to_enrichment_data(task.indicator_type, entry_context) if human_readable_strings: combined_md = "\n".join(human_readable_strings) header = f"### {task.command.name}" self._result.markdown_sections.append(f"{header}\n{combined_md}") def _add_new_keys_to_enrichment_data(self, indicator_type: IndicatorType, context: ContextResult) -> None: """ Extracts specific enrichment data based on the indicator type prefix and add "Type" key to it. Args: indicator_type: The configuration enum for the current indicator type. context: The raw EntryContext dictionary from the sub-command. """ for key, value in context.items(): if key.startswith(indicator_type.context_prefix): items = value if isinstance(value, list) else [value] for item in items: if isinstance(item, dict): unified_entry = item.copy() unified_entry["Type"] = indicator_type.display_name self._result.enriched_data.append(unified_entry) class ResponseFormatter: """ Transforms the internal EnrichmentResult into the final XSOAR CommandResults object. """ def format(self, result: EnrichmentResult, request: EnrichmentRequest) -> CommandResults: """ Formats the result into Markdown and Context. Args: result: The results from the service execution. request: The original request (used for error collection and raw_context flags). Returns: A populated CommandResults object. """ # Fatal Error Check: If we tried to enrich but got 0 results and >0 errors if not result.enriched_data and result.execution_errors: combined_errors = "\n".join(result.execution_errors) raise AllExecutionsFailedError(MSG_FATAL_EXECUTION_ERROR.format(error=combined_errors)) markdown = self._format_markdown(result, request) context = self._format_context(result, request) return CommandResults(readable_output=markdown, outputs=context, raw_response=flatten_context_values(context)) def _format_markdown(self, result: EnrichmentResult, request: EnrichmentRequest) -> str: """Generates the final Markdown string, including notes, results, and error tables.""" sections = [] if request.duplicates_removed_count > 0: sections.append( f"Note: Removed {request.duplicates_removed_count} duplicate indicator occurrences before enrichment." ) sections.extend(result.markdown_sections) error_table = self._generate_error_table(request) if error_table: sections.append(error_table) return "\n\n".join(sections) if sections else "No enrichment results found." def _remove_enrichment_keys_from_ctx(self, raw_context: ContextResult) -> ContextResult: filtered_context = {} enrichment_prefixes = tuple(indicator_type.context_prefix for indicator_type in IndicatorType) for k, v in raw_context.items(): if not k.startswith(enrichment_prefixes): filtered_context[k] = v return filtered_context def _format_context(self, result: EnrichmentResult, request: EnrichmentRequest) -> ContextResult: """Generates the final Context dictionary, handling raw context filtering and unified list generation.""" final_context = {} if not request.include_raw_context: filtered_context = self._remove_enrichment_keys_from_ctx(result.raw_context) final_context.update(filtered_context) else: final_context.update(result.raw_context) # Construct the enriched data for IndicatorEnrichment key final_context_output = result.enriched_data[:] final_context_output.extend(self._collect_error_objects(request)) if final_context_output: final_context["IndicatorEnrichment"] = final_context_output return final_context def _generate_error_table(self, request: EnrichmentRequest) -> str: rows = self._collect_error_rows(request) if not rows: return "" return tableToMarkdown("Invalid or unsupported indicators", rows, headers=["Type", "Value", "Status", "Message"]) def _collect_error_rows(self, request: EnrichmentRequest) -> list[ContextResult]: rows = [] for item in request.unsupported_items: rows.append( {"Type": item.type, "Value": item.value, "Status": "Error", "Message": "No script supports this indicator type."} ) for value in request.unknown_items: rows.append({"Type": "Unknown", "Value": value, "Status": "Error", "Message": "Not a valid indicator."}) rows.sort(key=lambda x: (x["Type"].lower(), x["Value"].lower())) return rows def _collect_error_objects(self, request: EnrichmentRequest) -> list[ContextResult]: return self._collect_error_rows(request) # type: ignore def main(): """ Entry point for the indicator enrichment command. Orchestrates building the request, executing the service, and formatting the response. """ try: enrichment_request_builder = EnrichmentRequestBuilder(demisto.args()) validated_request = enrichment_request_builder.build_and_validate() indicator_enrichment_executor = EnrichmentService(validated_request) result = indicator_enrichment_executor.execute() command_results = ResponseFormatter().format(result, validated_request) return_results(command_results) except GracefulExit as info_message: return_results(CommandResults(readable_output=str(info_message), outputs={})) except ValidationError as error_message: demisto.debug(f"Validation Error: {error_message}") return_error(str(error_message)) except AllExecutionsFailedError as error_message: demisto.debug(f"Failed to execute !indicator-enrichment. Error: {error_message}\n{str(traceback.format_exc())}") return_error(str(error_message)) except Exception as system_error: demisto.error(f"Failed to execute !indicator-enrichment. Error: {str(traceback.format_exc())}") return_error(f"Failed to execute !indicator-enrichment. Error: {str(system_error)}") if __name__ in ("__main__", "__builtin__", "builtins"): main()