GoogleThreatIntelligence

Analyzes suspicious hashes, URLs, domains, and IP addresses.

Data Enrichment & Threat Intelligence · GoogleThreatIntelligence

Details

IDGoogleThreatIntelligence
ProviderGoogle
CategoryData Enrichment & Threat Intelligence
From Version6.10.0
Docker Imagedemisto/python3:3.12.13.10116658
Supported ModulesAgentix XSIAM

README

Google Threat Intelligence

This integration analyzes suspicious hashes, URLs, domains, and IP addresses.

Configure Google Threat Intelligence in Cortex

Parameter Description Required
API Key See Acquiring your API key True
Use system proxy settings   False
Trust any certificate (not secure)   False
Source Reliability Reliability of the source providing the intelligence data  
GTI Malicious Verdict. Check Google Threat Intelligence verdict to consider the file malicious.   False
GTI Suspicious Verdict. Check Google Threat Intelligence verdict to consider the file suspicious.   False
File Malicious Threshold. Minimum number of positive results from GoogleThreatIntelligence scanners to consider the file malicious. See Indicator Thresholds. False
File Suspicious Threshold. Minimum number of positive and suspicious results from GoogleThreatIntelligence scanners to consider the file suspicious. See Indicator Thresholds. False
IP Malicious Threshold. Minimum number of positive results from GoogleThreatIntelligence scanners to consider the IP malicious. See Indicator Thresholds. False
IP Suspicious Threshold. Minimum number of positive and suspicious results from GoogleThreatIntelligence scanners to consider the IP suspicious. See Indicator Thresholds. False
Disable reputation lookups for private IP addresses To reduce the number of lookups made to the GoogleThreatIntelligence API, this option can be selected to gracefully skip enrichment of any IP addresses allocated for private networks. False
URL Malicious Threshold. Minimum number of positive results from GoogleThreatIntelligence scanners to consider the URL malicious. See Indicator Thresholds. False
URL Suspicious Threshold. Minimum number of positive and suspicious results from GoogleThreatIntelligence scanners to consider the URL suspicious. See Indicator Thresholds. False
Domain Malicious Threshold. Minimum number of positive results from GoogleThreatIntelligence scanners to consider the domain malicious. See Indicator Thresholds. False
Domain Suspicious Threshold. Minimum number of positive and suspicious results from GoogleThreatIntelligence scanners to consider the domain suspicious. See Indicator Thresholds. False
Preferred Vendors List. CSV list of vendors who are considered more trustworthy. See Indicator Thresholds. False
Preferred Vendor Threshold. The minimum number of highly trusted vendors required to consider a domain, IP address, URL, or file as malicious. See Indicator Thresholds. False
Enable score analyzing by Crowdsourced Yara Rules, Sigma, and IDS See Rules Threshold. False
Crowdsourced Yara Rules Threshold See Rules Threshold. False
Sigma and Intrusion Detection Rules Threshold See Rules Threshold. False
Domain Popularity Ranking Threshold See Rules Threshold. False

Acquiring your API key

Your API key can be found in your GoogleThreatIntelligence account user menu, clicking on your avatar:
How to get api key in GoogleThreatIntelligence
Your API key carries all your privileges, so keep it secure and don’t share it with anyone.

DBot Score / Reputation scores

The following information describes DBot Score which is new for this version.

Indicator Thresholds

Configure the default threshold for each indicator type in the instance settings.
You can also specify the threshold as an argument when running relevant commands.

  • Indicators with positive results from preferred vendors equal to or higher than the threshold will be considered malicious.
  • Indicators with positive results equal to or higher than the malicious threshold will be considered malicious.
  • Indicators with positive results equal to or higher than the suspicious threshold value will be considered suspicious.
  • Domain popularity ranks: GoogleThreatIntelligence is returning a popularity ranks for each vendor. The integration will calculate its average and will compare it to the threshold.

Rules Threshold

If the YARA rules analysis threshold is enabled:

  • Indicators with positive results, the number of found YARA rules results, Sigma analysis, or IDS equal to or higher than the threshold, will be considered suspicious.
  • If both the the basic analysis and the rules analysis is suspicious, the indicator will be considered as malicious.
    If the indicator was found to be suspicious only by the rules thresholds, the indicator will be considered suspicious.
  • Domain popularity ranks: GoogleThreatIntelligence is returning a popularity ranks for each vendor. The integration will calculate its average and will compare it to the threshold.

The DbotScore calculation process can be seen on the “description” field in any malicious/suspicious DBot score.
You can aquire those calculation on all of the indicators also from the debug log.

Example of a GoogleThreatIntelligence DBot score log:

Basic analyzing of "<domain>"
Found popularity ranks. Analyzing.
The average of the ranks is 809009.0 and the threshold is 10000
Indicator is good by popularity ranks.
Analyzing by get_domain_communicating_files
Found safe by relationship files. total_malicious=0 >= 3
Analyzing by get_url_downloaded_files
Found safe by relationship files. total_malicious=0 >= 3
Analyzing by get_url_referrer_files
Found safe by relationship files. total_malicious=0 >= 3

Reputation commands (ip, url, domain, and file)

  • Removed output paths: Due to changes in GoogleThreatIntelligence, the following output paths are no longer supported:
    • IP.GoogleThreatIntelligence
    • Domain.GoogleThreatIntelligence
    • URL.GoogleThreatIntelligence
    • File.GoogleThreatIntelligence

    Instead, you can use the following output paths that return concrete indicator reputations.

    • GoogleThreatIntelligence.IP
    • GoogleThreatIntelligence.Domain
    • GoogleThreatIntelligence.File
    • GoogleThreatIntelligence.URL
  • The following commands will no longer analyze the file/url sent to it, but will get the information stored in GoogleThreatIntelligence.
    • GoogleThreatIntelligence.Domain
    • GoogleThreatIntelligence.IP

    To analyze (detonate) the indicator, you can use the following playbooks:

    • Detonate File - GoogleThreatIntelligence
    • Detonate URL - GoogleThreatIntelligence
  • Each reputation command will use at least 1 API call. For advanced reputation commands, use the Premium API flag.
  • For each reputation command there is the new extended_data argument . When set to “true”, the results returned by the commands will contain
    additional information as last_analysis_results which contains the service name and its specific analysis.
  • Reputation commands can return relationships of the indicator.
    The relationships that are supported are defined as part of the instance configuration.
    For more information regarding URL relationships, see: https://gtidocs.virustotal.com/reference/url-info
    For more information regarding IP relationships, see: https://gtidocs.virustotal.com/reference/ip-info
    For more information regarding Domain relationships, see: https://gtidocs.virustotal.com/reference/domain-info
    For more information regarding File relationships, see: https://gtidocs.virustotal.com/reference/file-info

  • Starting with XSOAR version 6.9.0, You may monitor API usage via the GoogleThreatIntelligence Execution Metrics dashboard.

Comments

In GoogleThreatIntelligence you can now add comments to all indicator types (IP, Domain, File and URL) so each command now has the resource_type argument.
If supplied, the command will use the resource type to add a comment. If not, the command will determine if the given input is a hash or a URL.
This arguments is available in the following commands:

  • gti-comments-get
  • gti-comments-add

gti-comments-get

  • Added the resource_type argument. If not supplied, will try to determine if the resource argument is a hash or a URL.
  • Added the limit argument. Gets the latest comments within the given limit.
  • New output path: GoogleThreatIntelligence.Comments.

Detonation (scan) Commands

Removed the gtiLink output from all commands as it does no longer return from the API.
To easily use the scan commands we suggest using the following playbooks:

  • Detonate File - GoogleThreatIntelligence
  • Detonate URL - GoogleThreatIntelligence

Use the gti-analysis-get command to get the report from the scans.

file


Checks the file reputation of the specified hash.

Base Command

file

Input

Argument Name Description Required
file Hash of the file to query. Supports MD5, SHA1, and SHA256. Required
extended_data Whether to return extended data (last_analysis_results). Possible values are: true, false. Optional

Context Output

Path Type Description
File.MD5 String Bad MD5 hash.
File.SHA1 String Bad SHA1 hash.
File.SHA256 String Bad SHA256 hash.
File.Relationships.EntityA String The source of the relationship.
File.Relationships.EntityB String The destination of the relationship.
File.Relationships.Relationship String The name of the relationship.
File.Relationships.EntityAType String The type of the source of the relationship.
File.Relationships.EntityBType String The type of the destination of the relationship.
File.Malicious.Vendor String For malicious files, the vendor that made the decision.
File.Malicious.Detections Number For malicious files, the total number of detections.
File.Malicious.TotalEngines Number For malicious files, the total number of engines that checked the file hash.
DBotScore.Indicator String The indicator that was tested.
DBotScore.Type String The indicator type.
DBotScore.Vendor unknown The vendor used to calculate the score.
DBotScore.Score Number The actual score.
DBotScore.Reliability String Reliability of the source providing the intelligence data.
GoogleThreatIntelligence.File.attributes.type_description String Description of the type of the file.
GoogleThreatIntelligence.File.attributes.tlsh String The locality-sensitive hashing.
GoogleThreatIntelligence.File.attributes.exiftool.MIMEType String MIME type of the file.
GoogleThreatIntelligence.File.attributes.names String Names of the file.
GoogleThreatIntelligence.File.attributes.javascript_info.tags String Tags of the JavaScript.
GoogleThreatIntelligence.File.attributes.exiftool.FileType String The file type.
GoogleThreatIntelligence.File.attributes.exiftool.WordCount String Total number of words in the file.
GoogleThreatIntelligence.File.attributes.exiftool.LineCount String Total number of lines in file.
GoogleThreatIntelligence.File.attributes.crowdsourced_ids_stats.info Number Number of IDS that marked the file as “info”.
GoogleThreatIntelligence.File.attributes.crowdsourced_ids_stats.high Number Number of IDS that marked the file as “high”.
GoogleThreatIntelligence.File.attributes.crowdsourced_ids_stats.medium Number Number of IDS that marked the file as “medium”.
GoogleThreatIntelligence.File.attributes.crowdsourced_ids_stats.low Number Number of IDS that marked the file as “low”.
GoogleThreatIntelligence.File.attributes.sigma_analysis_stats.critical Number Number of Sigma analysis that marked the file as “critical”.
GoogleThreatIntelligence.File.attributes.sigma_analysis_stats.high Number Number of Sigma analysis that marked the file as “high”.
GoogleThreatIntelligence.File.attributes.sigma_analysis_stats.medium Number Number of Sigma analysis that marked the file as “medium”.
GoogleThreatIntelligence.File.attributes.sigma_analysis_stats.low Number Number of Sigma analysis that marked the file as “low”.
GoogleThreatIntelligence.File.attributes.exiftool.MIMEEncoding String The MIME encoding.
GoogleThreatIntelligence.File.attributes.exiftool.FileTypeExtension String The file type extension.
GoogleThreatIntelligence.File.attributes.exiftool.Newlines String Number of newlines signs.
GoogleThreatIntelligence.File.attributes.trid.file_type String The TrID file type.
GoogleThreatIntelligence.File.attributes.trid.probability Number The TrID probability.
GoogleThreatIntelligence.File.attributes.crowdsourced_yara_results.description String Description of the YARA rule.
GoogleThreatIntelligence.File.attributes.crowdsourced_yara_results.source String Source of the YARA rule.
GoogleThreatIntelligence.File.attributes.crowdsourced_yara_results.author String Author of the YARA rule.
GoogleThreatIntelligence.File.attributes.crowdsourced_yara_results.ruleset_name String Rule set name of the YARA rule.
GoogleThreatIntelligence.File.attributes.crowdsourced_yara_results.rule_name String Name of the YARA rule.
GoogleThreatIntelligence.File.attributes.crowdsourced_yara_results.ruleset_id String ID of the YARA rule.
GoogleThreatIntelligence.File.attributes.names String Name of the file.
GoogleThreatIntelligence.File.attributes.last_modification_date Number The last modification date in epoch format.
GoogleThreatIntelligence.File.attributes.type_tag String Tag of the type.
GoogleThreatIntelligence.File.attributes.total_votes.harmless Number Total number of harmless votes.
GoogleThreatIntelligence.File.attributes.total_votes.malicious Number Total number of malicious votes.
GoogleThreatIntelligence.File.attributes.size Number Size of the file.
GoogleThreatIntelligence.File.attributes.popular_threat_classification.suggested_threat_label String Suggested thread label.
GoogleThreatIntelligence.File.attributes.popular_threat_classification.popular_threat_name Number The popular thread name.
GoogleThreatIntelligence.File.attributes.times_submitted Number Number of times the file was submitted.
GoogleThreatIntelligence.File.attributes.last_submission_date Number Last submission date in epoch format.
GoogleThreatIntelligence.File.attributes.downloadable Boolean Whether the file is downloadable.
GoogleThreatIntelligence.File.attributes.sha256 String SHA-256 hash of the file.
GoogleThreatIntelligence.File.attributes.type_extension String Extension of the type.
GoogleThreatIntelligence.File.attributes.tags String File tags.
GoogleThreatIntelligence.File.attributes.last_analysis_date Number Last analysis date in epoch format.
GoogleThreatIntelligence.File.attributes.unique_sources Number Unique sources.
GoogleThreatIntelligence.File.attributes.first_submission_date Number First submission date in epoch format.
GoogleThreatIntelligence.File.attributes.ssdeep String SSDeep hash of the file.
GoogleThreatIntelligence.File.attributes.md5 String MD5 hash of the file.
GoogleThreatIntelligence.File.attributes.sha1 String SHA-1 hash of the file.
GoogleThreatIntelligence.File.attributes.magic String Identification of file by the magic number.
GoogleThreatIntelligence.File.attributes.last_analysis_stats.harmless Number The number of engines that found the indicator to be harmless.
GoogleThreatIntelligence.File.attributes.last_analysis_stats.type-unsupported Number The number of engines that found the indicator to be of type unsupported.
GoogleThreatIntelligence.File.attributes.last_analysis_stats.suspicious Number The number of engines that found the indicator to be suspicious.
GoogleThreatIntelligence.File.attributes.last_analysis_stats.confirmed-timeout Number The number of engines that confirmed the timeout of the indicator.
GoogleThreatIntelligence.File.attributes.last_analysis_stats.timeout Number The number of engines that timed out for the indicator.
GoogleThreatIntelligence.File.attributes.last_analysis_stats.failure Number The number of failed analysis engines.
GoogleThreatIntelligence.File.attributes.last_analysis_stats.malicious Number The number of engines that found the indicator to be malicious.
GoogleThreatIntelligence.File.attributes.last_analysis_stats.undetected Number The number of engines that could not detect the indicator.
GoogleThreatIntelligence.File.attributes.meaningful_name String Meaningful name of the file.
GoogleThreatIntelligence.File.attributes.reputation Number The reputation of the file.
GoogleThreatIntelligence.File.type String Type of the indicator (file).
GoogleThreatIntelligence.File.id String Type ID of the indicator.
GoogleThreatIntelligence.File.links.self String Link to the response.
GoogleThreatIntelligence.File.attributes.gti_assessment.verdict.value String GTI verdict of the file.
GoogleThreatIntelligence.File.attributes.gti_assessment.severity.value String GTI severity of the file.
GoogleThreatIntelligence.File.attributes.gti_assessment.threat_score.value Number GTI threat score of the file.

Command Example

!file file=0000000000000000000000000000000000000000000000000000000000000000

Context Example

{
    "DBotScore": {
        "Indicator": "0000000000000000000000000000000000000000000000000000000000000000",
        "Reliability": "A - Completely reliable",
        "Score": 2,
        "Type": "file",
        "Vendor": "GoogleThreatIntelligence"
    },
    "File": {
        "Extension": "txt",
        "MD5": "00000000000000000000000000000000",
        "SHA1": "0000000000000000000000000000000000000000",
        "SHA256": "0000000000000000000000000000000000000000000000000000000000000000",
        "SSDeep": "3:AIO9AJraNvsgzsVqSwHqiUZ:AeJuOgzskwZ",
        "Size": 103,
        "Tags": [
            "text"
        ],
        "Type": "text/plain"
    },
    "GoogleThreatIntelligence": {
        "File": {
            "attributes": {
                "capabilities_tags": [],
                "crowdsourced_yara_results": [
                    {
                        "author": "Marc Rivero | McAfee ATR Team",
                        "description": "Rule to detect the EICAR pattern",
                        "rule_name": "malw_eicar",
                        "ruleset_id": "0019ab4291",
                        "ruleset_name": "MALW_Eicar",
                        "source": "https://github.com/advanced-threat-research/Yara-Rules"
                    }
                ],
                "downloadable": true,
                "exiftool": {
                    "FileType": "TXT",
                    "FileTypeExtension": "txt",
                    "LineCount": "1",
                    "MIMEEncoding": "us-ascii",
                    "MIMEType": "text/plain",
                    "Newlines": "(none)",
                    "WordCount": "7"
                },
                "first_submission_date": 1613356237,
                "last_analysis_date": 1617088893,
                "last_analysis_stats": {
                    "confirmed-timeout": 0,
                    "failure": 0,
                    "harmless": 0,
                    "malicious": 7,
                    "suspicious": 0,
                    "timeout": 1,
                    "type-unsupported": 16,
                    "undetected": 50
                },
                "last_modification_date": 1617088964,
                "last_submission_date": 1613356237,
                "magic": "ASCII text, with no line terminators",
                "md5": "00000000000000000000000000000000",
                "meaningful_name": "brokencert.exe",
                "names": [
                    "brokencert.exe"
                ],
                "popular_threat_classification": {
                    "popular_threat_name": [
                        [
                            "eicar",
                            7
                        ]
                    ],
                    "suggested_threat_label": "eicar/test"
                },
                "reputation": 0,
                "sha1": "0000000000000000000000000000000000000000",
                "sha256": "0000000000000000000000000000000000000000000000000000000000000000",
                "size": 103,
                "ssdeep": "3:AIO9AJraNvsgzsVqSwHqiUZ:AeJuOgzskwZ",
                "tags": [
                    "text"
                ],
                "times_submitted": 1,
                "tlsh": "T1AEB01208274FFB1ED10738340431F8F14428434D1CD4697414911174887614512D8354",
                "total_votes": {
                    "harmless": 0,
                    "malicious": 0
                },
                "type_description": "Text",
                "type_extension": "txt",
                "type_tag": "text",
                "unique_sources": 1
            },
            "id": "0000000000000000000000000000000000000000000000000000000000000000",
            "links": {
                "self": "https://www.virustotal.com/api/v3/files/0000000000000000000000000000000000000000000000000000000000000000"
            },
            "type": "file"
        }
    }
}

Human Readable Output

Results of file hash 0000000000000000000000000000000000000000000000000000000000000000

Sha1 Sha256 Md5 MeaningfulName TypeExtension Last Modified Reputation Positives
0000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000 brokencert.exe txt 2021-03-30 07:22:44Z 0 7/74

url-scan

  • New output path: GoogleThreatIntelligence.Submission
  • Preserved output: gtiScanID
  • Removed output path: gtiLink - The V3 API does not returns a link to the GUI anymore.

gti-file-scan-upload-url

  • New output path: GoogleThreatIntelligence.FileUploadURL
  • Preserved output: gtiUploadURL

New Commands

  • gti-search
  • gti-ip-passive-dns-data
  • gti-file-sandbox-report
  • gti-comments-get-by-id
  • gti-analysis-get

Commands

You can execute these commands from the CLI, as part of an automation, or in a playbook.
After you successfully execute a command, a DBot message appears in the War Room with the command details.

ip


Checks the reputation of an IP address.

Base Command

ip

Input

Argument Name Description Required
ip IP address to check. Required
extended_data Whether to return extended data (last_analysis_results). Possible values are: true, false. Optional
override_private_lookup When set to “true”, enrichment of private IP addresses will be conducted even if it has been disabled at the integration level. Possible values are: true, false. Optional

Context Output

Path Type Description
IP.Address unknown Bad IP address.
IP.ASN unknown Bad IP ASN.
IP.Geo.Country unknown Bad IP country.
IP.Relationships.EntityA string The source of the relationship.
IP.Relationships.EntityB string The destination of the relationship.
IP.Relationships.Relationship string The name of the relationship.
IP.Relationships.EntityAType string The type of the source of the relationship.
IP.Relationships.EntityBType string The type of the destination of the relationship.
IP.Malicious.Vendor unknown For malicious IPs, the vendor that made the decision.
IP.Malicious.Description unknown For malicious IPs, the reason that the vendor made the decision.
IP.ASOwner String The autonomous system owner of the IP.
DBotScore.Indicator unknown The indicator that was tested.
DBotScore.Type unknown The indicator type.
DBotScore.Vendor unknown The vendor used to calculate the score.
DBotScore.Score Number The actual score.
DBotScore.Reliability String Reliability of the source providing the intelligence data.
GoogleThreatIntelligence.IP.attributes.regional_internet_registry String Regional internet registry (RIR).
GoogleThreatIntelligence.IP.attributes.jarm String JARM data.
GoogleThreatIntelligence.IP.attributes.network String Network data.
GoogleThreatIntelligence.IP.attributes.country String The country where the IP is located.
GoogleThreatIntelligence.IP.attributes.as_owner String IP owner.
GoogleThreatIntelligence.IP.attributes.last_analysis_stats.harmless Number The number of engines that found the domain to be harmless.
GoogleThreatIntelligence.IP.attributes.last_analysis_stats.malicious Number The number of engines that found the indicator to be malicious.
GoogleThreatIntelligence.IP.attributes.last_analysis_stats.suspicious Number The number of engines that found the indicator to be suspicious.
GoogleThreatIntelligence.IP.attributes.last_analysis_stats.undetected Number The number of engines that could not detect the indicator.
GoogleThreatIntelligence.IP.attributes.last_analysis_stats.timeout Number The number of engines that timed out for the indicator.
GoogleThreatIntelligence.IP.attributes.asn Number ASN data.
GoogleThreatIntelligence.IP.attributes.whois_date Number Date of the last update of the whois record.
GoogleThreatIntelligence.IP.attributes.reputation Number IP reputation.
GoogleThreatIntelligence.IP.attributes.last_modification_date Number Last modification date in epoch format.
GoogleThreatIntelligence.IP.attributes.total_votes.harmless Number Total number of harmless votes.
GoogleThreatIntelligence.IP.attributes.total_votes.malicious Number Total number of malicious votes.
GoogleThreatIntelligence.IP.attributes.continent String The continent where the IP is located.
GoogleThreatIntelligence.IP.attributes.whois String whois data.
GoogleThreatIntelligence.IP.type String Indicator IP type.
GoogleThreatIntelligence.IP.id String ID of the IP.
GoogleThreatIntelligence.IP.attributes.gti_assessment.verdict.value String GTI verdict of the IP address.
GoogleThreatIntelligence.IP.attributes.gti_assessment.severity.value String GTI severity of the IP address.
GoogleThreatIntelligence.IP.attributes.gti_assessment.threat_score.value Number GTI threat score of the IP address.

Command example

!ip ip=1.1.1.1

Context Example

{
    "DBotScore": {
        "Indicator": "1.1.1.1",
        "Reliability": "C - Fairly reliable",
        "Score": 1,
        "Type": "ip",
        "Vendor": "GoogleThreatIntelligence"
    },
    "IP": {
        "ASN": 13335,
        "ASOwner": "CLOUDFLARENET",
        "Address": "1.1.1.1",
        "DetectionEngines": 94,
        "PositiveDetections": 4,
        "Relationships": [
            {
                "EntityA": "1.1.1.1",
                "EntityAType": "IP",
                "EntityB": "00000cd773f456da710fa334507f8303e87ee228a0c42e365b0250a9a267e734",
                "EntityBType": "File",
                "Relationship": "communicates-with"
            },
            {
                "EntityA": "1.1.1.1",
                "EntityAType": "IP",
                "EntityB": "0000703e66fe64992425a5a6231671c08a6c3382a28d0efacc7efd3fb289a143",
                "EntityBType": "File",
                "Relationship": "communicates-with"
            }
        ]
    },
    "GoogleThreatIntelligence": {
        "IP": {
            "attributes": {
                "as_owner": "CLOUDFLARENET",
                "asn": 13335,
                "jarm": "27d3ed3ed0003ed1dc42d43d00041d6183ff1bfae51ebd88d70384363d525c",
                "last_analysis_stats": {
                    "harmless": 80,
                    "malicious": 4,
                    "suspicious": 0,
                    "timeout": 0,
                    "undetected": 10
                },
                "last_https_certificate": {
                    "cert_signature": {
                        "signature": "3064023024c2cf6cbdf6aed1c9d51f4a742e3c3dd1c03edcd71bd394715bfea5861626820122d30a6efc98b5d2e2b9e5076977960230457b6f82a67db662c33185d5b5355d4f4c8488ac1a003d0c8440dcb0a7ca1c1327151e37f946c3aed9fdf9b9238b7f2a",
                        "signature_algorithm": "1.2.840.10045.4.3.3"
                    },
                    "extensions": {
                        "**exten**": "0481f200f00076002979bef09e393921f056739f63a577e5be577d9c600af8f9",
                        "CA": true,
                        "authority_key_identifier": {
                            "keyid": "0abc0829178ca5396d7a0ece33c72eb3edfbc37a"
                        },
                        "ca_information_access": {
                            "CA Issuers": "http://cacerts.example.com/exampleTLSHybridECCSHA3842020CA1.crt",
                            "OCSP": "http://ocsp.example.com"
                        },
                        "certificate_policies": [
                            "**policy**"
                        ],
                        "crl_distribution_points": [
                            "http://crl3.example.com/exampleTLSHybridECCSHA3842020CA1.crl",
                            "http://crl4.example.com/exampleTLSHybridECCSHA3842020CA1.crl"
                        ],
                        "extended_key_usage": [
                            "serverAuth",
                            "clientAuth"
                        ],
                        "key_usage": [
                            "ff"
                        ],
                        "subject_alternative_name": [
                            "cloudflare-dns.com",
                            "*.cloudflare-dns.com",
                            "one.one.one.one",
                            "\u0001\u0001\u0001\u0001",
                            "\u0001\u0001",
                            "\\xa2\\x9f$\\x01",
                            "\\xa2\\x9f.\\x01",
                            "&\u0006GG\u0011\u0011",
                            "&\u0006GG\u0010\u0001",
                            "GGd",
                            "GGd"
                        ],
                        "subject_key_identifier": "19451b2318f874da2214cb466be213b360158240",
                        "tags": []
                    },
                    "issuer": {
                        "C": "US",
                        "CN": "example TLS Hybrid ECC SHA384 2020 CA1",
                        "O": "example Inc"
                    },
                    "public_key": {
                        "algorithm": "EC",
                        "ec": {
                            "oid": "secp256r1",
                            "pub": "0417ad1fe835af70d38d9c9e64fd471e5b970c0ad110a826321136664d1299c3e131bbf5216373dda5c1c1a0f06da4c45ee1c2dbdaf90d34801af7b9e03af2d574"
                        }
                    },
                    "serial_number": "5076f66d11b692256ccacd546ffec53",
                    "signature_algorithm": "1.2.840.10045.4.3.3",
                    "size": 1418,
                    "subject": {
                        "C": "US",
                        "CN": "cloudflare-dns.com",
                        "L": "San Francisco",
                        "O": "Cloudflare, Inc.",
                        "ST": "California"
                    },
                    "tags": [],
                    "thumbprint": "f1b38143b992645497cf452f8c1ac84249794282",
                    "thumbprint_sha256": "fb444eb8e68437bae06232b9f5091bccff62a768ca09e92eb5c9c2cf9d17c426",
                    "validity": {
                        "not_after": "2022-10-25 23:59:59",
                        "not_before": "2021-10-25 00:00:00"
                    },
                    "version": "V3"
                },
                "last_https_certificate_date": 1617041198,
                "last_modification_date": 1617083545,
                "network": "1.1.1.0/24",
                "reputation": 134,
                "tags": [],
                "total_votes": {
                    "harmless": 63,
                    "malicious": 8
                },
                "whois": "**whois string**",
                "whois_date": 1631599972
            },
            "id": "1.1.1.1",
            "links": {
                "self": "https://www.virustotal.com/api/v3/ip_addresses/1.1.1.1"
            },
            "relationships": {
                "communicating_files": {
                    "data": [
                        {
                            "id": "00000cd773f456da710fa334507f8303e87ee228a0c42e365b0250a9a267e734",
                            "type": "file"
                        },
                        {
                            "id": "0000703e66fe64992425a5a6231671c08a6c3382a28d0efacc7efd3fb289a143",
                            "type": "file"
                        }
                    ],
                    "links": {
                        "next": "https://www.virustotal.com/api/v3/ip_addresses/1.1.1.1/relationships/communicating_files?cursor=eyJsaW1pdCI6IDIwLCAib2Zmc2V0IjogMjB9&limit=20",
                        "related": "https://www.virustotal.com/api/v3/ip_addresses/1.1.1.1/communicating_files",
                        "self": "https://www.virustotal.com/api/v3/ip_addresses/1.1.1.1/relationships/communicating_files?limit=20"
                    },
                    "meta": {
                        "cursor": "eyJsaW1pdCI6IDIwLCAib2Zmc2V0IjogMjB9"
                    }
                }
            },
            "type": "ip_address"
        }
    }
}

Human Readable Output

IP reputation of 1.1.1.1

Id Network Country AsOwner LastModified Reputation Positives
1.1.1.1 1.1.1.0/24   CLOUDFLARENET 2022-08-29 15:15:41Z 134 4/94

url


Checks the reputation of a URL.

Base Command

url

Input

Argument Name Description Required
url URL to check. Required
extended_data Whether to return extended data (last_analysis_results). Possible values are: true, false. Optional

Context Output

Path Type Description
URL.Data unknown Bad URLs found.
URL.Relationships.EntityA String The source of the relationship.
URL.Relationships.EntityB String The destination of the relationship.
URL.Relationships.Relationship String The name of the relationship.
URL.Relationships.EntityAType String The type of the source of the relationship.
URL.Relationships.EntityBType String The type of the destination of the relationship.
URL.Malicious.Vendor unknown For malicious URLs, the vendor that made the decision.
URL.Malicious.Description unknown For malicious URLs, the reason that the vendor made the decision.
DBotScore.Indicator unknown The indicator that was tested.
DBotScore.Type unknown The indicator type.
DBotScore.Vendor unknown The vendor used to calculate the score.
DBotScore.Score Number The actual score.
DBotScore.Reliability String Reliability of the source providing the intelligence data.
GoogleThreatIntelligence.URL.attributes.favicon.raw_md5 String The MD5 hash of the URL.
GoogleThreatIntelligence.URL.attributes.favicon.dhash String Difference hash.
GoogleThreatIntelligence.URL.attributes.last_modification_date Number Last modification date in epoch format.
GoogleThreatIntelligence.URL.attributes.times_submitted Number The number of times the url has been submitted.
GoogleThreatIntelligence.URL.attributes.total_votes.harmless Number Total number of harmless votes.
GoogleThreatIntelligence.URL.attributes.total_votes.malicious Number Total number of malicious votes.
GoogleThreatIntelligence.URL.attributes.threat_names String Name of the threats found.
GoogleThreatIntelligence.URL.attributes.last_submission_date Number The last submission date in epoch format.
GoogleThreatIntelligence.URL.attributes.last_http_response_content_length Number The last HTTPS response length.
GoogleThreatIntelligence.URL.attributes.last_http_response_headers.date Date The last response header date.
GoogleThreatIntelligence.URL.attributes.last_http_response_headers.x-sinkhole String DNS sinkhole from last response.
GoogleThreatIntelligence.URL.attributes.last_http_response_headers.content-length String The content length of the last response.
GoogleThreatIntelligence.URL.attributes.last_http_response_headers.content-type String The content type of the last response.
GoogleThreatIntelligence.URL.attributes.reputation Number Reputation of the indicator.
GoogleThreatIntelligence.URL.attributes.last_analysis_date Number The date of the last analysis in epoch format.
GoogleThreatIntelligence.URL.attributes.has_content Boolean Whether the url has content in it.
GoogleThreatIntelligence.URL.attributes.first_submission_date Number The first submission date in epoch format.
GoogleThreatIntelligence.URL.attributes.last_http_response_content_sha256 String The SHA-256 hash of the content of the last response.
GoogleThreatIntelligence.URL.attributes.last_http_response_code Number Last response status code.
GoogleThreatIntelligence.URL.attributes.last_final_url String Last final URL.
GoogleThreatIntelligence.URL.attributes.url String The URL itself.
GoogleThreatIntelligence.URL.attributes.title String Title of the page.
GoogleThreatIntelligence.URL.attributes.last_analysis_stats.harmless Number The number of engines that found the domain to be harmless.
GoogleThreatIntelligence.URL.attributes.last_analysis_stats.malicious Number The number of engines that found the indicator to be malicious.
GoogleThreatIntelligence.URL.attributes.last_analysis_stats.suspicious Number The number of engines that found the indicator to be suspicious.
GoogleThreatIntelligence.URL.attributes.last_analysis_stats.undetected Number The number of engines that could not detect the indicator.
GoogleThreatIntelligence.URL.attributes.last_analysis_stats.timeout Number The number of engines that timed out for the indicator.
GoogleThreatIntelligence.URL.attributes.outgoing_links String Outgoing links of the URL page.
GoogleThreatIntelligence.URL.type String Type of the indicator (url).
GoogleThreatIntelligence.URL.id String ID of the indicator.
GoogleThreatIntelligence.URL.links.self String Link to the response.
GoogleThreatIntelligence.URL.attributes.gti_assessment.verdict.value String GTI verdict of the URL.
GoogleThreatIntelligence.URL.attributes.gti_assessment.severity.value String GTI severity of the URL.
GoogleThreatIntelligence.URL.attributes.gti_assessment.threat_score.value Number GTI threat score of the URL.

Command Example

!url url=https://example.com

Context Example

{
    "DBotScore": {
        "Indicator": "https://example.com",
        "Reliability": "A - Completely reliable",
        "Score": 2,
        "Type": "url",
        "Vendor": "GoogleThreatIntelligence"
    },
    "URL": {
        "Category": {
            "Dr.Web": "known infection source",
            "Forcepoint ThreatSeeker": "information technology",
            "alphaMountain.ai": "Malicious",
            "sophos": "malware callhome, command and control"
        },
        "Data": "https://example.com",
        "DetectionEngines": 86,
        "PositiveDetections": 8
    },
    "GoogleThreatIntelligence": {
        "URL": {
            "attributes": {
                "categories": {
                    "Dr.Web": "known infection source"
                },
                "first_submission_date": 1554509044,
                "has_content": false,
                "html_meta": {},
                "last_analysis_date": 1615900309,
                "last_analysis_stats": {
                    "harmless": 71,
                    "malicious": 8,
                    "suspicious": 0,
                    "timeout": 0,
                    "undetected": 7
                },
                "last_final_url": "https://example.com/dashboard/",
                "last_http_response_code": 200,
                "last_http_response_content_length": 1671,
                "last_http_response_content_sha256": "f2ddbc5b5468c2cd9c28ae820420d32c4f53d088e4a1cc31f661230e4893104a",
                "last_http_response_headers": {
                    "content-length": "1671",
                    "content-type": "text/html; charset=utf-8",
                    "date": "Tue, 16 Mar 2021 13:16:50 GMT",
                    "x-sinkhole": "Malware"
                },
                "last_modification_date": 1615900620,
                "last_submission_date": 1615900309,
                "outgoing_links": [
                    "http://www.example.com",
                    "http://www.example.com"
                ],
                "reputation": 0,
                "tags": [],
                "targeted_brand": {},
                "threat_names": [
                    "C2/Generic-A"
                ],
                "times_submitted": 5,
                "title": "Welcome page",
                "total_votes": {
                    "harmless": 0,
                    "malicious": 0
                },
                "trackers": {},
                "url": "https://example.com/"
            },
            "id": "84eb1485254266e093683024b3bd172abde615fc6a37498707ca912964a108a9",
            "links": {
                "self": "https://www.virustotal.com/api/v3/urls/84eb1485254266e093683024b3bd172abde615fc6a37498707ca912964a108a9"
            },
            "type": "url"
        }
    }
}

Human Readable Output

URL data of “https://example.com”

Url Title LastModified HasContent LastHttpResponseContentSha256 Positives Reputation
https://example.com Welcome page 2021-03-16 13:17:00Z false f2ddbc5b5468c2cd9c28ae820420d32c4f53d088e4a1cc31f661230e4893104a 8/86 0

domain


Checks the reputation of a domain.

Base Command

domain\

Input

Argument Name Description Required
domain Domain name to check. Required
extended_data Whether to return extended data (last_analysis_results). Possible values are: true, false. Optional

Context Output

Path Type Description
Domain.Name unknown Bad domain found.
Domain.Relationships.EntityA String The source of the relationship.
Domain.Relationships.EntityB String The destination of the relationship.
Domain.Relationships.Relationship String The name of the relationship.
Domain.Relationships.EntityAType String The type of the source of the relationship.
Domain.Relationships.EntityBType String The type of the destination of the relationship.
Domain.Malicious.Vendor unknown For malicious domains, the vendor that made the decision.
Domain.Malicious.Description unknown For malicious domains, the reason that the vendor made the decision.
DBotScore.Indicator unknown The indicator that was tested.
DBotScore.Type unknown The indicator type.
DBotScore.Vendor unknown The vendor used to calculate the score.
DBotScore.Score Number The actual score.
DBotScore.Reliability String Reliability of the source providing the intelligence data.
GoogleThreatIntelligence.Domain.attributes.last_dns_records.type String The type of the last DNS records.
GoogleThreatIntelligence.Domain.attributes.last_dns_records.value String The value of the last DNS records.
GoogleThreatIntelligence.Domain.attributes.last_dns_records.ttl Number The time To live (ttl) of the last DNS records.
GoogleThreatIntelligence.Domain.attributes.jarm String JARM data.
GoogleThreatIntelligence.Domain.attributes.whois String whois data.
GoogleThreatIntelligence.Domain.attributes.last_dns_records_date Number The last DNS records date in epoch format.
GoogleThreatIntelligence.Domain.attributes.last_analysis_stats.harmless Number The number of engines that found the domain to be harmless.
GoogleThreatIntelligence.Domain.attributes.last_analysis_stats.malicious Number The number of engines that found the indicator to be malicious.
GoogleThreatIntelligence.Domain.attributes.last_analysis_stats.suspicious Number The number of engines that found the indicator to be suspicious.
GoogleThreatIntelligence.Domain.attributes.last_analysis_stats.undetected Number The number of engines that could not detect the indicator.
GoogleThreatIntelligence.Domain.attributes.last_analysis_stats.timeout Number The number of engines that timed out for the indicator.
GoogleThreatIntelligence.Domain.attributes.favicon.raw_md5 String MD5 hash of the domain.
GoogleThreatIntelligence.Domain.attributes.favicon.dhash String Difference hash.
GoogleThreatIntelligence.Domain.attributes.reputation Number Reputation of the indicator.
GoogleThreatIntelligence.Domain.attributes.registrar String Registrar information.
GoogleThreatIntelligence.Domain.attributes.last_update_date Number Last updated date in epoch format.
GoogleThreatIntelligence.Domain.attributes.last_modification_date Number Last modification date in epoch format.
GoogleThreatIntelligence.Domain.attributes.creation_date Number Creation date in epoch format.
GoogleThreatIntelligence.Domain.attributes.total_votes.harmless Number Total number of harmless votes.
GoogleThreatIntelligence.Domain.attributes.total_votes.malicious Number Total number of malicious votes.
GoogleThreatIntelligence.Domain.type String Type of indicator (domain).
GoogleThreatIntelligence.Domain.id String ID of the domain.
GoogleThreatIntelligence.Domain.links.self String Link to the domain investigation.
GoogleThreatIntelligence.Domain.attributes.gti_assessment.verdict.value String GTI verdict of the domain.
GoogleThreatIntelligence.Domain.attributes.gti_assessment.severity.value String GTI severity of the domain.
GoogleThreatIntelligence.Domain.attributes.gti_assessment.threat_score.value Number GTI threat score of the domain.

Command Example

!domain domain=example.com

Context Example

{
    "DBotScore": {
        "Indicator": "example.com",
        "Reliability": "A - Completely reliable",
        "Score": 2,
        "Type": "domain",
        "Vendor": "GoogleThreatIntelligence"
    },
    "Domain": {
        "Admin": {
            "Country": " PA",
            "Email": " [REDACTED]@whoisguard.com",
            "Name": " WhoisGuard, Inc.",
            "Phone": null
        },
        "CreationDate": [
            " 2017-01-21T16:26:19.0Z"
        ],
        "ExpirationDate": " 2018-01-21T23:59:59.0Z",
        "Name": "example.com",
        "NameServers": [
            " PDNS1.REGISTRAR-SERVERS.COM"
        ],
        "Registrant": {
            "Country": " PA",
            "Email": " [REDACTED]@whoisguard.com",
            "Name": null,
            "Phone": null
        },
        "Registrar": {
            "AbuseEmail": " abuse@namecheap.com",
            "AbusePhone": " +1.6613102107",
            "Name": [
                " Namecheap",
                " NAMECHEAP INC"
            ]
        },
        "UpdatedDate": [
            "2017-03-06T21:52:39.0Z"
        ],
        "WHOIS": {
            "Admin": {
                "Country": " PA",
                "Email": " [REDACTED]@whoisguard.com",
                "Name": " WhoisGuard, Inc.",
                "Phone": null
            },
            "CreationDate": [
                "2017-01-21T16:26:19.0Z"
            ],
            "ExpirationDate": " 2018-01-21T23:59:59.0Z",
            "NameServers": [
                " PDNS1.REGISTRAR-SERVERS.COM"
            ],
            "Registrant": {
                "Country": " PA",
                "Email": " [REDACTED]@whoisguard.com",
                "Name": null,
                "Phone": null
            },
            "Registrar": {
                "AbuseEmail": " abuse@namecheap.com",
                "AbusePhone": " +1.6613102107",
                "Name": [
                    " Namecheap",
                    " NAMECHEAP INC"
                ]
            },
            "UpdatedDate": [
                " 2017-03-06T21:52:39.0Z"
            ]
        }
    },
    "GoogleThreatIntelligence": {
        "Domain": {
            "attributes": {
                "categories": {
                    "Dr.Web": "known infection source",
                    "Forcepoint ThreatSeeker": "information technology",
                    "alphaMountain.ai": "Malicious",
                    "sophos": "malware callhome, command and control"
                },
                "creation_date": 1485015979,
                "favicon": {
                    "dhash": "f4cca89496a0ccb2",
                    "raw_md5": "6eb4a43cb64c97f76562af703893c8fd"
                },
                "jarm": "29d21b20d29d29d21c41d21b21b41d494e0df9532e75299f15ba73156cee38",
                "last_analysis_stats": {
                    "harmless": 66,
                    "malicious": 8,
                    "suspicious": 0,
                    "timeout": 0,
                    "undetected": 8
                },
                "last_dns_records": [
                    {
                        "ttl": 3599,
                        "type": "A",
                        "value": "value"
                    }
                ],
                "last_dns_records_date": 1615900633,
                "last_modification_date": 1615900633,
                "last_update_date": 1488837159,
                "popularity_ranks": {},
                "registrar": "Namecheap",
                "reputation": 0,
                "tags": [],
                "total_votes": {
                    "harmless": 0,
                    "malicious": 0
                },
                "whois": "**whoisstring**"
            },
            "id": "example.com",
            "links": {
                "self": "https://www.virustotal.com/api/v3/domains/example.com"
            },
            "type": "domain"
        }
    }
}

Human Readable Output

Domain data of example.com

Id Registrant Country LastModified LastAnalysisStats
example.com PA 2021-03-16 13:17:13Z harmless: 66malicious: 8
suspicious: 0
undetected: 8
timeout: 0

cve


Retrieves CVE information from Google Threat Intelligence.

Base Command

cve

Input

Argument Name Description Required
cve Provide CVE ID. Supports comma-separated values. Required

Context Output

Path Type Description
CVE.CVSS.Score Number CVSS score indicating the severity of the vulnerability.
CVE.CVSS.Vector String CVSS vector string representing attack metrics and impact.
CVE.Description String Full textual description of the CVE, including affected components and exploitation details.
CVE.ID String Unique identifier for the CVE (e.g., CVE-2025-14205).
CVE.Modified Date Timestamp when the CVE record was last modified (e.g., 1766963614).
CVE.Published Date Timestamp when the CVE was originally published (e.g., 1766963614).
CVE.Relationships.EntityA String First entity in the relationship (usually the CVE ID).
CVE.Relationships.EntityAType String Type of the first entity (e.g., CVE).
CVE.Relationships.EntityB String Second entity in the relationship (e.g., file, IP, domain).
CVE.Relationships.EntityBType String Type of the second entity (e.g., File, Domain, IP).
CVE.Relationships.Relationship String Nature of the relationship between EntityA and EntityB (e.g., related-to).
CVE.Relationships.STIXID String STIX ID associated with the CVE relationship.
DBotScore.Indicator String The indicator that was tested.
DBotScore.Reliability String Reliability rating of the threat intelligence source (e.g., A - Completely reliable, B - Usually reliable).
DBotScore.Score Number The actual score.
DBotScore.Type String The indicator type.
DBotScore.Vendor String The vendor used to calculate the score.
GoogleThreatIntelligence.CVE.id String ID of the CVE.
GoogleThreatIntelligence.CVE.type String Data type returned (usually ‘cve’).
GoogleThreatIntelligence.CVE.links.self String API link to the detailed CVE resource.
GoogleThreatIntelligence.CVE.attributes.urls_count Number Number of URLs associated with the CVE.
GoogleThreatIntelligence.CVE.attributes.is_content_translated Boolean Indicates if the CVE content has been machine-translated.
GoogleThreatIntelligence.CVE.attributes.autogenerated_tags List Tags automatically generated for this CVE.
GoogleThreatIntelligence.CVE.attributes.subscribers_count Number Number of GTI users subscribed to updates for this CVE.
GoogleThreatIntelligence.CVE.attributes.risk_rating String GTI-assigned risk rating (e.g., Low/Medium/High/Critical).
GoogleThreatIntelligence.CVE.attributes.sources.title String Title of the external reference source.
GoogleThreatIntelligence.CVE.attributes.sources.name String Name of the external reference source.
GoogleThreatIntelligence.CVE.attributes.sources.url String URL of the external reference source.
GoogleThreatIntelligence.CVE.attributes.sources.source_description String Description of the reference source.
GoogleThreatIntelligence.CVE.attributes.sources.cvss.cvssv2_0.base_score Number CVSS v2 base score from the source.
GoogleThreatIntelligence.CVE.attributes.sources.cvss.cvssv2_0.temporal_score Number CVSS v2 temporal score from the source.
GoogleThreatIntelligence.CVE.attributes.sources.cvss.cvssv2_0.vector String CVSS v2 vector string.
GoogleThreatIntelligence.CVE.attributes.sources.cvss.cvssv3_x.base_score Number CVSS v3 base score from the source.
GoogleThreatIntelligence.CVE.attributes.sources.cvss.cvssv3_x.temporal_score Number CVSS v3 temporal score from the source.
GoogleThreatIntelligence.CVE.attributes.sources.cvss.cvssv3_x.vector String CVSS v3 vector string.
GoogleThreatIntelligence.CVE.attributes.sources.cvss.cvssv4_x.score Number CVSS v4 base score from the source.
GoogleThreatIntelligence.CVE.attributes.sources.cvss.cvssv4_x.vector String CVSS v4 vector string.
GoogleThreatIntelligence.CVE.attributes.sources.cvss.cvssv4_x.threat.exploit_maturity String Threat metrics associated with CVSS v4.
GoogleThreatIntelligence.CVE.attributes.sources.cvss.cvssv3_x_translated.temporal_score Number Machine-translated CVSS v3 metrics.
GoogleThreatIntelligence.CVE.attributes.sources.cvss.cvssv3_x_translated.base_score Number Machine-translated CVSS v3 metrics.
GoogleThreatIntelligence.CVE.attributes.sources.cvss.cvssv3_x_translated.vector String Machine-translated CVSS v3 metrics.
GoogleThreatIntelligence.CVE.attributes.sources.published_date String Source publication date for the CVE information.
GoogleThreatIntelligence.CVE.attributes.sources.md5 String MD5 hash associated with the source content.
GoogleThreatIntelligence.CVE.attributes.sources.unique_id String Unique identifier for the source entry.
GoogleThreatIntelligence.CVE.attributes.name String Name/title of the CVE entry inside GTI.
GoogleThreatIntelligence.CVE.attributes.capabilities List Attacker capabilities related to the CVE.
GoogleThreatIntelligence.CVE.attributes.technologies List Technologies impacted by the CVE.
GoogleThreatIntelligence.CVE.attributes.counters.files Number Number of malicious files associated with the CVE.
GoogleThreatIntelligence.CVE.attributes.counters.domains Number Number of domains associated with the CVE.
GoogleThreatIntelligence.CVE.attributes.counters.ip_addresses Number Number of IP addresses linked to the CVE.
GoogleThreatIntelligence.CVE.attributes.counters.urls Number Number of URLs related to the CVE.
GoogleThreatIntelligence.CVE.attributes.counters.iocs Number Total indicator count associated with the CVE.
GoogleThreatIntelligence.CVE.attributes.counters.subscribers Number Number of subscribers following the CVE.
GoogleThreatIntelligence.CVE.attributes.counters.attack_techniques Number Count of associated attack techniques (MITRE etc.).
GoogleThreatIntelligence.CVE.attributes.cve_id String The CVE identifier (e.g., CVE-2024-12345).
GoogleThreatIntelligence.CVE.attributes.domains_count Number Number of domains involved in CVE activity.
GoogleThreatIntelligence.CVE.attributes.version_history.date Number Date when the version entry was updated.
GoogleThreatIntelligence.CVE.attributes.version_history.version_notes String Notes about changes in CVE version history.
GoogleThreatIntelligence.CVE.attributes.alt_names List Alternate names or aliases for the CVE.
GoogleThreatIntelligence.CVE.attributes.recent_activity_summary Number Recent activity score or summary related to exploitation.
GoogleThreatIntelligence.CVE.attributes.exploitation.exploit_release_date String Date when exploit code was released.
GoogleThreatIntelligence.CVE.attributes.exploitation.first_exploitation String Date when the CVE was first exploited.
GoogleThreatIntelligence.CVE.attributes.exploitation.tech_details_release_date String Date technical details were publicly released.
GoogleThreatIntelligence.CVE.attributes.mitigations List Mitigation steps for the CVE.
GoogleThreatIntelligence.CVE.attributes.top_icon_md5 List MD5 hash of the top-listed malicious sample.
GoogleThreatIntelligence.CVE.attributes.description String Full CVE description.
GoogleThreatIntelligence.CVE.attributes.targeted_regions List Geographic regions targeted by exploitation.
GoogleThreatIntelligence.CVE.attributes.detection_names List Security vendor detection names linked to the CVE.
GoogleThreatIntelligence.CVE.attributes.vendor_fix_references List Vendor-published fix or patch references.
GoogleThreatIntelligence.CVE.attributes.malware_roles List Malware roles (dropper, loader, etc.) related to the CVE.
GoogleThreatIntelligence.CVE.attributes.collection_links List Related collection or reference links from GTI.
GoogleThreatIntelligence.CVE.attributes.source_regions_hierarchy List Hierarchy of affected regions sourced by GTI.
GoogleThreatIntelligence.CVE.attributes.references_count Number Number of references for the CVE.
GoogleThreatIntelligence.CVE.attributes.creation_date Number Date when the CVE entry was created in GTI.
GoogleThreatIntelligence.CVE.attributes.risk_factors String List of risk factors contributing to severity.
GoogleThreatIntelligence.CVE.attributes.exploit_availability String Availability status of exploit (e.g., Available/None).
GoogleThreatIntelligence.CVE.attributes.merged_actors List Threat actors linked to this vulnerability.
GoogleThreatIntelligence.CVE.attributes.first_seen_details List Details on when this CVE was first observed.
GoogleThreatIntelligence.CVE.attributes.available_mitigation List Available mitigations for exploitation prevention.
GoogleThreatIntelligence.CVE.attributes.last_modification_date Number Last updated timestamp for the CVE in GTI.
GoogleThreatIntelligence.CVE.attributes.mve_id String MVE (Multi-Vulnerability Event) ID for grouping related issues.
GoogleThreatIntelligence.CVE.attributes.tags List Tags associated with the CVE inside GTI.
GoogleThreatIntelligence.CVE.attributes.cvss.cvssv2_0.base_score Number CVSS v2 base score.
GoogleThreatIntelligence.CVE.attributes.cvss.cvssv2_0.temporal_score Number CVSS v2 temporal score.
GoogleThreatIntelligence.CVE.attributes.cvss.cvssv2_0.vector String CVSS v2 vector notation.
GoogleThreatIntelligence.CVE.attributes.cvss.cvssv3_x.base_score Number CVSS v3 base score.
GoogleThreatIntelligence.CVE.attributes.cvss.cvssv3_x.temporal_score Number CVSS v3 temporal score.
GoogleThreatIntelligence.CVE.attributes.cvss.cvssv3_x.vector String CVSS v3 vector string.
GoogleThreatIntelligence.CVE.attributes.cvss.cvssv4_x.score Number CVSS v4 score.
GoogleThreatIntelligence.CVE.attributes.cvss.cvssv4_x.supplemental.provider_urgency String Provider urgency supplemental metric.
GoogleThreatIntelligence.CVE.attributes.cvss.cvssv4_x.supplemental.response_effort String Response effort supplemental metric.
GoogleThreatIntelligence.CVE.attributes.cvss.cvssv4_x.supplemental.recovery String Recovery supplemental metric.
GoogleThreatIntelligence.CVE.attributes.cvss.cvssv4_x.supplemental.safety String Safety supplemental metric.
GoogleThreatIntelligence.CVE.attributes.cvss.cvssv4_x.supplemental.value_density String Value density supplemental metric.
GoogleThreatIntelligence.CVE.attributes.cvss.cvssv4_x.supplemental.automatable String Indicates if exploitation can be automated.
GoogleThreatIntelligence.CVE.attributes.cvss.cvssv4_x.vector String CVSS v4 vector string.
GoogleThreatIntelligence.CVE.attributes.cvss.cvssv4_x.threat.exploit_maturity String Exploit maturity level (e.g., High/Functional/Proof of Concept).
GoogleThreatIntelligence.CVE.attributes.cvss.cvssv3_x_translated.base_score Number Machine-translated CVSS v3 base score.
GoogleThreatIntelligence.CVE.attributes.cvss.cvssv3_x_translated.temporal_score Number Machine-translated CVSS v3 temporal score.
GoogleThreatIntelligence.CVE.attributes.cvss.cvssv3_x_translated.vector String Machine-translated CVSS v3 vector.
GoogleThreatIntelligence.CVE.attributes.collection_type String Type of GTI collection this CVE belongs to.
GoogleThreatIntelligence.CVE.attributes.targeted_industries List Industries targeted by exploitation of this CVE.
GoogleThreatIntelligence.CVE.attributes.cwe.title String Title of the mapped CWE (root cause).
GoogleThreatIntelligence.CVE.attributes.cwe.id String CWE identifier linked to the CVE.
GoogleThreatIntelligence.CVE.attributes.affected_systems List Systems or platforms affected by the vulnerability.
GoogleThreatIntelligence.CVE.attributes.tags_details List Detailed metadata for GTI tags.
GoogleThreatIntelligence.CVE.attributes.executive_summary String High-level summary of the vulnerability impact.
GoogleThreatIntelligence.CVE.attributes.priority String GTI-assigned priority score/category.
GoogleThreatIntelligence.CVE.attributes.alt_names_details List Additional details about alternate CVE names.
GoogleThreatIntelligence.CVE.attributes.targeted_regions_hierarchy List Hierarchy of targeted regions for exploitation.
GoogleThreatIntelligence.CVE.attributes.epss.percentile Number EPSS percentile (Exploit Prediction Scoring System).
GoogleThreatIntelligence.CVE.attributes.epss.score Number EPSS score indicating exploitation likelihood.
GoogleThreatIntelligence.CVE.attributes.date_of_disclosure Number Date when the vulnerability was publicly disclosed.
GoogleThreatIntelligence.CVE.attributes.days_to_report Number Time taken from discovery to reporting.
GoogleThreatIntelligence.CVE.attributes.targeted_industries_tree List Hierarchical breakdown of targeted industries.
GoogleThreatIntelligence.CVE.attributes.status String Current vulnerability status (e.g., Active, Resolved).
GoogleThreatIntelligence.CVE.attributes.intended_effects List Intent or malicious outcomes achieved by exploiting the CVE.
GoogleThreatIntelligence.CVE.attributes.private Boolean Whether the CVE entry is private in GTI.
GoogleThreatIntelligence.CVE.attributes.targeted_informations List Types of information targeted by attackers.
GoogleThreatIntelligence.CVE.attributes.ip_addresses_count Number Number of IPs related to the vulnerability.
GoogleThreatIntelligence.CVE.attributes.mati_genids_dict.report_id String MATI report ID linked to the CVE.
GoogleThreatIntelligence.CVE.attributes.mati_genids_dict.cve_id String CVE ID mapped within MATI dataset.
GoogleThreatIntelligence.CVE.attributes.mati_genids_dict.mve_id String MVE ID mapped within MATI dataset.
GoogleThreatIntelligence.CVE.attributes.exploitation_state String Current exploitation state (Known Exploited / No Evidence).
GoogleThreatIntelligence.CVE.attributes.field_sources.source.sources List Source list for specific enriched fields.
GoogleThreatIntelligence.CVE.attributes.field_sources.source.source_url String URL of the field’s data source.
GoogleThreatIntelligence.CVE.attributes.field_sources.source.field_type String Type of field data (e.g., text, reference).
GoogleThreatIntelligence.CVE.attributes.field_sources.source.source_name String Name of the field’s data source provider.
GoogleThreatIntelligence.CVE.attributes.field_sources.field String Field name being sourced.
GoogleThreatIntelligence.CVE.attributes.field_sources.source.sources.source_names String Names of the sources contributing to this field.
GoogleThreatIntelligence.CVE.attributes.field_sources.source.sources.source_urls List URLs of the sources contributing to this field.
GoogleThreatIntelligence.CVE.attributes.exploitation_vectors String Methods or vectors used to exploit the vulnerability.
GoogleThreatIntelligence.CVE.attributes.threat_scape String Threat landscape and context around the CVE.
GoogleThreatIntelligence.CVE.attributes.operating_systems List Operating systems impacted by the CVE.
GoogleThreatIntelligence.CVE.attributes.last_seen_details List Last observed exploitation activity details.
GoogleThreatIntelligence.CVE.attributes.workarounds List Workarounds available to mitigate the vulnerability.
GoogleThreatIntelligence.CVE.attributes.motivations List Attacker motivations behind exploiting this CVE.
GoogleThreatIntelligence.CVE.attributes.predicted_risk_rating String AI-generated predicted risk rating.
GoogleThreatIntelligence.CVE.attributes.files_count Number Number of files linked to the CVE.
GoogleThreatIntelligence.CVE.attributes.exploitation_consequence String Possible consequences of exploitation.
GoogleThreatIntelligence.CVE.attributes.origin String Origin/source of the CVE data.
GoogleThreatIntelligence.CVE.attributes.aggregations List Aggregated threat or metadata information.
GoogleThreatIntelligence.CVE.context_attributes.shared_with_me Boolean Indicates if the CVE is shared with the user.
GoogleThreatIntelligence.CVE.context_attributes.role String User role for viewing this CVE in GTI.

Command Example

!cve cve=CVE-2022-30190

Context Example

{
    "CVE": {
        "CVSS": {
            "Score": 7.8,
            "Vector": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H/E:F/RL:O/RC:C"
        },
        "Description": "google has provided the follow description:  \n*A remote code execution vulnerability exists when MSDT is called using the URL protocol from a calling application such as Word.",
        "ID": "CVE-2022-30190",
        "Modified": "2025-10-29T18:46:49.000Z",
        "Published": "2022-05-27T00:00:00.000Z",
        "Relationships": [
            {
                "EntityA": "CVE-2022-30190",
                "EntityAType": "CVE",
                "EntityB": "test_md5_001",
                "EntityBType": "File",
                "Relationship": "related-to"
            },
            {
                "EntityA": "CVE-2022-30190",
                "EntityAType": "CVE",
                "EntityB": "test_md5_002",
                "EntityBType": "File",
                "Relationship": "related-to"
            }
        ],
        "STIXID": "CVE-2022-30190",
        "Tags": [
            "observed_in_the_wild",
            "has_exploits",
            "was_zero_day",
            "media_attention"
        ]
    },
    "DBotScore": {
        "Indicator": "CVE-2022-30190",
        "Reliability": "C - Fairly reliable",
        "Score": 2,
        "Type": "cve",
        "Vendor": "GoogleThreatIntelligence"
    },
    "GoogleThreatIntelligence": {
        "CVE": {
            "id": "vulnerability--cve-2022-30190",
            "type": "collection",
            "links": {
                "self": "https://www.virustotal.com/api/v3/collections/vulnerability--cve-2022-30190"
            },
            "attributes": {
                "description": "google has provided the following description:  \n*A remote code execution vulnerability exists when MSDT is called using the URL protocol from a calling application such as Word.",
                "risk_factors": [
                    "User Interaction Required"
                ],
                "predicted_risk_rating": "",
                "exploitation_state": "Confirmed",
                "version_history": [
                    {
                        "date": 1761763609,
                        "version_notes": [
                            "cisa_known_exploited.ransomware_use: Unknown -> Known"
                        ]
                    }
                ],
                "recent_activity_relative_change": 0.0714285714285714,
                "cisa_known_exploited": {
                    "added_date": 1655164800,
                    "due_date": 1656979200,
                    "ransomware_use": "Known"
                },
                "origin": "Google Threat Intelligence",
                "exploitation": {
                    "tech_details_release_date": 1689120000,
                    "first_exploitation": 1651276800,
                    "exploit_release_date": 1653868800
                },
                "available_mitigation": [
                    "Workaround",
                    "Patch"
                ],
                "alt_names_details": [
                    {
                        "value": "Follina",
                        "confidence": "possible"
                    }
                ],
                "mve_id": "MVE-2022-4552",
                "tags": [
                    "observed_in_the_wild",
                    "has_exploits",
                    "was_zero_day",
                    "media_attention"
                ],
                "executive_summary": "* An Improper Control of Generation of Code ('Code Injection') vulnerability exists that, when exploited, allows a remote attacker to execute arbitrary code.",
                "autogenerated_tags": [
                    "cve-2021-40444"
                ],
                "workarounds": [
                    "<p>google recommends disabling the MSDT URL Protocol as a method to mitigate the chance of exploitation. For more information see their advisory."
                ],
                "date_of_disclosure": 1653609600,
                "vendor_fix_references": [
                    {
                        "url": "https://portal.msrc.google.com/en-US/security-guidance/advisory/CVE-2022-30190",
                        "name": "google Corp.",
                        "published_date": 1653894000,
                        "title": "google Windows Support Diagnostic Tool (MSDT) Remote Code Execution Vulnerability (CVE-2022-30190)"
                    }
                ],
                "cpes": [
                    {
                        "start_cpe": {
                            "version": "R2",
                            "uri": "cpe:2.3:o:google:windows_server_2012:r2:*:*:*:*:*:*:*",
                            "product": "Windows Server 2012 (OS)",
                            "vendor": "google"
                        },
                        "start_rel": "="
                    }
                ],
                "field_sources": [
                    {
                        "field": "cvss.cvssv3_x",
                        "source": {
                            "field_type": "Ranked",
                            "source_name": "Google Threat Intelligence Group (GTIG)",
                            "source_url": ""
                        }
                    }
                ],
                "ip_addresses_count": 0,
                "private": true,
                "cve_id": "CVE-2022-30190",
                "sources": [
                    {
                        "md5": "test_md5_001",
                        "url": "https://github.com/cisagov/vulnrichment/blob/develop/2022/30xxx/test_CVE_2022_30190.json",
                        "name": "Cybersecurity and Infrastructure Security Agency (CISA)",
                        "published_date": 1654114217,
                        "title": "google Windows Support Diagnostic Tool (MSDT) Remote Code Execution Vulnerability",
                        "cvss": {
                            "cvssv3_x": {
                                "base_score": 7.8,
                                "vector": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H/E:P/RL:O/RC:C"
                            }
                        }
                    },
                    {
                        "md5": "test_md5_002",
                        "url": "https://github.com/CVEProject/cvelistV5/blob/main/cves/2022/30xxx/test_CVE_2022_30190.json",
                        "name": "Mitre Corporation",
                        "published_date": 1654114217,
                        "title": "google Windows Support Diagnostic Tool (MSDT) Remote Code Execution Vulnerability",
                        "cvss": {
                            "cvssv3_x": {
                                "base_score": 7.8,
                                "vector": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H/E:P/RL:O/RC:C"
                            }
                        }
                    }
                ],
                "alt_names": [
                    "Follina"
                ],
                "exploitation_consequence": "Code Execution",
                "name": "CVE-2022-30190",
                "tags_details": [
                    {
                        "value": "has_exploits",
                        "confidence": "possible"
                    }
                ],
                "analysis": "An attacker could exploit this vulnerability to execute arbitrary code. An attacker would need to create a specially url calling MSDT and cause a user to open it on a vulnerable system.",
                "summary_stats": {
                    "first_submission_date": {
                        "min": 0,
                        "max": 1746722000,
                        "avg": 733834342.875
                    },
                    "last_submission_date": {
                        "min": 0,
                        "max": 1746722000,
                        "avg": 735827136.25
                    },
                    "files_detections": {
                        "min": 0,
                        "max": 48,
                        "avg": 16.5625
                    }
                },
                "files_count": 18,
                "creation_date": 1653927632,
                "exploitation_vectors": [
                    "File Share",
                    "Web",
                    "Email",
                    "Malicious File"
                ],
                "recent_activity_summary": [],
                "days_to_report": 3,
                "last_modification_date": 1761763609,
                "is_content_translated": false,
                "risk_rating": "MEDIUM",
                "exploit_availability": "Publicly Available",
                "vulnerable_products": "",
                "references_count": 0,
                "urls_count": 0,
                "days_to_patch": 3,
                "collection_type": "vulnerability",
                "counters": {
                    "files": 18,
                    "domains": 0,
                    "ip_addresses": 0,
                    "urls": 0,
                    "iocs": 18,
                    "subscribers": 0,
                    "attack_techniques": 0
                },
                "status": "COMPUTED",
                "epss": {
                    "score": 0.93187,
                    "percentile": 0.99784
                },
                "mati_genids_dict": {
                    "mve_id": "vulnerability--test_mve_id",
                    "cve_id": "vulnerability--test_cve_id",
                    "report_id": "report--test_report_id"
                },
                "cvss": {
                    "cvssv3_x": {
                        "base_score": 7.8,
                        "vector": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H/E:F/RL:O/RC:C",
                        "temporal_score": 7.2
                    },
                    "cvssv2_0": {
                        "base_score": 6.8,
                        "vector": "AV:N/AC:M/Au:N/C:P/I:P/A:P/E:F/RL:OF/RC:C",
                        "temporal_score": 5.6
                    }
                },
                "domains_count": 0,
                "subscribers_count": 0,
                "priority": "P1",
                "cwe": {
                    "title": "Improper Control of Generation of Code ('Code Injection')",
                    "id": "CWE-94"
                }
            },
            "context_attributes": {
                "shared_with_me": false,
                "role": "viewer"
            }
        }
    }
}

Human Readable Output

CVE Information: CVE-2022-30190

CVE ID Risk Rating Priority Exploitation State Exploit Availability CVSS v3.x Score CVSS v4.x Score CVSS v3.x Vector Date Of Disclosure Creation Date Last Modified Sources Description Related Files Related Domains Related IPs Related URLs Executive Summary
CVE-2022-30190 MEDIUM P1 Confirmed Publicly Available 7.8 0 CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H/E:F/RL:O/RC:C 2022-05-27T00:00:00.000Z 2022-05-30T16:20:32.000Z 2025-10-29T18:46:49.000Z 2 google has provided the following description:
*A remote code execution vulnerability exists when MSDT is called using the URL protocol from a calling application such as Word.
2 0 0 0 * An Improper Control of Generation of Code (‘Code Injection’) vulnerability exists that, when exploited, allows a remote attacker to execute arbitrary code.

url-scan


Scans a specified URL. Use the gti-analysis-get command to get the scan results.

Base Command

url-scan

Input

Argument Name Description Required
url The URL to scan. Required

Context Output

Path Type Description
GoogleThreatIntelligence.Submission.Type String The type of the submission (analysis).
GoogleThreatIntelligence.Submission.id String The ID of the submission.
GoogleThreatIntelligence.Submission.hash String The indicator sent to rescan.

Command Example

!url-scan url=https://example.com

Context Example

{
    "GoogleThreatIntelligence": {
        "Submission": {
            "id": "u-0f115db062b7c0dd030b16878c99dea5c354b49dc37b38eb8846179c7783e9d7-1617088890",
            "type": "analysis",
            "url": "https://example.com"
        }
    },
    "gtiScanID": "u-0f115db062b7c0dd030b16878c99dea5c354b49dc37b38eb8846179c7783e9d7-1617088890"
}

Human Readable Output

New url submission

id url
u-0f115db062b7c0dd030b16878c99dea5c354b49dc37b38eb8846179c7783e9d7-1617088890 https://example.com

gti-comments-add


Adds comments to files and URLs.

Base Command

gti-comments-add

Input

Argument Name Description Required
resource The file hash (MD5, SHA1, orSHA256), Domain, URL or IP on which you’re commenting on. If not supplied, will try to determine if it’s a hash or a url. Required
resource_type The type of the resource on which you’re commenting. Possible values are: ip, url, domain, hash. Optional
comment The actual review that you can tag by using the “#” twitter-like syntax, for example, #disinfection #zbot, and reference users using the “@” syntax, for example, @GoogleThreatIntelligenceTeam. Required

Context Output

Path Type Description
GoogleThreatIntelligence.Comments.comments.attributes.date Number The date of the comment in epoch format.
GoogleThreatIntelligence.Comments.comments.attributes.text String The text of the comment.
GoogleThreatIntelligence.Comments.comments.attributes.votes.positive Number Number of positive votes.
GoogleThreatIntelligence.Comments.comments.attributes.votes.abuse Number Number of abuse votes.
GoogleThreatIntelligence.Comments.comments.attributes.votes.negative Number Number of negative votes.
GoogleThreatIntelligence.Comments.comments.attributes.html String The HTML content.
GoogleThreatIntelligence.Comments.comments.type String The type of the comment.
GoogleThreatIntelligence.Comments.comments.id String ID of the comment.
GoogleThreatIntelligence.Comments.comments.links.self String Link to the request.

Command Example

!gti-comments-add resource=paloaltonetworks.com resource_type=domain comment="this is a comment"

Context Example

{
    "GoogleThreatIntelligence": {
        "Comments": {
            "comments": {
                "attributes": {
                    "date": 1617088894,
                    "html": "this is a comment",
                    "tags": [],
                    "text": "this is a comment",
                    "votes": {
                        "abuse": 0,
                        "negative": 0,
                        "positive": 0
                    }
                },
                "id": "d-paloaltonetworks.com-e757b16b",
                "links": {
                    "self": "https://www.virustotal.com/api/v3/comments/d-paloaltonetworks.com-e757b16b"
                },
                "type": "comment"
            }
        }
    }
}

Human Readable Output

Comment has been added

Date Text Positive Votes Abuse Votes Negative Votes
2021-03-30 07:21:34Z this is a comment 0 0 0

gti-file-scan-upload-url


Premium API. Get a special URL for files larger than 32 MB.

Base Command

gti-file-scan-upload-url

Input

There are no input arguments for this command.

Context Output

Path Type Description
GoogleThreatIntelligence.FileUploadURL unknown The special upload URL for large files.

Command Example


#### Context Example

```json
{
    "GoogleThreatIntelligence": {
        "FileUploadURL": "https://www.virustotal.com/_ah/upload/**upload-hash**"
    },
    "gtiUploadURL": "https://www.virustotal.com/_ah/upload/**upload-hash**"
}

Human Readable Output

New upload url acquired

Upload url
https://www.virustotal.com/_ah/upload/**upload-hash**/

gti-comments-delete


Delete a comment.

Base Command

gti-comments-delete

Input

Argument Name Description Required
id Comment ID. Required

Context Output

There is no context output for this command.

Command Example

!gti-comments-delete id=d-paloaltonetworks.com-7886a33c

Human Readable Output

Comment d-paloaltonetworks.com-7886a33c has been deleted!

gti-comments-get


Retrieves comments for a given resource.

Base Command

gti-comments-get

Input

Argument Name Description Required
resource The file hash (MD5, SHA1, orSHA256), Domain, URL or IP on which you’re commenting on. If not supplied, will try to determine if it’s a hash or a url. Required
resource_type The type of the resource on which you’re commenting. If not supplied, will determine if it’s a url or a file. Possible values are: ip, url, domain, file. Optional
limit Maximum comments to fetch. Default is 10. Optional
before Fetch only comments before the given time. Optional

Context Output

Path Type Description
GoogleThreatIntelligence.Comments.id String ID that contains the comment (the given hash, domain, url, or ip).
GoogleThreatIntelligence.Comments.comments.attributes.date Number The date of the comment in epoch format.
GoogleThreatIntelligence.Comments.comments.attributes.text String The text of the comment.
GoogleThreatIntelligence.Comments.comments.attributes.votes.positive Number Number of positive votes.
GoogleThreatIntelligence.Comments.comments.attributes.votes.abuse Number Number of abuse votes.
GoogleThreatIntelligence.Comments.comments.attributes.votes.negative Number Number of negative votes.
GoogleThreatIntelligence.Comments.comments.attributes.html String The HTML content.
GoogleThreatIntelligence.Comments.comments.type String The type of the comment.
GoogleThreatIntelligence.Comments.comments.id String ID of the commented.
GoogleThreatIntelligence.Comments.comments.links.self String Link to the request

Command Example

!gti-comments-get resource=https://paloaltonetworks.com

Context Example

{
    "GoogleThreatIntelligence": {
        "Comments": {
            "comments": [
                {
                    "attributes": {
                        "date": 1616325673,
                        "html": "another comment",
                        "tags": [],
                        "text": "another comment",
                        "votes": {
                            "abuse": 0,
                            "negative": 0,
                            "positive": 0
                        }
                    },
                    "id": "u-c5fad1f7084153e328563fbacdb07a9ad6428dc3f0a88e756266efb7c0553d9d-fe2d6a9e",
                    "links": {
                        "self": "https://www.virustotal.com/api/v3/comments/u-c5fad1f7084153e328563fbacdb07a9ad6428dc3f0a88e756266efb7c0553d9d-fe2d6a9e"
                    },
                    "type": "comment"
                },
                {
                    "attributes": {
                        "date": 1616325673,
                        "html": "another comment",
                        "tags": [],
                        "text": "another comment",
                        "votes": {
                            "abuse": 0,
                            "negative": 0,
                            "positive": 0
                        }
                    },
                    "id": "u-c5fad1f7084153e328563fbacdb07a9ad6428dc3f0a88e756266efb7c0553d9d-d63782a9",
                    "links": {
                        "self": "https://www.virustotal.com/api/v3/comments/u-c5fad1f7084153e328563fbacdb07a9ad6428dc3f0a88e756266efb7c0553d9d-d63782a9"
                    },
                    "type": "comment"
                },
                {
                    "attributes": {
                        "date": 1616313101,
                        "html": "a new comment",
                        "tags": [],
                        "text": "a new comment",
                        "votes": {
                            "abuse": 0,
                            "negative": 0,
                            "positive": 0
                        }
                    },
                    "id": "u-c5fad1f7084153e328563fbacdb07a9ad6428dc3f0a88e756266efb7c0553d9d-97a331a3",
                    "links": {
                        "self": "https://www.virustotal.com/api/v3/comments/u-c5fad1f7084153e328563fbacdb07a9ad6428dc3f0a88e756266efb7c0553d9d-97a331a3"
                    },
                    "type": "comment"
                },
                {
                    "attributes": {
                        "date": 1616313067,
                        "html": "a comment",
                        "tags": [],
                        "text": "a comment",
                        "votes": {
                            "abuse": 0,
                            "negative": 0,
                            "positive": 0
                        }
                    },
                    "id": "u-c5fad1f7084153e328563fbacdb07a9ad6428dc3f0a88e756266efb7c0553d9d-ae0de9fc",
                    "links": {
                        "self": "https://www.virustotal.com/api/v3/comments/u-c5fad1f7084153e328563fbacdb07a9ad6428dc3f0a88e756266efb7c0553d9d-ae0de9fc"
                    },
                    "type": "comment"
                }
            ],
            "indicator": "https://paloaltonetworks.com"
        }
    }
}

Human Readable Output

GoogleThreatIntelligence comments of url: “https://paloaltonetworks.com”

Date Text Positive Votes Abuse Votes Negative Votes
2021-03-21 11:21:13Z another comment 0 0 0
2021-03-21 11:21:13Z another comment 0 0 0
2021-03-21 07:51:41Z a new comment 0 0 0
2021-03-21 07:51:07Z a comment 0 0 0

gti-comments-get-by-id


Retrieves a comment by comment ID.

Base Command

gti-comments-get-by-id

Input

Argument Name Description Required
id The comment’s ID. Can be retrieved using the gti-comments-get command. Required

Context Output

Path Type Description
GoogleThreatIntelligence.Comments.comments.id String ID of the comment.
GoogleThreatIntelligence.Comments.comments.attributes.date Number The date of the comment in epoch format.
GoogleThreatIntelligence.Comments.comments.attributes.text String The text of the comment.
GoogleThreatIntelligence.Comments.comments.attributes.votes.positive Number Number of positive votes.
GoogleThreatIntelligence.Comments.comments.attributes.votes.abuse Number Number of abuse votes.
GoogleThreatIntelligence.Comments.comments.attributes.votes.negative Number Number of negative votes.
GoogleThreatIntelligence.Comments.comments.attributes.html String The HTML content.
GoogleThreatIntelligence.Comments.comments.type String The type of the comment.
GoogleThreatIntelligence.Comments.comments.links.self String Link to the request.

Command Example

!gti-comments-get-by-id id=d-paloaltonetworks.com-64591897

Context Example

{
    "GoogleThreatIntelligence": {
        "Comments": {
            "comments": {
                "attributes": {
                    "date": 1615195751,
                    "html": "a new comment!",
                    "tags": [],
                    "text": "a new comment!",
                    "votes": {
                        "abuse": 0,
                        "negative": 0,
                        "positive": 0
                    }
                },
                "id": "d-paloaltonetworks.com-64591897",
                "links": {
                    "self": "https://www.virustotal.com/api/v3/comments/d-paloaltonetworks.com-64591897"
                },
                "type": "comment"
            }
        }
    }
}

Human Readable Output

Comment of ID d-paloaltonetworks.com-64591897

Date Text Positive Votes Abuse Votes Negative Votes
2021-03-08 09:29:11Z a new comment! 0 0 0

gti-search


Search for an indicator in GoogleThreatIntelligence.

Base Command

gti-search

Input

Argument Name Description Required
query This endpoint searches any of the following: A file hash, URL, domain, IP address, tag comments. Required
extended_data Whether to return extended data (last_analysis_results). Possible values are: true, false. Optional
limit Maximum number of results to fetch. Default is 10. Optional

Context Output

Path Type Description
GoogleThreatIntelligence.SearchResults.attributes.last_analysis_stats.harmless Number Number of engines that found the indicator to be harmless.
GoogleThreatIntelligence.SearchResults.attributes.last_analysis_stats.malicious Number Number of engines that found the indicator to be malicious.
GoogleThreatIntelligence.SearchResults.attributes.last_analysis_stats.suspicious Number Number of engines that found the indicator to be suspicious.
GoogleThreatIntelligence.SearchResults.attributes.last_analysis_stats.undetected Number Number of engines that could not detect the indicator.
GoogleThreatIntelligence.SearchResults.attributes.last_analysis_stats.timeout Number Number of engines that timed out.
GoogleThreatIntelligence.SearchResults.attributes.reputation Number The indicator’s reputation
GoogleThreatIntelligence.SearchResults.attributes.last_modification_date Number The last modification date in epoch format.
GoogleThreatIntelligence.SearchResults.attributes.total_votes.harmless Number Total number of harmless votes.
GoogleThreatIntelligence.SearchResults.attributes.total_votes.malicious Number Total number of malicious votes.
GoogleThreatIntelligence.SearchResults.type String The type of the indicator (ip, domain, url, file).
GoogleThreatIntelligence.SearchResults.id String ID of the indicator.
GoogleThreatIntelligence.SearchResults.links.self String Link to the response.

Command Example

!gti-search query=paloaltonetworks.com

Context Example

{
    "GoogleThreatIntelligence": {
        "SearchResults": {
            "attributes": {
                "categories": {
                    "BitDefender": "marketing",
                    "Forcepoint ThreatSeeker": "information technology",
                    "alphaMountain.ai": "Business/Economy, Information Technology",
                    "sophos": "information technology"
                },
                "creation_date": 1108953730,
                "favicon": {
                    "dhash": "02e9ecb69ac869a8",
                    "raw_md5": "920c3c89139c32d356fa4b8b61616f37"
                },
                "jarm": "29d3fd00029d29d00042d43d00041d598ac0c1012db967bb1ad0ff2491b3ae",
                "last_analysis_stats": {
                    "harmless": 75,
                    "malicious": 0,
                    "suspicious": 0,
                    "timeout": 0,
                    "undetected": 7
                },
                "last_dns_records": [
                    {
                        "ttl": 14399,
                        "type": "TXT",
                        "value": "atlassian-domain-verification=WeW32v7AwYQEviMzlNjYyXNMUngcnmIMtNZKJ69TuQUoda5T6DFFV/A6rRvOzwvs"
                    }
],
                "last_dns_records_date": 1616986415,
                "last_https_certificate": {
                    "cert_signature": {
                        "signature": "signature",
                        "signature_algorithm": "sha256RSA"
                    },
                    "extensions": {
                        "**exten**": "0482016a0168007600a4b90990b418581487bb13a2cc67700a3c359804f91bdf",
                        "CA": true,
                        "authority_key_identifier": {
                            "keyid": "40c2bd278ecc348330a233d7fb6cb3f0b42c80ce"
                        },
                        "ca_information_access": {
                            "CA Issuers": "http://certificates.example.com/repository/gdig2.crt",
                            "OCSP": "http://ocsp.example.com/"
                        },
                        "certificate_policies": [
                            "**policy**"
                        ],
                        "crl_distribution_points": [
                            "http://example.com/gdig2s1-1677.crl"
                        ],
                        "extended_key_usage": [
                            "serverAuth",
                            "clientAuth"
                        ],
                        "key_usage": [
                            "ff"
                        ],
                        "subject_alternative_name": [
                            "www.paloaltonetworks.com"
                        ],
                        "subject_key_identifier": "ed89d4b918aab2968bd1dfde421a179c51445be0",
                        "tags": []
                    },
                    "issuer": {
                        "C": "US",
                        "CN": "Go Daddy Secure Certificate Authority - G2",
                        "L": "Scottsdale",
                        "O": "example.com, Inc.",
                        "OU": "http://certs.example.com/repository/",
                        "ST": "Arizona"
                    },
                    "public_key": {
                        "algorithm": "RSA",
                        "rsa": {
                            "exponent": "010001",
                            "key_size": 2048,
                            "modulus": "modulus"
                        }
                    },
                    "serial_number": "f5fa379466d9884a",
                    "signature_algorithm": "sha256RSA",
                    "size": 1963,
                    "subject": {
                        "CN": "www.paloaltonetworks.com",
                        "OU": "Domain Control Validated"
                    },
                    "tags": [],
                    "thumbprint": "0296c20e3a4a607b8d9e2af86155cde04594535e",
                    "thumbprint_sha256": "17bb7bda507abc602bdf1b160d7f51edaccac39fd34f8dab1e793c3612cfc8c2",
                    "validity": {
                        "not_after": "2022-01-27 16:52:24",
                        "not_before": "2020-01-27 16:52:24"
                    },
                    "version": "V3"
                },
                "last_https_certificate_date": 1616986415,
                "last_modification_date": 1617084294,
                "last_update_date": 1594825871,
                "popularity_ranks": {
                    "Alexa": {
                        "rank": 32577,
                        "timestamp": 1617032161
                    }
                },
                "registrar": "MarkMonitor Inc.",
                "reputation": 0,
                "tags": [],
                "total_votes": {
                    "harmless": 0,
                    "malicious": 0
                },
                "whois": "whois string",
                "whois_date": 1615321176
            },
            "id": "paloaltonetworks.com",
            "links": {
                "self": "https://www.virustotal.com/api/v3/domains/paloaltonetworks.com"
            },
            "type": "domain"
        }
    }
}

Human Readable Output

Search result of query paloaltonetworks.com

Categories CreationDate LastAnalysisStats    
Forcepoint ThreatSeeker: information technology
sophos: information technology
BitDefender: marketing
alphaMountain.ai: Business/Economy, Information Technology
1108953730 harmless: 75
malicious: 0
suspicious: 0
undetected: 7
timeout: 0
  1615321176

gti-file-sandbox-report


Retrieves a behavioral relationship of the given file hash.

Base Command

gti-file-sandbox-report

Input

Argument Name Description Required
file Hash of the file to query. Supports MD5, SHA1, and SHA256. Required
limit Maximum number of results to fetch. Default is 10. Optional

Context Output

Path Type Description
SandboxReport.attributes.analysis_date Number The date of the analysis in epoch format.
SandboxReport.attributes.behash String Behash of the attribute.
SandboxReport.attributes.command_executions String Which command were executed.
SandboxReport.attributes.dns_lookups.hostname String Host names found in the lookup.
SandboxReport.attributes.dns_lookups.resolved_ips String The IPs that were resolved.
SandboxReport.attributes.files_attribute_changed String The file attributes that were changed.
SandboxReport.attributes.has_html_report Boolean Whether there is an HTML report.
SandboxReport.attributes.has_pcap Boolean Whether the IP has a PCAP file.
SandboxReport.attributes.http_conversations.request_method String The request method of the HTTP conversation.
SandboxReport.attributes.http_conversations.response_headers.Cache-Control String The cache-control method of the response header.
SandboxReport.attributes.http_conversations.response_headers.Connection String The connection of the response header.
SandboxReport.attributes.http_conversations.response_headers.Content-Length String THe Content-Length of the response header.
SandboxReport.attributes.http_conversations.response_headers.Content-Type String The Content-Type of the response header.
SandboxReport.attributes.http_conversations.response_headers.Pragma String The pragma of the response header.
SandboxReport.attributes.http_conversations.response_headers.Server String The server of the response header.
SandboxReport.attributes.http_conversations.response_headers.Status-Line String The Status-Line of the response header.
SandboxReport.attributes.http_conversations.response_status_code Number The response status code.
SandboxReport.attributes.http_conversations.url String The conversation URL.
SandboxReport.attributes.last_modification_date Number Last modified data in epoch format.
SandboxReport.attributes.modules_loaded String Loaded modules.
SandboxReport.attributes.mutexes_created String The mutexes that were created.
SandboxReport.attributes.mutexes_opened String The mutexes that were opened.
SandboxReport.attributes.processes_created String The processes that were created.
SandboxReport.attributes.processes_tree.name String The name of the process tree.
SandboxReport.attributes.processes_tree.process_id String The ID of the process.
SandboxReport.attributes.registry_keys_deleted String Deleted registry keys.
SandboxReport.attributes.registry_keys_set.key String Key of the registry key.
SandboxReport.attributes.registry_keys_set.value String Value of the registry key.
SandboxReport.attributes.sandbox_name String The name of the sandbox.
SandboxReport.attributes.services_started String The services that were started.
SandboxReport.attributes.verdicts String The verdicts.
SandboxReport.id String The IP analyzed.
SandboxReport.links.self String Link to the response.
SandboxReport.attributes.files_dropped.path String Path of the file dropped.
SandboxReport.attributes.files_dropped.sha256 String SHA-256 hash of the dropped files.
SandboxReport.attributes.files_opened String The files that were opened.
SandboxReport.attributes.files_written String The files that were written.
SandboxReport.attributes.ip_traffic.destination_ip String Destination IP in the traffic.
SandboxReport.attributes.ip_traffic.destination_port Number Destination port in the traffic.
SandboxReport.attributes.ip_traffic.transport_layer_protocol String Transport layer protocol in the traffic.
SandboxReport.attributes.registry_keys_opened String The registry keys that were opened.
SandboxReport.attributes.tags String The tags of the DNS data.
SandboxReport.attributes.files_copied.destination String Destination of the files copied.
SandboxReport.attributes.files_copied.source String Source of the files copied.
SandboxReport.attributes.permissions_requested String The permissions that where requested.
SandboxReport.attributes.processes_injected String The processes that were injected.
SandboxReport.attributes.processes_terminated String The processes that were terminated.
SandboxReport.attributes.processes_tree.children.name String The name of the children of the process.
SandboxReport.attributes.processes_tree.children.process_id String The ID of the children of the process.
SandboxReport.attributes.services_opened String The services that were opened.
SandboxReport.attributes.text_highlighted String The text that was highlighted.
SandboxReport.attributes.calls_highlighted String The calls that were highlighted.
SandboxReport.attributes.processes_tree.children.time_offset Number The time offset of the children in the process.
SandboxReport.links.self String The link to the response.
SandboxReport.meta.count Number The number of objects that were found in the attributes.

Command Example

!gti-file-sandbox-report file=2b294b3499d1cce794badffc959b7618

Context Example

{
    "GoogleThreatIntelligence": {
        "SandboxReport": [
            {
                "attributes": {
                    "analysis_date": 1558429832,
                    "behash": "079386becc949a2aafdcd2c6042cf0a9",
                    "command_executions": [
                        "C:\\DOCUME~1\\Miller\\LOCALS~1\\Temp\\Win32.AgentTesla.exe",
                    ],
                    "dns_lookups": [
                        {
                            "hostname": "checkip.dyndns.org",
                            "resolved_ips": [
                                "**ip**"
                            ]
                        },
                        {
                            "hostname": "checkip.dyndns.org",
                            "resolved_ips": [
                                "**ip**"
                            ]
                        }
                    ],
                    "files_attribute_changed": [
                        "C:\\Documents and Settings\\Miller\\Local Settings\\Temp\\xws\\xws.exe"
                    ],
                    "has_html_report": false,
                    "has_pcap": false,
                    "http_conversations": [
                        {
                            "request_method": "GET",
                            "response_headers": {
                                "Cache-Control": "no-cache",
                                "Connection": "close",
                                "Content-Length": "107",
                                "Content-Type": "text/html",
                                "Pragma": "no-cache",
                                "Server": "DynDNS-CheckIP/1.0.1",
                                "Status-Line": "HTTP/1.1 200"
                            },
                            "response_status_code": 200,
                            "url": "http://checkip.dyndns.org/"
                        },
                        {
                            "request_method": "GET",
                            "response_headers": {
                                "Cache-Control": "no-cache",
                                "Connection": "close",
                                "Content-Length": "105",
                                "Content-Type": "text/html",
                                "Pragma": "no-cache",
                                "Server": "DynDNS-CheckIP/1.0.1",
                                "Status-Line": "HTTP/1.1 200"
                            },
                            "response_status_code": 200,
                            "url": "http://checkip.dyndns.org/"
                        }
                    ],
                    "last_modification_date": 1588377117,
                    "modules_loaded": [
                        "c:\\windows\\system32\\imm32.dll"
                    ],
                    "mutexes_created": [
                        "CTF.Compart.MutexDefaultS-1-5-21-1229272821-1563985344-1801674531-1003"
                    ],
                    "mutexes_opened": [
                        "ShimCacheMutex"
                    ],
                    "processes_created": [
                        "C:\\DOCUME~1\\Miller\\LOCALS~1\\Temp\\Win32.AgentTesla.exe"
                    ],
                    "processes_tree": [
                        {
                            "name": "C:\\DOCUME~1\\Miller\\LOCALS~1\\Temp\\Win32.AgentTesla.exe",
                            "process_id": "272"
                        }
                    ],
                    "registry_keys_deleted": [
                        "HKU\\S-1-5-21-3712457824-2419000099-45725732-1005\\SOFTWARE\\CLASSES\\MSCFILE\\SHELL\\OPEN\\COMMAND"
                    ],
                    "registry_keys_set": [
                        {
                            "key": "HKU\\S-1-5-21-1229272821-1563985344-1801674531-1003\\SOFTWARE\\MICROSOFT\\WINDOWS\\CURRENTVERSION\\RUN",
                            "value": "xws"
                        }
                    ],
                    "sandbox_name": "Lastline",
                    "services_started": [
                        "RASMAN",
                        "WinHttpAutoProxySvc"
                    ],
                    "verdicts": [
                        "MALWARE",
                        "TROJAN"
                    ]
                },
                "id": "699ec052ecc898bdbdafea0027c4ab44c3d01ae011c17745dd2b7fbddaa077f3_Lastline",
                "links": {
                    "self": "https://www.virustotal.com/api/v3/file_behaviours/699ec052ecc898bdbdafea0027c4ab44c3d01ae011c17745dd2b7fbddaa077f3_Lastline"
                },
                "type": "file_behaviour"
            },
            {
                "attributes": {
                    "analysis_date": 1561405459,
                    "files_dropped": [
                        {
                            "path": "\\Users\\Petra\\AppData\\Local\\Temp\\xws\\xws.exe",
                            "sha256": "699ec052ecc898bdbdafea0027c4ab44c3d01ae011c17745dd2b7fbddaa077f3"
                        }
                    ],
                    "files_opened": [
                        "C:\\Windows\\Microsoft.NET\\Framework\\v4.0.30319\\config\\machine.config"
                    ],
                    "files_written": [
                        "C:\\Users\\<USER>\\AppData\\Local\\Temp\\xws\\xws.exe"
                    ],
                    "has_html_report": false,
                    "has_pcap": false,
                    "ip_traffic": [
                        {
                            "destination_ip": "**ip**",
                            "destination_port": 80,
                            "transport_layer_protocol": "TCP"
                        }
                    ],
                    "last_modification_date": 1563272815,
                    "processes_tree": [
                        {
                            "name": "1526312897-2b294b349.pe32",
                            "process_id": "2624"
                        }
                    ],
                    "registry_keys_opened": [
                        "\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\OLE",
                    ],
                    "registry_keys_set": [
                        {
                            "key": "\\REGISTRY\\USER\\S-1-5-21-1119815420-2032815650-2779196966-1000\\Software\\Microsoft\\Windows\\CurrentVersion\\Run",
                            "value": "xws"
                        }
                    ],
                    "sandbox_name": "SNDBOX",
                    "tags": [
                        "PERSISTENCE"
                    ]
                },
                "id": "699ec052ecc898bdbdafea0027c4ab44c3d01ae011c17745dd2b7fbddaa077f3_SNDBOX",
                "links": {
                    "self": "https://www.virustotal.com/api/v3/file_behaviours/699ec052ecc898bdbdafea0027c4ab44c3d01ae011c17745dd2b7fbddaa077f3_SNDBOX"
                },
                "type": "file_behaviour"
            },
            {
                "attributes": {
                    "analysis_date": 1601545446,
                    "behash": "7617055bb3994dea99c19877fd7ec55a",
                    "command_executions": [
                        "\"C:\\Documents and Settings\\Administrator\\Local Settings\\Temp\\EB93A6\\996E.exe\"",
                        "Shutdown -r -t 5"
                    ],
                    "dns_lookups": [
                        {
                            "hostname": "checkip.dyndns.org"
                        }
                    ],
                    "files_copied": [
                        {
                            "destination": "C:\\Documents and Settings\\Administrator\\Local Settings\\Temp\\xws\\xws.exe ",
                            "source": "C:\\Documents and Settings\\Administrator\\Local Settings\\Temp\\EB93A6\\996E.exe "
                        }
                    ],
                    "files_opened": [
                        "C:\\WINDOWS\\system32\\winime32.dll"
                    ],
                    "files_written": [
                        "C:\\Documents and Settings\\Administrator\\Local Settings\\Temp\\xws\\xws.exe",
                        "C:\\Documents and Settings\\Administrator\\Local Settings\\Temp\\Ktx.exe"
                    ],
                    "has_html_report": true,
                    "has_pcap": false,
                    "last_modification_date": 1601545448,
                    "modules_loaded": [
                        "ADVAPI32.dll"
                    ],
                    "mutexes_created": [
                        "CTF.LBES.MutexDefaultS-1-5-21-1482476501-1645522239-1417001333-500",

                    ],
                    "mutexes_opened": [
                        "ShimCacheMutex"
                    ],
                    "permissions_requested": [
                        "SE_DEBUG_PRIVILEGE"
                    ],
                    "processes_created": [
                        "C:\\Documents and Settings\\Administrator\\Local Settings\\Temp\\EB93A6\\996E.exe"
                    ],
                    "processes_injected": [
                        "C:\\Documents and Settings\\Administrator\\Local Settings\\Temp\\EB93A6\\996E.exe"
                    ],
                    "processes_terminated": [
                        "C:\\Documents and Settings\\Administrator\\Local Settings\\Temp\\EB93A6\\996E.exe"
                    ],
                    "processes_tree": [
                        {
                            "children": [
                                {
                                    "children": [
                                        {
                                            "name": "shutdown.exe",
                                            "process_id": "2336"
                                        }
                                    ],
                                    "name": "****.exe",
                                    "process_id": "1024"
                                }
                            ],
                            "name": "****.exe",
                            "process_id": "628"
                        }
                    ],
                    "registry_keys_opened": [
                        "\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\996E.exe"
                    ],
                    "registry_keys_set": [
                        {
                            "key": "HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run\\xws",
                            "value": "C:\\Users\\<USER>\\AppData\\Local\\Temp\\xws\\xws.exe"
                        }
                    ],
                    "sandbox_name": "GoogleThreatIntelligence Jujubox",
                    "tags": [
                        "DIRECT_CPU_CLOCK_ACCESS"
                    ],
                    "text_highlighted": [
                        "C:\\Windows\\system32\\cmd.exe"
                    ]
                },
                "id": "699ec052ecc898bdbdafea0027c4ab44c3d01ae011c17745dd2b7fbddaa077f3_GoogleThreatIntelligence Jujubox",
                "links": {
                    "self": "https://www.virustotal.com/api/v3/file_behaviours/699ec052ecc898bdbdafea0027c4ab44c3d01ae011c17745dd2b7fbddaa077f3_GoogleThreatIntelligence Jujubox"
                },
                "type": "file_behaviour"
            }
        ]
    }
}

Human Readable Output

Sandbox Reports for file hash: 2b294b3499d1cce794badffc959b7618

AnalysisDate LastModificationDate SandboxName Link
1558429832 1588377117 Lastline https://www.virustotal.com/api/v3/file_behaviours/699ec052ecc898bdbdafea0027c4ab44c3d01ae011c17745dd2b7fbddaa077f3_Lastline
1561405459 1563272815 SNDBOX https://www.virustotal.com/api/v3/file_behaviours/699ec052ecc898bdbdafea0027c4ab44c3d01ae011c17745dd2b7fbddaa077f3_SNDBOX
1601545446 1601545448 Tencent HABO https://www.virustotal.com/api/v3/file_behaviours/699ec052ecc898bdbdafea0027c4ab44c3d01ae011c17745dd2b7fbddaa077f3_Tencent HABO
1592373137 1592373137 GoogleThreatIntelligence Jujubox https://www.virustotal.com/api/v3/file_behaviours/699ec052ecc898bdbdafea0027c4ab44c3d01ae011c17745dd2b7fbddaa077f3_GoogleThreatIntelligence Jujubox

gti-passive-dns-data


Returns passive DNS records by indicator.

Base Command

gti-passive-dns-data

Input

Argument Name Description Required
id IP or domain for which to get its DNS data. Optional
ip IP for which to get its DNS data. Optional
domain Domain for which to get its DNS data. Optional
limit Maximum number of results to fetch. Default is 10. Optional

Context Output

Path Type Description
GoogleThreatIntelligence.PassiveDNS.attributes.date Number Date of the DNS analysis in epoch format.
GoogleThreatIntelligence.PassiveDNS.attributes.host_name String The DNS host name.
GoogleThreatIntelligence.PassiveDNS.attributes.ip_address String The DNS IP address.
GoogleThreatIntelligence.PassiveDNS.attributes.resolver String The name of the resolver.
GoogleThreatIntelligence.PassiveDNS.id String The ID of the resolution.
GoogleThreatIntelligence.PassiveDNS.links.self String The link to the resolution.
GoogleThreatIntelligence.PassiveDNS.type String The type of the resolution.

Command Example

!gti-passive-dns-data ip=1.1.1.1

Context Example

{
    "GoogleThreatIntelligence": {
        "PassiveDNS": [
            {
                "attributes": {
                    "date": 1617085962,
                    "host_name": "muhaha.xyz",
                    "ip_address": "1.1.1.1",
                    "resolver": "GoogleThreatIntelligence"
                },
                "id": "1.1.1.1muhaha.xyz",
                "links": {
                    "self": "https://www.virustotal.com/api/v3/resolutions/1.1.1.1muhaha.xyz"
                },
                "type": "resolution"
            }
        ]
    }
}

Human Readable Output

Passive DNS data for IP 1.1.1.1

Id Date HostName IpAddress Resolver
1.1.1.1muhaha.xyz 1617085962 muhaha.xyz 1.1.1.1 GoogleThreatIntelligence

gti-analysis-get


Retrieves resolutions of the given IP.

Base Command

gti-analysis-get

Input

Argument Name Description Required
id ID of the analysis (from file-scan, file-rescan, or url-scan). Required
extended_data Whether to return extended data (last_analysis_results). Optional

Context Output

Path Type Description
GoogleThreatIntelligence.Analysis.data.attributes.date Number Date of the analysis in epoch format.
GoogleThreatIntelligence.Analysis.data.attributes.stats.harmless Number Number of engines that found the indicator to be harmless.
GoogleThreatIntelligence.Analysis.data.attributes.stats.malicious Number Number of engines that found the indicator to be malicious.
GoogleThreatIntelligence.Analysis.data.attributes.stats.suspicious Number Number of engines that found the indicator to be suspicious.
GoogleThreatIntelligence.Analysis.data.attributes.stats.timeout Number he number of engines that timed out for the indicator.
GoogleThreatIntelligence.Analysis.data.attributes.stats.undetected Number Number of engines the found the indicator to be undetected.
GoogleThreatIntelligence.Analysis.data.attributes.status String Status of the analysis.
GoogleThreatIntelligence.Analysis.data.id String ID of the analysis.
GoogleThreatIntelligence.Analysis.data.type String Type of object (analysis).
GoogleThreatIntelligence.Analysis.meta.file_info.sha256 String SHA-256 hash of the file (if it is a file).
GoogleThreatIntelligence.Analysis.meta.file_info.sha1 String SHA-1 hash of the file (if it is a file).
GoogleThreatIntelligence.Analysis.meta.file_info.md5 String MD5 hash of the file (if it is a file).
GoogleThreatIntelligence.Analysis.meta.file_info.name unknown Name of the file (if it is a file).
GoogleThreatIntelligence.Analysis.meta.file_info.size String Size of the file (if it is a file).
GoogleThreatIntelligence.Analysis.meta.url_info.id String ID of the url (if it is a URL).
GoogleThreatIntelligence.Analysis.meta.url_info.url String The URL (if it is a URL).
GoogleThreatIntelligence.Analysis.id String The analysis ID.

Command Example

!gti-analysis-get id=u-20694f234fbac92b1dcc16f424aa1c85e9dd7af75b360745df6484dcae410853-1613980758

Context Example

{
    "GoogleThreatIntelligence": {
        "Analysis": {
            "data": {
                "attributes": {
                    "date": 1613980758,
                    "results": {
                        "ADMINUSLabs": {
                            "category": "harmless",
                            "engine_name": "ADMINUSLabs",
                            "method": "blacklist",
                            "result": "clean"
                        }
                    },
                    "stats": {
                        "harmless": 69,
                        "malicious": 7,
                        "suspicious": 0,
                        "timeout": 0,
                        "undetected": 7
                    },
                    "status": "completed"
                },
                "id": "u-20694f234fbac92b1dcc16f424aa1c85e9dd7af75b360745df6484dcae410853-1613980758",
                "links": {
                    "self": "https://www.virustotal.com/api/v3/analyses/u-20694f234fbac92b1dcc16f424aa1c85e9dd7af75b360745df6484dcae410853-1613980758"
                },
                "type": "analysis"
            },
            "id": "u-20694f234fbac92b1dcc16f424aa1c85e9dd7af75b360745df6484dcae410853-1613980758",
            "meta": {
                "url_info": {
                    "id": "20694f234fbac92b1dcc16f424aa1c85e9dd7af75b360745df6484dcae410853"
                }
            }
        }
    }
}

Human Readable Output

Analysis results

Id Stats Status
u-20694f234fbac92b1dcc16f424aa1c85e9dd7af75b360745df6484dcae410853-1613980758 harmless: 69
malicious: 7
suspicious: 0
undetected: 7
timeout: 0
completed

gti-file-sigma-analysis


Retrieves result of the last Sigma analysis.

Base Command

gti-file-sigma-analysis

Input

Argument Name Description Required
file File hash (md5, sha1, sha256). Required
only_stats Print only Sigma analysis summary stats. Optional

Context Output

Path Type Description
GoogleThreatIntelligence.SigmaAnalysis.data.attributes.last_modification_date Number Date of the last update in epoch format.
GoogleThreatIntelligence.SigmaAnalysis.data.attributes.analysis_date Number Date of the last update in epoch format.
GoogleThreatIntelligence.SigmaAnalysis.data.attributes.stats.rule_matches.match_context String Matched strings from the log file.
GoogleThreatIntelligence.SigmaAnalysis.data.attributes.stats.rule_matches.rule_author String Rule authors separated by commas.
GoogleThreatIntelligence.SigmaAnalysis.data.attributes.stats.rule_matches.rule_description String Brief summary about what the rule detects.
GoogleThreatIntelligence.SigmaAnalysis.data.attributes.stats.rule_matches.rule_id String Rule ID in GoogleThreatIntelligence’s database.
GoogleThreatIntelligence.SigmaAnalysis.data.attributes.stats.rule_matches.rule_level String Rule severity. Can be “low”, “medium”, “high” or “critical”.
GoogleThreatIntelligence.SigmaAnalysis.data.attributes.stats.rule_matches.rule_source String Ruleset where the rule belongs.
GoogleThreatIntelligence.SigmaAnalysis.data.attributes.stats.rule_matches.rule_title String Rule title.
GoogleThreatIntelligence.SigmaAnalysis.data.attributes.stats.severity_stats.critical Number Number of matched rules having a “critical” severity.
GoogleThreatIntelligence.SigmaAnalysis.data.attributes.stats.severity_stats.high Number Number of matched rules having a “high” severity.
GoogleThreatIntelligence.SigmaAnalysis.data.attributes.stats.severity_stats.low Number Number of matched rules having a “low” severity.
GoogleThreatIntelligence.SigmaAnalysis.data.attributes.stats.severity_stats.medium Number Number of matched rules having a “medium” severity.
GoogleThreatIntelligence.SigmaAnalysis.data.attributes.stats.source_severity_stats unknown Same as severity_stats but grouping stats by ruleset. Keys are ruleset names as string and values are stats in a dictionary.
GoogleThreatIntelligence.SigmaAnalysis.data.id String ID of the analysis.

Command Example

!gti-file-sigma-analysis file=f912398cb3542ab704fe917af4a60d4feee21ac577535b10453170f10c6fd6de

Context Example

{
    "GoogleThreatIntelligence": {
        "SigmaAnalysis": {
            "meta": {
                "count": 1
            },
            "data": {
                "attributes": {
                    "last_modification_date": 1650970667,
                    "analysis_date": 1650968852,
                    "rule_matches": [
                        {
                            "match_context": "$EventID: '1117'",
                            "rule_level": "high",
                            "rule_description": "Detects all actions taken by Windows Defender malware detection engines",
                            "rule_source": "Sigma Integrated Rule Set (GitHub)",
                            "rule_title": "Windows Defender Threat Detected",
                            "rule_id": "cf90b923dcb2c8192e6651425886607684aac6680bf25b20c39ae3f8743aebf1",
                            "rule_author": "Ján Trenčanský"
                        },
                        {
                            "match_context": "$EventID: '2002'",
                            "rule_level": "low",
                            "rule_description": "Setting have been change in Windows Firewall",
                            "rule_source": "Sigma Integrated Rule Set (GitHub)",
                            "rule_title": "Setting Change in Windows Firewall with Advanced Security",
                            "rule_id": "693c36f61ac022fd66354b440464f490058c22b984ba1bef05ca246aba210ed1",
                            "rule_author": "frack113"
                        }
                    ],
                    "source_severity_stats": {
                        "Sigma Integrated Rule Set (GitHub)": {
                            "high": 1,
                            "medium": 0,
                            "critical": 0,
                            "low": 1
                        },
                    },
                    "severity_stats": {
                        "high": 1,
                        "medium": 0,
                        "critical": 0,
                        "low": 1
                    }
                },
                "type": "sigma_analysis",
                "id": "f912398cb3542ab704fe917af4a60d4feee21ac577535b10453170f10c6fd6de",
                "links": {
                    "self": "https://www.virustotal.com/api/v3/sigma_analyses/f912398cb3542ab704fe917af4a60d4feee21ac577535b10453170f10c6fd6de"
                }
            },
            "links": {
                "self": "https://www.virustotal.com/api/v3/files/f912398cb3542ab704fe917af4a60d4feee21ac577535b10453170f10c6fd6de/sigma_analysis"
            }
        }
    }
}

Human Readable Output

Last Sigma analysis results

MatchContext RuleLevel RuleDescription RuleSource RuleTitle RuleId RuleAuthor
$EventID: ‘1117’ high Detects all actions taken by Windows Defender malware detection engines Sigma Integrated Rule Set (GitHub) Windows Defender Threat Detected 693c36f61ac022fd66354b440464f490058c22b984ba1bef05ca246aba210ed1 Ján Trenčanský

gti-privatescanning-file


Checks the file reputation of the specified private hash.

See files through the eyes of GoogleThreatIntelligence without uploading them to the main threat corpus, keeping them entirely private. Static, dynamic, network and similarity analysis included, as well as automated threat intel enrichment, but NOT multi-antivirus analysis.

Base Command

gti-privatescanning-file

Input

Argument Name Description Required
file File hash (md5, sha1, sha256). Required

Context Output

Path Type Description
GoogleThreatIntelligence.File.attributes.type_description String Description of the type of the file.
GoogleThreatIntelligence.File.attributes.tlsh String The locality-sensitive hashing.
GoogleThreatIntelligence.File.attributes.exiftool.MIMEType String MIME type of the file.
GoogleThreatIntelligence.File.attributes.names String Names of the file.
GoogleThreatIntelligence.File.attributes.javascript_info.tags String Tags of the JavaScript.
GoogleThreatIntelligence.File.attributes.exiftool.FileType String The file type.
GoogleThreatIntelligence.File.attributes.exiftool.WordCount Number Total number of words in the file.
GoogleThreatIntelligence.File.attributes.exiftool.LineCount Number Total number of lines in file.
GoogleThreatIntelligence.File.attributes.exiftool.MIMEEncoding String The MIME encoding.
GoogleThreatIntelligence.File.attributes.exiftool.FileTypeExtension String The file type extension.
GoogleThreatIntelligence.File.attributes.exiftool.Newlines Number Number of newlines signs.
GoogleThreatIntelligence.File.attributes.crowdsourced_ids_stats.info Number Number of IDS that marked the file as “info”.
GoogleThreatIntelligence.File.attributes.crowdsourced_ids_stats.high Number Number of IDS that marked the file as “high”.
GoogleThreatIntelligence.File.attributes.crowdsourced_ids_stats.medium Number Number of IDS that marked the file as “medium”.
GoogleThreatIntelligence.File.attributes.crowdsourced_ids_stats.low Number Number of IDS that marked the file as “low”.
GoogleThreatIntelligence.File.attributes.trid.file_type String The TrID file type.
GoogleThreatIntelligence.File.attributes.trid.probability Number The TrID probability.
GoogleThreatIntelligence.File.attributes.crowdsourced_yara_results.description String Description of the YARA rule.
GoogleThreatIntelligence.File.attributes.crowdsourced_yara_results.source String Source of the YARA rule.
GoogleThreatIntelligence.File.attributes.crowdsourced_yara_results.author String Author of the YARA rule.
GoogleThreatIntelligence.File.attributes.crowdsourced_yara_results.ruleset_name String Rule set name of the YARA rule.
GoogleThreatIntelligence.File.attributes.crowdsourced_yara_results.rule_name String Name of the YARA rule.
GoogleThreatIntelligence.File.attributes.crowdsourced_yara_results.ruleset_id String ID of the YARA rule.
GoogleThreatIntelligence.File.attributes.names String Name of the file.
GoogleThreatIntelligence.File.attributes.type_tag String Tag of the type.
GoogleThreatIntelligence.File.attributes.size Number Size of the file.
GoogleThreatIntelligence.File.attributes.sha256 String SHA-256 hash of the file.
GoogleThreatIntelligence.File.attributes.type_extension String Extension of the type.
GoogleThreatIntelligence.File.attributes.tags String File tags.
GoogleThreatIntelligence.File.attributes.last_analysis_date Number Last analysis date in epoch format.
GoogleThreatIntelligence.File.attributes.ssdeep String SSDeep hash of the file.
GoogleThreatIntelligence.File.attributes.md5 String MD5 hash of the file.
GoogleThreatIntelligence.File.attributes.sha1 String SHA-1 hash of the file.
GoogleThreatIntelligence.File.attributes.magic String Identification of file by the magic number.
GoogleThreatIntelligence.File.attributes.meaningful_name String Meaningful name of the file.
GoogleThreatIntelligence.File.attributes.threat_severity.threat_severity_level String Threat severity level of the file.
GoogleThreatIntelligence.File.attributes.threat_severity.threat_severity_data.popular_threat_category String Popular threat category of the file.
GoogleThreatIntelligence.File.attributes.threat_verdict String Threat verdict of the file.
GoogleThreatIntelligence.File.type String Type of the file.
GoogleThreatIntelligence.File.id String ID of the file.
GoogleThreatIntelligence.File.links.self String Link to the response.

Command Example

!gti-privatescanning-file file=example-file-hash

Context Example

{
    "GoogleThreatIntelligence": {
        "File": {
            "attributes": {
                "type_description": "ELF",
                "tlsh": "Example tlsh",
                "vhash": "Example vhash",
                "exiftool": {
                    "MIMEType": "application/octet-stream",
                    "CPUByteOrder": "Little endian",
                    "ObjectFileType": "Executable file",
                    "CPUArchitecture": "32 bit",
                    "CPUType": "i386",
                    "FileType": "ELF executable"
                },
                "trid": [
                    {
                        "file_type": "ELF Executable and Linkable format (Linux)",
                        "probability": 55
                    },
                    {
                        "file_type": "ELF Executable and Linkable format (generic)",
                        "probability": 45
                    }
                ],
                "crowdsourced_yara_results": [
                    {
                        "description": "Detects a suspicious ELF binary with UPX compression",
                        "source": "https://www.example.com",
                        "author": "Author X",
                        "ruleset_name": "gen_elf_file_anomalies",
                        "rule_name": "SUSP_ELF_LNX_UPX_Compressed_File",
                        "ruleset_id": "0224a54ba7"
                    }
                ],
                "threat_severity": {
                    "threat_severity_level": "SEVERITY_HIGH",
                    "threat_severity_data": {
                        "has_dropped_files_with_detections": true,
                        "type_tag": "elf",
                        "has_execution_parents_with_detections": true,
                        "can_be_detonated": true,
                        "popular_threat_category": "trojan"
                    },
                    "last_analysis_date": "1681045097",
                    "version": 1
                },
                "names": [
                    "private",
                    "/usr/lib/sample.so",
                    "private_sample.bin",
                ],
                "owner": "virustotal",
                "type_tag": "elf",
                "elf_info": {
                    "header": {
                        "hdr_version": "1 (current)",
                        "type": "EXEC (Executable file)",
                        "obj_version": "0x1",
                        "data": "2's complement, little endian",
                        "machine": "Intel 80386",
                        "num_section_headers": 0,
                        "os_abi": "UNIX - Linux",
                        "abi_version": 0,
                        "entrypoint": 4633,
                        "num_prog_headers": 2,
                        "class": "ELF32"
                    },
                    "packers": [
                        "upx"
                    ],
                    "segment_list": [
                        {
                            "segment_type": "LOAD"
                        }
                    ]
                },
                "size": 255510,
                "type_extension": "so",
                "threat_verdict": "VERDICT_MALICIOUS",
                "detectiteasy": {
                    "filetype": "ELF32",
                    "values": [
                        {
                            "info": "EXEC 386-32",
                            "version": "3.05",
                            "type": "Packer",
                            "name": "UPX"
                        }
                    ]
                },
                "crowdsourced_ids_stats": {
                    "high": 0,
                    "info": 0,
                    "medium": 1,
                    "low": 1
                },
                "type_tags": [
                    "executable",
                    "linux",
                    "elf"
                ],
                "sandbox_verdicts": {
                    "Zenbox Linux": {
                        "category": "malicious",
                        "confidence": 81,
                        "sandbox_name": "Zenbox Linux",
                        "malware_classification": [
                            "MALWARE",
                            "TROJAN",
                            "EVADER"
                        ],
                        "malware_names": [
                            "MalwareName"
                        ]
                    }
                },
                "sha256": "Example_sha256",
                "tags": [
                    "elf",
                    "upx"
                ],
                "crowdsourced_ids_results": [
                    {
                        "rule_category": "Misc Attack",
                        "alert_severity": "medium",
                        "rule_msg": "Known Compromised or Hostile Host Traffic",
                        "rule_raw": "alert ip [8.8.8.8] any -> $HOME_NET any"
                    },
                    {
                        "rule_category": "Misc Attack",
                        "alert_severity": "low",
                        "rule_msg": "Poor Reputation IP",
                        "rule_raw": "alert ip [1.1.1.1] any -> $HOME_NET any)"
                    },
                ],
                "last_analysis_date": 1681386314,
                "ssdeep": "Example ssdeep",
                "packers": {
                    "Gandelf": "upx"
                },
                "md5": "Example_md5",
                "sha1": "Example_sha1",
                "magic": "ELF 32-bit LSB executable, Intel 80386, version 1 (GNU/Linux), statically linked, stripped",
                "meaningful_name": "private"
            },
            "type": "private_file",
            "id": "Example_sha256",
            "links": {
                "self": "https://www.virustotal.com/api/v3/private/files/Example_sha256"
            }
        }
    }
}

Human Readable Output

Results of file hash Example_sha256

Sha1 Sha256 Md5 Meaningful Name Threat Severity Level Popular Threat Category Threat Verdict
Example_sha1 Example_sha256 Example_md5 private HIGH trojan MALICIOUS

gti-privatescanning-file-scan


Submits a file for private scanning. Use the gti-privatescanning-analysis-get command to get the scan results.

Base Command

gti-privatescanning-file-scan

Input

Argument Name Description Required
entryID The file entry ID to submit. Required

Context Output

Path Type Description
GoogleThreatIntelligence.Submission.type String The type of the submission (analysis).
GoogleThreatIntelligence.Submission.id String The ID of the submission.
GoogleThreatIntelligence.Submission.EntryID String The entry ID of the file detonated.
GoogleThreatIntelligence.Submission.Extension String File extension.
GoogleThreatIntelligence.Submission.Info String File info.
GoogleThreatIntelligence.Submission.MD5 String MD5 hash of the file.
GoogleThreatIntelligence.Submission.Name String Name of the file.
GoogleThreatIntelligence.Submission.SHA1 String SHA-1 of the file.
GoogleThreatIntelligence.Submission.SHA256 String SHA-256 of the file.
GoogleThreatIntelligence.Submission.SHA512 String SHA-512 of the file.
GoogleThreatIntelligence.Submission.SSDeep String SSDeep of the file.
GoogleThreatIntelligence.Submission.Size String Size of the file.
GoogleThreatIntelligence.Submission.Type String Type of the file.

Command Example

!gti-privatescanning-file-scan entryID=example-entry-id

Context Example

{
    "GoogleThreatIntelligence": {
        "Submission": {
            "type": "private_analysis",
            "id": "example-analysis-id",
            "EntryID": "example-entry-id",
            "Extension": "txt",
            "Info": "ASCII text, with no line terminators",
            "MD5": "Example_md5",
            "Name": "Testing.txt",
            "SHA1": "Example_sha1",
            "SHA256": "Example_sha256",
            "SHA512": "Example_sha512",
            "SSDeep": "Example ssdeep",
            "Size": "71 bytes",
            "Type": "text/plain; charset=utf-8"
        }
    }
}

Human Readable Output

The file has been submitted “Testing.txt”

id EntryID MD5 SHA1 SHA256
example-analysis-id example-entry-id Example_md5 Example_sha1 Example_sha256

gti-privatescanning-analysis-get


Get analysis of a private file or URL submitted to GoogleThreatIntelligence.

Base Command

gti-privatescanning-analysis-get

Input

Argument Name Description Required
id ID of the analysis. Required

Context Output

Path Type Description
GoogleThreatIntelligence.Analysis.data.attributes.date Number Date of the analysis in epoch format.
GoogleThreatIntelligence.Analysis.data.attributes.status String Status of the analysis.
GoogleThreatIntelligence.Analysis.data.attributes.sha256 String SHA-256 hash of the private file.
GoogleThreatIntelligence.Analysis.data.attributes.threat_severity_level String Threat severity level of the private file (if analysis is completed).
GoogleThreatIntelligence.Analysis.data.attributes.popular_threat_category String Popular threat category of the private file (if analysis is completed).
GoogleThreatIntelligence.Analysis.data.attributes.threat_verdict String Threat verdict of the private file (if analysis is completed).
GoogleThreatIntelligence.Analysis.data.attributes.url String URL submitted.
GoogleThreatIntelligence.Analysis.data.attributes.title String Title of the private URL (if analysis is completed).
GoogleThreatIntelligence.Analysis.data.attributes.last_http_response_content_sha256 String Last HTTP response content SHA-256 hash of the private URL (if analysis is completed).
GoogleThreatIntelligence.Analysis.data.attributes.positives String Ratio of malicious detections to the total number of engines that scanned the private URL (if analysis is completed).
GoogleThreatIntelligence.Analysis.data.id String ID of the analysis.
GoogleThreatIntelligence.Analysis.data.type String Type of object (private_analysis).
GoogleThreatIntelligence.Analysis.meta.file_info.sha256 String SHA-256 hash of the file.
GoogleThreatIntelligence.Analysis.meta.file_info.sha1 String SHA-1 hash of the file.
GoogleThreatIntelligence.Analysis.meta.file_info.md5 String MD5 hash of the file.
GoogleThreatIntelligence.Analysis.meta.file_info.size Number Size of the file.
GoogleThreatIntelligence.Analysis.meta.url_info.id String ID of the URL.
GoogleThreatIntelligence.Analysis.meta.url_info.url String URL submitted.
GoogleThreatIntelligence.Analysis.id String The analysis ID.

gti-curated-threat-actors-get


Retrieves GTI curated threat actors for a given resource.

Base Command

gti-curated-threat-actors-get

Input

Argument Name Description Required
resource The file hash (MD5, SHA1, or SHA256), Domain, URL or IP. Required
resource_type The type of the resource. If not supplied, will determine it’s a file. Possible values are: ip, url, domain, file, hash. Optional

Context Output

Path Type Description
GoogleThreatIntelligence.Collection.id String ID that contains the assessment (the given hash, domain, url, or ip).
GoogleThreatIntelligence.Collection.collections.id String ID of the curated threat actors.
GoogleThreatIntelligence.Collection.collections.attributes.name String Name of the curated threat actors.
GoogleThreatIntelligence.Collection.collections.attributes.description String Description of the curated threat actors.
GoogleThreatIntelligence.Collection.collections.attributes.last_modification_date String Last modification date of the curated threat actors.
GoogleThreatIntelligence.Collection.collections.attributes.targeted_regions list Targeted regions of the curated threat actors.
GoogleThreatIntelligence.Collection.collections.attributes.targeted_industries list Targeted industries of the curated threat actors.

gti-curated-malware-families-get


Retrieves GTI curated malware families for a given resource.

Base Command

gti-curated-malware-families-get

Input

Argument Name Description Required
resource The file hash (MD5, SHA1, or SHA256), Domain, URL or IP. Required
resource_type The type of the resource. If not supplied, will determine it’s a file. Possible values are: ip, url, domain, file, hash. Optional

Context Output

Path Type Description
GoogleThreatIntelligence.Collection.id String ID that contains the assessment (the given hash, domain, url, or ip).
GoogleThreatIntelligence.Collection.collections.id String ID of the curated malware families.
GoogleThreatIntelligence.Collection.collections.attributes.name String Name of the curated malware families.
GoogleThreatIntelligence.Collection.collections.attributes.description String Description of the curated malware families.
GoogleThreatIntelligence.Collection.collections.attributes.last_modification_date String Last modification date of the curated malware families.
GoogleThreatIntelligence.Collection.collections.attributes.targeted_regions list Targeted regions of the curated malware families.
GoogleThreatIntelligence.Collection.collections.attributes.targeted_industries list Targeted industries of the curated malware families.

gti-curated-campaigns-get


Retrieves GTI curated campaigns for a given resource.

Base Command

gti-curated-campaigns-get

Input

Argument Name Description Required
resource The file hash (MD5, SHA1, or SHA256), Domain, URL or IP. Required
resource_type The type of the resource. If not supplied, will determine it’s a file. Possible values are: ip, url, domain, file, hash. Optional

Context Output

Path Type Description
GoogleThreatIntelligence.Collection.id String ID that contains the assessment (the given hash, domain, url, or ip).
GoogleThreatIntelligence.Collection.collections.id String ID of the curated campaign.
GoogleThreatIntelligence.Collection.collections.attributes.name String Name of the curated campaign.
GoogleThreatIntelligence.Collection.collections.attributes.description String Description of the curated campaign.
GoogleThreatIntelligence.Collection.collections.attributes.last_modification_date String Last modification date of the curated campaign.
GoogleThreatIntelligence.Collection.collections.attributes.targeted_regions list Targeted regions of the curated campaign.
GoogleThreatIntelligence.Collection.collections.attributes.targeted_industries list Targeted industries of the curated campaign.

gti-url-scan-and-analysis-get


Scan and get the analysis of a URL submitted to GoogleThreatIntelligence.

Base Command

gti-url-scan-and-analysis-get

Input

Argument Name Description Required
url The URL to scan. Required
id This is an internal argument used for the polling process, not to be used by the user. Optional
extended_data Whether to return extended data. Possible values are: true, false. Optional
interval_in_seconds Interval in seconds between each poll. Default is 60. Optional

Context Output

Path Type Description
URL.Data unknown Bad URLs found.
URL.Malicious.Vendor unknown For malicious URLs, the vendor that made the decision.
URL.Malicious.Description unknown For malicious URLs, the reason that the vendor made the decision.
URL.Relationships.EntityA string The source of the relationship.
URL.Relationships.EntityB string The destination of the relationship.
URL.Relationships.Relationship string The name of the relationship.
URL.Relationships.EntityAType string The type of the source of the relationship.
URL.Relationships.EntityBType string The type of the destination of the relationship.
DBotScore.Indicator unknown The indicator that was tested.
DBotScore.Type unknown The indicator type.
DBotScore.Vendor unknown The vendor used to calculate the score.
DBotScore.Score Number The actual score.
DBotScore.Reliability String Reliability of the source providing the intelligence data.
GoogleThreatIntelligence.URL.attributes.favicon.raw_md5 String The MD5 hash of the URL.
GoogleThreatIntelligence.URL.attributes.favicon.dhash String Difference hash.
GoogleThreatIntelligence.URL.attributes.last_modification_date Number Last modification date in epoch format.
GoogleThreatIntelligence.URL.attributes.times_submitted Number The number of times the url has been submitted.
GoogleThreatIntelligence.URL.attributes.total_votes.harmless Number Total number of harmless votes.
GoogleThreatIntelligence.URL.attributes.total_votes.malicious Number Total number of malicious votes.
GoogleThreatIntelligence.URL.attributes.threat_names String Name of the threats found.
GoogleThreatIntelligence.URL.attributes.last_submission_date Number The last submission date in epoch format.
GoogleThreatIntelligence.URL.attributes.last_http_response_content_length Number The last HTTPS response length.
GoogleThreatIntelligence.URL.attributes.last_http_response_headers.date Date The last response header date.
GoogleThreatIntelligence.URL.attributes.last_http_response_headers.x-sinkhole String DNS sinkhole from last response.
GoogleThreatIntelligence.URL.attributes.last_http_response_headers.content-length String The content length of the last response.
GoogleThreatIntelligence.URL.attributes.last_http_response_headers.content-type String The content type of the last response.
GoogleThreatIntelligence.URL.attributes.reputation Number Reputation of the indicator.
GoogleThreatIntelligence.URL.attributes.last_analysis_date Number The date of the last analysis in epoch format.
GoogleThreatIntelligence.URL.attributes.has_content Boolean Whether the url has content in it.
GoogleThreatIntelligence.URL.attributes.first_submission_date Number The first submission date in epoch format.
GoogleThreatIntelligence.URL.attributes.last_http_response_content_sha256 String The SHA-256 hash of the content of the last response.
GoogleThreatIntelligence.URL.attributes.last_http_response_code Number Last response status code.
GoogleThreatIntelligence.URL.attributes.last_final_url String Last final URL.
GoogleThreatIntelligence.URL.attributes.url String The URL itself.
GoogleThreatIntelligence.URL.attributes.title String Title of the page.
GoogleThreatIntelligence.URL.attributes.last_analysis_stats.harmless Number The number of engines that found the domain to be harmless.
GoogleThreatIntelligence.URL.attributes.last_analysis_stats.malicious Number The number of engines that found the indicator to be malicious.
GoogleThreatIntelligence.URL.attributes.last_analysis_stats.suspicious Number The number of engines that found the indicator to be suspicious.
GoogleThreatIntelligence.URL.attributes.last_analysis_stats.undetected Number The number of engines that could not detect the indicator.
GoogleThreatIntelligence.URL.attributes.last_analysis_stats.timeout Number The number of engines that timed out for the indicator.
GoogleThreatIntelligence.URL.attributes.outgoing_links String Outgoing links of the URL page.
GoogleThreatIntelligence.URL.attributes.gti_assessment.threat_score.value Number GTI threat score of the URL.
GoogleThreatIntelligence.URL.attributes.gti_assessment.severity.value String GTI severity of the URL.
GoogleThreatIntelligence.URL.attributes.gti_assessment.verdict.value String GTI verdict of the URL.
GoogleThreatIntelligence.URL.type String Type of the indicator (url).
GoogleThreatIntelligence.URL.id String ID of the indicator.
GoogleThreatIntelligence.URL.links.self String Link to the response.
GoogleThreatIntelligence.Analysis.data.attributes.date Number Date of the analysis in epoch format.
GoogleThreatIntelligence.Analysis.data.attributes.stats.harmless Number Number of engines that found the indicator to be harmless.
GoogleThreatIntelligence.Analysis.data.attributes.stats.malicious Number Number of engines that found the indicator to be malicious.
GoogleThreatIntelligence.Analysis.data.attributes.stats.suspicious Number Number of engines that found the indicator to be suspicious.
GoogleThreatIntelligence.Analysis.data.attributes.stats.timeout Number he number of engines that timed out for the indicator.
GoogleThreatIntelligence.Analysis.data.attributes.stats.undetected Number Number of engines the found the indicator to be undetected.
GoogleThreatIntelligence.Analysis.data.attributes.status String Status of the analysis.
GoogleThreatIntelligence.Analysis.data.id String ID of the analysis.
GoogleThreatIntelligence.Analysis.data.type String Type of object (analysis).
GoogleThreatIntelligence.Analysis.meta.url_info.id String ID of the URL.
GoogleThreatIntelligence.Analysis.meta.url_info.url String The URL.
GoogleThreatIntelligence.Analysis.id String The analysis ID.

gti-file-scan-and-analysis-get


Scan and get the analysis of a file submitted to GoogleThreatIntelligence.

Base Command

gti-file-scan-and-analysis-get

Input

Argument Name Description Required
entryID The file entry ID to submit. Required
uploadURL Special upload URL for files larger than 32 MB. Can be acquired from the gti-file-scan-upload-url command. Optional
id This is an internal argument used for the polling process, not to be used by the user. Optional
file This is an internal argument used for the polling process, not to be used by the user. Optional
extended_data Whether to return extended data. Possible values are: true, false. Optional
interval_in_seconds Interval in seconds between each poll. Default is 60. Optional

Context Output

Path Type Description
File.MD5 unknown Bad MD5 hash.
File.SHA1 unknown Bad SHA1 hash.
File.SHA256 unknown Bad SHA256 hash.
File.Relationships.EntityA string The source of the relationship.
File.Relationships.EntityB string The destination of the relationship.
File.Relationships.Relationship string The name of the relationship.
File.Relationships.EntityAType string The type of the source of the relationship.
File.Relationships.EntityBType string The type of the destination of the relationship.
File.Malicious.Vendor unknown For malicious files, the vendor that made the decision.
File.Malicious.Detections unknown For malicious files, the total number of detections.
File.Malicious.TotalEngines unknown For malicious files, the total number of engines that checked the file hash.
DBotScore.Indicator unknown The indicator that was tested.
DBotScore.Type unknown The indicator type.
DBotScore.Vendor unknown The vendor used to calculate the score.
DBotScore.Score Number The actual score.
DBotScore.Reliability String Reliability of the source providing the intelligence data.
GoogleThreatIntelligence.File.attributes.type_description String Description of the type of the file.
GoogleThreatIntelligence.File.attributes.tlsh String The locality-sensitive hashing.
GoogleThreatIntelligence.File.attributes.exiftool.MIMEType String MIME type of the file.
GoogleThreatIntelligence.File.attributes.names String Names of the file.
GoogleThreatIntelligence.File.attributes.javascript_info.tags String Tags of the JavaScript.
GoogleThreatIntelligence.File.attributes.exiftool.FileType String The file type.
GoogleThreatIntelligence.File.attributes.exiftool.WordCount String Total number of words in the file.
GoogleThreatIntelligence.File.attributes.exiftool.LineCount String Total number of lines in file.
GoogleThreatIntelligence.File.attributes.crowdsourced_ids_stats.info Number Number of IDS that marked the file as “info”.
GoogleThreatIntelligence.File.attributes.crowdsourced_ids_stats.high Number Number of IDS that marked the file as “high”.
GoogleThreatIntelligence.File.attributes.crowdsourced_ids_stats.medium Number Number of IDS that marked the file as “medium”.
GoogleThreatIntelligence.File.attributes.crowdsourced_ids_stats.low Number Number of IDS that marked the file as “low”.
GoogleThreatIntelligence.File.attributes.sigma_analysis_stats.critical Number Number of Sigma analysis that marked the file as “critical”.
GoogleThreatIntelligence.File.attributes.sigma_analysis_stats.high Number Number of Sigma analysis that marked the file as “high”.
GoogleThreatIntelligence.File.attributes.sigma_analysis_stats.medium Number Number of Sigma analysis that marked the file as “medium”.
GoogleThreatIntelligence.File.attributes.sigma_analysis_stats.low Number Number of Sigma analysis that marked the file as “low”.
GoogleThreatIntelligence.File.attributes.exiftool.MIMEEncoding String The MIME encoding.
GoogleThreatIntelligence.File.attributes.exiftool.FileTypeExtension String The file type extension.
GoogleThreatIntelligence.File.attributes.exiftool.Newlines String Number of newlines signs.
GoogleThreatIntelligence.File.attributes.trid.file_type String The TrID file type.
GoogleThreatIntelligence.File.attributes.trid.probability Number The TrID probability.
GoogleThreatIntelligence.File.attributes.crowdsourced_yara_results.description String Description of the YARA rule.
GoogleThreatIntelligence.File.attributes.crowdsourced_yara_results.source String Source of the YARA rule.
GoogleThreatIntelligence.File.attributes.crowdsourced_yara_results.author String Author of the YARA rule.
GoogleThreatIntelligence.File.attributes.crowdsourced_yara_results.ruleset_name String Rule set name of the YARA rule.
GoogleThreatIntelligence.File.attributes.crowdsourced_yara_results.rule_name String Name of the YARA rule.
GoogleThreatIntelligence.File.attributes.crowdsourced_yara_results.ruleset_id String ID of the YARA rule.
GoogleThreatIntelligence.File.attributes.names String Name of the file.
GoogleThreatIntelligence.File.attributes.last_modification_date Number The last modification date in epoch format.
GoogleThreatIntelligence.File.attributes.type_tag String Tag of the type.
GoogleThreatIntelligence.File.attributes.total_votes.harmless Number Total number of harmless votes.
GoogleThreatIntelligence.File.attributes.total_votes.malicious Number Total number of malicious votes.
GoogleThreatIntelligence.File.attributes.size Number Size of the file.
GoogleThreatIntelligence.File.attributes.popular_threat_classification.suggested_threat_label String Suggested thread label.
GoogleThreatIntelligence.File.attributes.popular_threat_classification.popular_threat_name Number The popular thread name.
GoogleThreatIntelligence.File.attributes.times_submitted Number Number of times the file was submitted.
GoogleThreatIntelligence.File.attributes.last_submission_date Number Last submission date in epoch format.
GoogleThreatIntelligence.File.attributes.downloadable Boolean Whether the file is downloadable.
GoogleThreatIntelligence.File.attributes.sha256 String SHA-256 hash of the file.
GoogleThreatIntelligence.File.attributes.type_extension String Extension of the type.
GoogleThreatIntelligence.File.attributes.tags String File tags.
GoogleThreatIntelligence.File.attributes.last_analysis_date Number Last analysis date in epoch format.
GoogleThreatIntelligence.File.attributes.unique_sources Number Unique sources.
GoogleThreatIntelligence.File.attributes.first_submission_date Number First submission date in epoch format.
GoogleThreatIntelligence.File.attributes.ssdeep String SSDeep hash of the file.
GoogleThreatIntelligence.File.attributes.md5 String MD5 hash of the file.
GoogleThreatIntelligence.File.attributes.sha1 String SHA-1 hash of the file.
GoogleThreatIntelligence.File.attributes.magic String Identification of file by the magic number.
GoogleThreatIntelligence.File.attributes.last_analysis_stats.harmless Number The number of engines that found the indicator to be harmless.
GoogleThreatIntelligence.File.attributes.last_analysis_stats.type-unsupported Number The number of engines that found the indicator to be of type unsupported.
GoogleThreatIntelligence.File.attributes.last_analysis_stats.suspicious Number The number of engines that found the indicator to be suspicious.
GoogleThreatIntelligence.File.attributes.last_analysis_stats.confirmed-timeout Number The number of engines that confirmed the timeout of the indicator.
GoogleThreatIntelligence.File.attributes.last_analysis_stats.timeout Number The number of engines that timed out for the indicator.
GoogleThreatIntelligence.File.attributes.last_analysis_stats.failure Number The number of failed analysis engines.
GoogleThreatIntelligence.File.attributes.last_analysis_stats.malicious Number The number of engines that found the indicator to be malicious.
GoogleThreatIntelligence.File.attributes.last_analysis_stats.undetected Number The number of engines that could not detect the indicator.
GoogleThreatIntelligence.File.attributes.meaningful_name String Meaningful name of the file.
GoogleThreatIntelligence.File.attributes.reputation Number The reputation of the file.
GoogleThreatIntelligence.File.attributes.gti_assessment.threat_score.value Number GTI threat score of the file.
GoogleThreatIntelligence.File.attributes.gti_assessment.severity.value String GTI severity of the file.
GoogleThreatIntelligence.File.attributes.gti_assessment.verdict.value String GTI verdict of the file.
GoogleThreatIntelligence.File.type String Type of the indicator (file).
GoogleThreatIntelligence.File.id String Type ID of the indicator.
GoogleThreatIntelligence.File.links.self String Link to the response.
GoogleThreatIntelligence.Analysis.data.attributes.date Number Date of the analysis in epoch format.
GoogleThreatIntelligence.Analysis.data.attributes.stats.harmless Number Number of engines that found the indicator to be harmless.
GoogleThreatIntelligence.Analysis.data.attributes.stats.malicious Number Number of engines that found the indicator to be malicious.
GoogleThreatIntelligence.Analysis.data.attributes.stats.suspicious Number Number of engines that found the indicator to be suspicious.
GoogleThreatIntelligence.Analysis.data.attributes.stats.timeout Number he number of engines that timed out for the indicator.
GoogleThreatIntelligence.Analysis.data.attributes.stats.undetected Number Number of engines the found the indicator to be undetected.
GoogleThreatIntelligence.Analysis.data.attributes.status String Status of the analysis.
GoogleThreatIntelligence.Analysis.data.id String ID of the analysis.
GoogleThreatIntelligence.Analysis.data.type String Type of object (analysis).
GoogleThreatIntelligence.Analysis.meta.file_info.sha256 String SHA-256 hash of the file.
GoogleThreatIntelligence.Analysis.meta.file_info.sha1 String SHA-1 hash of the file.
GoogleThreatIntelligence.Analysis.meta.file_info.md5 String MD5 hash of the file.
GoogleThreatIntelligence.Analysis.meta.file_info.name unknown Name of the file.
GoogleThreatIntelligence.Analysis.meta.file_info.size Number Size of the file.
GoogleThreatIntelligence.Analysis.id String The analysis ID.

gti-private-file-scan-and-analysis-get


Scan and get the analysis of a private file submitted to GoogleThreatIntelligence.

Base Command

gti-private-file-scan-and-analysis-get

Input

Argument Name Description Required
entryID The file entry ID to submit. Required
id This is an internal argument used for the polling process, not to be used by the user. Optional
extended_data Whether to return extended data. Possible values are: true, false. Optional
interval_in_seconds Interval in seconds between each poll. Default is 60. Optional

Context Output

Path Type Description
GoogleThreatIntelligence.Analysis.data.attributes.date Number Date of the analysis in epoch format.
GoogleThreatIntelligence.Analysis.data.attributes.status String Status of the analysis.
GoogleThreatIntelligence.Analysis.data.attributes.sha256 String SHA-256 hash of the private file.
GoogleThreatIntelligence.Analysis.data.attributes.threat_severity_level String Threat severity level of the private file (if analysis is completed).
GoogleThreatIntelligence.Analysis.data.attributes.popular_threat_category String Popular threat category of the private file (if analysis is completed).
GoogleThreatIntelligence.Analysis.data.attributes.threat_verdict String Threat verdict of the private file (if analysis is completed).
GoogleThreatIntelligence.Analysis.data.id String ID of the analysis.
GoogleThreatIntelligence.Analysis.data.type String Type of object (private_analysis).
GoogleThreatIntelligence.Analysis.meta.file_info.sha256 String SHA-256 hash of the file.
GoogleThreatIntelligence.Analysis.meta.file_info.sha1 String SHA-1 hash of the file.
GoogleThreatIntelligence.Analysis.meta.file_info.md5 String MD5 hash of the file.
GoogleThreatIntelligence.Analysis.meta.file_info.size Number Size of the file.
GoogleThreatIntelligence.Analysis.id String The analysis ID.

gti-private-file-scan-and-analysis-get


Scan and get the analysis of a private file submitted to GoogleThreatIntelligence.

Base Command

gti-private-file-scan-and-analysis-get

Input

Argument Name Description Required
entryID The file entry ID to submit. Required
id This is an internal argument used for the polling process, not to be used by the user. Optional
extended_data Whether to return extended data. Possible values are: true, false. Optional
interval_in_seconds Interval in seconds between each poll. Default is 60. Optional

Context Output

Path Type Description
GoogleThreatIntelligence.Analysis.data.attributes.date Number Date of the analysis in epoch format.
GoogleThreatIntelligence.Analysis.data.attributes.status String Status of the analysis.
GoogleThreatIntelligence.Analysis.data.attributes.threat_severity_level String Threat severity level of the private file.
GoogleThreatIntelligence.Analysis.data.attributes.popular_threat_category String Popular threat category of the private file.
GoogleThreatIntelligence.Analysis.data.attributes.threat_verdict String Threat verdict of the private file.
GoogleThreatIntelligence.Analysis.data.id String ID of the analysis.
GoogleThreatIntelligence.Analysis.data.type String Type of object (analysis).
GoogleThreatIntelligence.Analysis.meta.file_info.sha256 String SHA-256 hash of the file.
GoogleThreatIntelligence.Analysis.meta.file_info.sha1 String SHA-1 hash of the file.
GoogleThreatIntelligence.Analysis.meta.file_info.md5 String MD5 hash of the file.
GoogleThreatIntelligence.Analysis.meta.file_info.size Number Size of the file.
GoogleThreatIntelligence.Analysis.id String The analysis ID.

gti-assessment-get


Retrieves GTI assessment for a given resource.

Base Command

gti-assessment-get

Input

Argument Name Description Required
resource The file hash (MD5, SHA1, or SHA256), Domain, URL or IP. Required
resource_type The type of the resource. If not supplied, will determine it’s a file. Possible values are: ip, url, domain, file, hash. Optional

Context Output

Path Type Description
GoogleThreatIntelligence.Assessment.id String ID that contains the assessment (the given hash, domain, url, or ip).
GoogleThreatIntelligence.Assessment.attributes.gti_assessment.threat_score.value Number The threat score of the assessment.
GoogleThreatIntelligence.Assessment.attributes.gti_assessment.severity.value String The severity of the assessment.
GoogleThreatIntelligence.Assessment.attributes.gti_assessment.verdict.value String The verdict of the assessment.

gti-private-url-scan-and-analysis-get


Scan and get the analysis of a private URL submitted to GoogleThreatIntelligence.

Base Command

gti-private-url-scan-and-analysis-get

Input

Argument Name Description Required
url The URL to scan. Required
id This is an internal argument used for the polling process, not to be used by the user. Optional
extended_data Whether to return extended data. Possible values are: true, false. Optional
interval_in_seconds Interval in seconds between each poll. Default is 60. Optional

Context Output

Path Type Description
GoogleThreatIntelligence.Analysis.data.attributes.date Number Date of the analysis in epoch format.
GoogleThreatIntelligence.Analysis.data.attributes.status String Status of the analysis.
GoogleThreatIntelligence.Analysis.data.attributes.url String URL submitted.
GoogleThreatIntelligence.Analysis.data.attributes.title String Title of the private URL (if analysis is completed).
GoogleThreatIntelligence.Analysis.data.attributes.last_http_response_content_sha256 String Last HTTP response content SHA-256 hash of the private URL (if analysis is completed).
GoogleThreatIntelligence.Analysis.data.attributes.positives String Ratio of malicious detections to the total number of engines that scanned the private URL (if analysis is completed).
GoogleThreatIntelligence.Analysis.data.id String ID of the analysis.
GoogleThreatIntelligence.Analysis.data.type String Type of object (private_analysis).
GoogleThreatIntelligence.Analysis.meta.url_info.id String ID of the URL.
GoogleThreatIntelligence.Analysis.meta.url_info.url String URL submitted.
GoogleThreatIntelligence.Analysis.id String The analysis ID.

gti-privatescanning-url-scan


Base Command

gti-privatescanning-url-scan

Input

Argument Name Description Required
url The private URL to scan. Required

Context Output

Path Type Description
GoogleThreatIntelligence.Submission.Type String The type of the submission (private_analysis).
GoogleThreatIntelligence.Submission.id String The ID of the submission.

gti-privatescanning-url


Checks the reputation of a private URL.

Base Command

gti-privatescanning-url

Input

Argument Name Description Required
url Private URL to check. Required

Context Output

Path Type Description
GoogleThreatIntelligence.URL.attributes.favicon.raw_md5 String The MD5 hash of the URL.
GoogleThreatIntelligence.URL.attributes.favicon.dhash String Difference hash.
GoogleThreatIntelligence.URL.attributes.last_http_response_content_length Number The last HTTPS response length.
GoogleThreatIntelligence.URL.attributes.last_http_response_headers.date Date The last response header date.
GoogleThreatIntelligence.URL.attributes.last_http_response_headers.x-sinkhole String DNS sinkhole from last response.
GoogleThreatIntelligence.URL.attributes.last_http_response_headers.content-length String The content length of the last response.
GoogleThreatIntelligence.URL.attributes.last_http_response_headers.content-type String The content type of the last response.
GoogleThreatIntelligence.URL.attributes.last_http_response_content_sha256 String The SHA-256 hash of the content of the last response.
GoogleThreatIntelligence.URL.attributes.last_http_response_code Number Last response status code.
GoogleThreatIntelligence.URL.attributes.last_final_url String Last final URL.
GoogleThreatIntelligence.URL.attributes.url String The URL itself.
GoogleThreatIntelligence.URL.attributes.title String Title of the page.
GoogleThreatIntelligence.URL.attributes.last_analysis_stats.harmless Number The number of engines that found the domain to be harmless.
GoogleThreatIntelligence.URL.attributes.last_analysis_stats.malicious Number The number of engines that found the indicator to be malicious.
GoogleThreatIntelligence.URL.attributes.last_analysis_stats.suspicious Number The number of engines that found the indicator to be suspicious.
GoogleThreatIntelligence.URL.attributes.last_analysis_stats.undetected Number The number of engines that could not detect the indicator.
GoogleThreatIntelligence.URL.attributes.last_analysis_stats.timeout Number The number of engines that timed out for the indicator.
GoogleThreatIntelligence.URL.attributes.outgoing_links String Outgoing links of the URL page.
GoogleThreatIntelligence.URL.type String Type of the indicator (private_url).
GoogleThreatIntelligence.URL.id String ID of the indicator.
GoogleThreatIntelligence.URL.links.self String Link to the response.

Configuration parameters

  • credentials — API Key (leave empty. Fill in the API key in the password field.) (required)
  • feedReliability — Source Reliability
  • gti_malicious — GTI Malicious Verdict. Check Google Threat Intelligence verdict to consider the file malicious.
  • gti_suspicious — GTI Suspicious Verdict. Check Google Threat Intelligence verdict to consider the file suspicious.
  • fileThreshold — File Malicious Threshold. Minimum number of positive results from VT scanners to consider the file malicious.
  • fileSuspiciousThreshold — File Suspicious Threshold. Minimum number of positive and suspicious results from VT scanners to consider the file suspicious.
  • ipThreshold — IP Malicious Threshold. Minimum number of positive results from VT scanners to consider the IP malicious.
  • ipSuspiciousThreshold — IP Suspicious Threshold. Minimum number of positive and suspicious results from VT scanners to consider the IP suspicious.
  • disable_private_ip_lookup — Disable reputation lookups for private IP addresses
  • urlThreshold — URL Malicious Threshold. Minimum number of positive results from VT scanners to consider the URL malicious.
  • urlSuspiciousThreshold — URL Suspicious Threshold. Minimum number of positive and suspicious results from VT scanners to consider the URL suspicious.
  • domainThreshold — Domain Malicious Threshold. Minimum number of positive results from VT scanners to consider the Domain malicious.
  • domainSuspiciousThreshold — Domain Suspicious Threshold. Minimum number of positive and suspicious results from VT scanners to consider the Domain suspicious.
  • preferredVendors — Preferred Vendors List. CSV list of vendors who are considered more trustworthy.
  • preferredVendorsThreshold — Preferred Vendor Threshold. The minimum number of highly trusted vendors required to consider a domain, IP address, URL, or file as malicious.
  • crowdsourced_yara_rules_enabled — Enable score analyzing by Crowdsourced Yara Rules, Sigma, and IDS.
  • yaraRulesThreshold — Crowdsourced Yara Rules Threshold
  • SigmaIDSThreshold — Sigma and Intrusion Detection Rules Threshold
  • domain_popularity_ranking — Domain Popularity Ranking Threshold
  • ip_relationships — IP Relationships
  • domain_relationships — Domain Relationships
  • url_relationships — URL Relationships
  • file_relationships — File Relationships
  • proxy — Use system proxy settings
  • insecure — Trust any certificate (not secure)

Commands (31)

  • cve

    Retrieves CVE information from Google Threat Intelligence.

  • domain

    Checks the reputation of a domain.

  • file

    Checks the file reputation of the specified hash.

  • file-rescan

    Rescans an already submitted file. This avoids having to upload the file again. Use the gti-analysis-get command to get the scan results.

  • file-scan

    Submits a file for scanning. Use the gti-analysis-get command to get the scan results.

  • gti-analysis-get

    Scan and get the analysis of a file submitted to GoogleThreatIntelligence.

  • gti-assessment-get

    Retrieves GTI assessment for a given resource.

  • gti-comments-add

    Adds comments to files and URLs.

  • gti-comments-delete

    Delete a comment.

  • gti-comments-get

    Retrieves comments for a given resource.

  • gti-comments-get-by-id

    Retrieves a comment by comment ID.

  • gti-curated-campaigns-get

    Retrieves GTI curated campaigns for a given resource.

  • gti-curated-malware-families-get

    Retrieves GTI curated malware families for a given resource.

  • gti-curated-threat-actors-get

    Retrieves GTI curated threat actors for a given resource.

  • gti-file-sandbox-report

    Retrieves a behavioral relationship of the given file hash.

  • gti-file-scan-and-analysis-get

    Scan and get the analysis of a file submitted to GoogleThreatIntelligence.

  • gti-file-scan-upload-url

    Get a special URL for files larger than 32 MB.

  • gti-file-sigma-analysis

    Result of the last Sigma analysis in markdown format.

  • gti-passive-dns-data

    Returns passive DNS records by indicator.

  • gti-private-file-scan-and-analysis-get

    Scan and get the analysis of a private file submitted to GoogleThreatIntelligence.

  • gti-private-url-scan-and-analysis-get

    Scan and get the analysis of a private URL submitted to GoogleThreatIntelligence.

  • gti-privatescanning-analysis-get

    Get analysis of a private file or URL submitted to GoogleThreatIntelligence.

  • gti-privatescanning-file

    Checks the file reputation of the specified private hash.

  • gti-privatescanning-file-scan

    Submits a file for private scanning. Use the gti-privatescanning-analysis-get command to get the scan results.

  • gti-privatescanning-url

    Checks the reputation of a private URL.

  • gti-privatescanning-url-scan

    Submits an URL for private scanning. Use the gti-privatescanning-analysis-get command to get the scan results.

  • gti-search

    Search for an indicator in Google Threat Intelligence.

  • gti-url-scan-and-analysis-get

    Scan and get the analysis of a URL submitted to GoogleThreatIntelligence.

  • ip

    Checks the reputation of an IP address.

  • url

    Checks the reputation of a URL.

  • url-scan

    Scans a specified URL. Use the gti-analysis-get command to get the scan results.

import demistomock as demisto  # noqa: F401
from CommonServerPython import *  # noqa: F401

"""
An integration module for the Google Threat Intelligence API.
API Documentation:
    https://gtidocs.virustotal.com/reference
"""
import ipaddress
import re
from collections import defaultdict
from typing import cast

from dateparser import parse

INTEGRATION_NAME = "GoogleThreatIntelligence"
COMMAND_PREFIX = "gti"
INTEGRATION_ENTRY_CONTEXT = INTEGRATION_NAME

INDICATOR_TYPE = {
    "ip": FeedIndicatorType.IP,
    "ip_address": FeedIndicatorType.IP,
    "domain": FeedIndicatorType.Domain,
    "file": FeedIndicatorType.File,
    "url": FeedIndicatorType.URL,
    "cve": FeedIndicatorType.CVE,
}

SEVERITY_LEVELS = {
    "SEVERITY_UNKNOWN": "UNKNOWN",
    "SEVERITY_LOW": "LOW",
    "SEVERITY_MEDIUM": "MEDIUM",
    "SEVERITY_HIGH": "HIGH",
}

VERDICTS = {
    "VERDICT_UNKNOWN": "UNKNOWN",
    "VERDICT_UNDETECTED": "UNDETECTED",
    "VERDICT_SUSPICIOUS": "SUSPICIOUS",
    "VERDICT_MALICIOUS": "MALICIOUS",
}

TYPE_TO_ENDPOINT = {
    "file": "files",
    "hash": "files",
    "domain": "domains",
    "url": "urls",
    "ip": "ip_addresses",
}


"""RELATIONSHIP TYPE"""
RELATIONSHIP_TYPE = {
    "file": {
        "carbonblack_children": EntityRelationship.Relationships.CREATES,
        "carbonblack_parents": EntityRelationship.Relationships.CREATED_BY,
        "compressed_parents": EntityRelationship.Relationships.BUNDLED_IN,
        "contacted_domains": EntityRelationship.Relationships.COMMUNICATES_WITH,
        "contacted_ips": EntityRelationship.Relationships.COMMUNICATES_WITH,
        "contacted_urls": EntityRelationship.Relationships.COMMUNICATES_WITH,
        "dropped_files": EntityRelationship.Relationships.DROPPED_BY,
        "email_attachments": EntityRelationship.Relationships.ATTACHES,
        "email_parents": EntityRelationship.Relationships.ATTACHMENT_OF,
        "embedded_domains": EntityRelationship.Relationships.EMBEDDED_IN,
        "embedded_ips": EntityRelationship.Relationships.EMBEDDED_IN,
        "embedded_urls": EntityRelationship.Relationships.EMBEDDED_IN,
        "execution_parents": EntityRelationship.Relationships.EXECUTED_BY,
        "itw_domains": EntityRelationship.Relationships.DOWNLOADS_FROM,
        "itw_ips": EntityRelationship.Relationships.DOWNLOADS_FROM,
        "overlay_children": EntityRelationship.Relationships.BUNDLES,
        "overlay_parents": EntityRelationship.Relationships.BUNDLED_IN,
        "pcap_children": EntityRelationship.Relationships.BUNDLES,
        "pcap_parents": EntityRelationship.Relationships.BUNDLED_IN,
        "pe_resource_children": EntityRelationship.Relationships.EXECUTED,
        "pe_resource_parents": EntityRelationship.Relationships.EXECUTED_BY,
        "similar_files": EntityRelationship.Relationships.SIMILAR_TO,
    },
    "domain": {
        "cname_records": EntityRelationship.Relationships.IS_ALSO,
        "caa_records": EntityRelationship.Relationships.RELATED_TO,
        "communicating_files": EntityRelationship.Relationships.DROPS,
        "downloaded_files": EntityRelationship.Relationships.DROPS,
        "immediate_parent": EntityRelationship.Relationships.SUB_DOMAIN_OF,
        "mx_records": EntityRelationship.Relationships.RELATED_TO,
        "ns_records": EntityRelationship.Relationships.DROPS,
        "parent": EntityRelationship.Relationships.SUB_DOMAIN_OF,
        "referrer_files": EntityRelationship.Relationships.RELATED_TO,
        "resolutions": EntityRelationship.Relationships.RESOLVED_FROM,
        "siblings": EntityRelationship.Relationships.SUPRA_DOMAIN_OF,
        "soa_records": EntityRelationship.Relationships.IS_ALSO,
        "subdomains": EntityRelationship.Relationships.SUPRA_DOMAIN_OF,
        "urls": EntityRelationship.Relationships.HOSTS,
    },
    "ip": {
        "communicating_files": EntityRelationship.Relationships.COMMUNICATES_WITH,
        "downloaded_files": EntityRelationship.Relationships.DROPS,
        "referrer_files": EntityRelationship.Relationships.RELATED_TO,
        "resolutions": EntityRelationship.Relationships.RESOLVES_TO,
        "urls": EntityRelationship.Relationships.RELATED_TO,
    },
    "url": {
        "contacted_domains": EntityRelationship.Relationships.RELATED_TO,
        "contacted_ips": EntityRelationship.Relationships.RELATED_TO,
        "downloaded_files": EntityRelationship.Relationships.DROPS,
        "last_serving_ip_address": EntityRelationship.Relationships.RESOLVED_FROM,
        "network_location": EntityRelationship.Relationships.RESOLVED_FROM,
        "redirecting_urls": EntityRelationship.Relationships.DUPLICATE_OF,
        "redirects_to": EntityRelationship.Relationships.DUPLICATE_OF,
        "referrer_files": EntityRelationship.Relationships.EMBEDDED_IN,
        "referrer_urls": EntityRelationship.Relationships.RELATED_TO,
    },
    "cve": {"referrer_cve": EntityRelationship.Relationships.RELATED_TO},
}


class Client(BaseClient):
    """Client for Google Threat Intelligence API."""

    reliability: DBotScoreReliability

    def __init__(self, params: dict):
        self.reliability = DBotScoreReliability.get_dbot_score_reliability_from_str(params["feedReliability"])

        super().__init__(
            "https://www.virustotal.com/api/v3/",
            verify=not argToBoolean(params.get("insecure")),
            proxy=argToBoolean(params.get("proxy")),
            headers={
                "x-apikey": params["credentials"]["password"],
                "x-tool": "CortexGTI",
            },
        )

    # region Reputation calls

    def ip(self, ip: str, relationships: str = "") -> dict:
        """
        See Also:
            https://gtidocs.virustotal.com/reference/ip-info
        """
        return self._http_request("GET", f"ip_addresses/{ip}?relationships={relationships}", ok_codes=(404, 429, 200))

    def file(self, file: str, relationships: str = "") -> dict:
        """
        See Also:
            https://gtidocs.virustotal.com/reference/file-info
        """
        return self._http_request("GET", f"files/{file}?relationships={relationships}", ok_codes=(404, 429, 200))

    # It is not a Reputation call
    def private_file(self, file: str) -> dict:
        """
        See Also:
            https://gtidocs.virustotal.com/reference/private-files-info
        """
        return self._http_request("GET", f"private/files/{file}", ok_codes=(404, 429, 200))

    def url(self, url: str, relationships: str = ""):
        """
        See Also:
            https://gtidocs.virustotal.com/reference/url-info
        """
        return self._http_request(
            "GET", f"urls/{encode_url_to_base64(url)}?relationships={relationships}", ok_codes=(404, 429, 200)
        )

    def private_url(self, url: str):
        """
        See Also:
            https://gtidocs.virustotal.com/reference/get-a-private-url-analysis-report
        """
        return self._http_request("GET", f"private/urls/{encode_url_to_base64(url)}", ok_codes=(404, 429, 200))

    def domain(self, domain: str, relationships: str = "") -> dict:
        """
        See Also:
            https://gtidocs.virustotal.com/reference/domain-info
        """
        return self._http_request("GET", f"domains/{domain}?relationships={relationships}", ok_codes=(404, 429, 200))

    def cve(self, cve_id: str) -> dict:
        """
        Get CVE (vulnerability) information from Google Threat Intelligence.

        Args:
            cve_id: CVE identifier (e.g., "CVE-2025-62173")

        Returns:
            dict: CVE information from the collections endpoint

        See Also:
            https://gtidocs.virustotal.com/reference/get-vulnerability
        """
        # Format: vulnerability--cve-2025-62173
        object_id = f"vulnerability--{cve_id.lower()}"
        return self._http_request("GET", f"collections/{object_id}", ok_codes=(404, 429, 200))

    # endregion

    # region Comments call
    def delete_comment(self, id_: str):
        """
        See Also:
            https://gtidocs.virustotal.com/reference/comment-id-delete
        """
        self._http_request("DELETE", f"comments/{id_}", resp_type="response")

    def get_ip_comments(self, ip: str, limit: int) -> dict:
        """
        See Also:
            https://gtidocs.virustotal.com/reference/ip-comments-get
        """

        return self._http_request("GET", f"ip_addresses/{ip}/comments", params={"limit": limit})

    def get_url_comments(self, url: str, limit: int) -> dict:
        """
        See Also:
            https://gtidocs.virustotal.com/reference/urls-comments-get

        """
        return self._http_request("GET", f"urls/{encode_url_to_base64(url)}/comments", params={"limit": limit})

    def get_hash_comments(self, file_hash: str, limit: int) -> dict:
        """
        See Also:
            https://gtidocs.virustotal.com/reference/files-comments-get
        """
        return self._http_request("GET", f"files/{file_hash}/comments", params={"limit": limit})

    def get_domain_comments(self, domain: str, limit: int) -> dict:
        """
        See Also:
            https://gtidocs.virustotal.com/reference/domains-comments-get
        """
        return self._http_request("GET", f"domains/{domain}/comments", params={"limit": limit})

    def get_comment_by_id(self, comment_id: str) -> dict:
        """
        See Also:
            https://gtidocs.virustotal.com/reference/get-comment
        """
        return self._http_request("GET", f"comments/{comment_id}")

    def add_comment(self, suffix: str, comment: str) -> dict:
        """Sending POST HTTP request to comment

        Args:
            suffix: suffix of the comment
            comment: the comment itself

        Returns:
            json of response
        """
        return self._http_request("POST", suffix, json_data={"data": {"type": "comment", "attributes": {"text": comment}}})

    def add_comment_to_ip(self, ip: str, comment: str) -> dict:
        """
        See Also:
            https://gtidocs.virustotal.com/reference/ip-comments-post
        """
        return self.add_comment(f"ip_addresses/{ip}/comments", comment)

    def add_comment_to_url(self, url: str, comment: str) -> dict:
        """
        See Also:
            https://gtidocs.virustotal.com/reference/urls-comments-post
        """
        return self.add_comment(f"urls/{encode_url_to_base64(url)}/comments", comment)

    def add_comment_to_domain(self, domain: str, comment: str) -> dict:
        """
        See Also:
            https://gtidocs.virustotal.com/reference/domains-comments-post
        """
        return self.add_comment(f"domains/{domain}/comments", comment)

    def add_comment_to_file(self, resource: str, comment: str) -> dict:
        """
        See Also:
            https://gtidocs.virustotal.com/reference/files-comments-post
        """
        return self.add_comment(f"files/{resource}/comments", comment)

    # endregion

    # region Scan calls
    def file_rescan(self, file_hash: str) -> dict:
        """
        See Also:
            https://gtidocs.virustotal.com/reference/files-analyse
        """
        return self._http_request("POST", f"/files/{file_hash}/analyse")

    def file_scan(self, file_path: str, /, upload_url: Optional[str]) -> dict:
        """
        See Also:
            https://gtidocs.virustotal.com/reference/files-analyse
        """
        response: requests.Response
        with open(file_path, "rb") as file:
            if upload_url or os.stat(file_path).st_size / (1024 * 1024) >= 32:
                if not upload_url:
                    raw_response = self.get_upload_url()
                    upload_url = raw_response["data"]
                response = self._http_request("POST", full_url=upload_url, files={"file": file}, resp_type="response")
            else:
                response = self._http_request("POST", url_suffix="/files", files={"file": file}, resp_type="response")
        demisto.debug(f"scan_file response:\n{response.status_code=!s}, {response.headers=!s}, {response.content!s}")
        return response.json()

    def private_file_scan(self, file_path: str) -> dict:
        """
        See Also:
            https://gtidocs.virustotal.com/reference/post_files-1
        """
        response: requests.Response
        with open(file_path, "rb") as file:
            if os.stat(file_path).st_size / (1024 * 1024) >= 32:
                raw_response = self.get_private_upload_url()
                upload_url = raw_response["data"]
                response = self._http_request("POST", full_url=upload_url, files={"file": file}, resp_type="response")
            else:
                response = self._http_request("POST", url_suffix="/private/files", files={"file": file}, resp_type="response")
        demisto.debug(f"scan_private_file response:\n{response.status_code=!s}, {response.headers=!s}, {response.content!s}")
        return response.json()

    def get_upload_url(self) -> dict:
        """
        See Also:
            https://gtidocs.virustotal.com/reference/files-upload-url
        """
        return self._http_request("GET", "files/upload_url")

    def get_private_upload_url(self) -> dict:
        """
        See Also:
            https://gtidocs.virustotal.com/reference/private-files-upload-url
        """
        return self._http_request("GET", "private/files/upload_url")

    def url_scan(self, url: str) -> dict:
        """
        See Also:
            https://gtidocs.virustotal.com/reference/urls-analyse
        """
        return self._http_request("POST", "urls", data={"url": url})

    def private_url_scan(self, url: str) -> dict:
        """
        See Also:
            https://gtidocs.virustotal.com/reference/private-scan-url
        """
        return self._http_request("POST", "/private/urls", data={"url": url})

    # endregion

    def file_sandbox_report(self, file_hash: dict, limit: int) -> dict:
        """
        See Also:
            https://gtidocs.virustotal.com/reference/files-relationships
        """
        return self._http_request("GET", f"files/{file_hash}/behaviours", params={"limit": limit}, ok_codes=(404, 429, 200))

    def passive_dns_data(self, id: dict, limit: int) -> dict:
        """
        See Also:
            https://gtidocs.virustotal.com/reference/ip-relationships
        """
        return self._http_request(
            "GET", f'{"ip_addresses" if id["type"] == "ip" else "domains"}/{id["value"]}/resolutions', params={"limit": limit}
        )

    def search(self, query: str, limit: int) -> dict:
        """
        See Also:
            https://gtidocs.virustotal.com/reference/intelligence-search
        """
        return self._http_request("GET", "search", params={"query": query, "limit": limit})

    def get_analysis(self, analysis_id: str) -> dict:
        """
        See Also:
            https://gtidocs.virustotal.com/reference/analysis
        """
        return self._http_request("GET", f"/analyses/{analysis_id}")

    def get_private_analysis(self, analysis_id: str) -> dict:
        """
        See Also:
            https://gtidocs.virustotal.com/reference/private-analysis
        """
        return self._http_request("GET", f"private/analyses/{analysis_id}")

    def get_private_item_from_analysis(self, analysis_id: str) -> dict:
        """
        See Also:
            https://gtidocs.virustotal.com/reference/analysesidrelationship
        """
        return self._http_request("GET", f"private/analyses/{analysis_id}/item")

    def get_file_sigma_analysis(self, file_hash: str) -> dict:
        """
        See Also:
            https://gtidocs.virustotal.com/reference/files-relationships
        """
        return self._http_request(
            "GET",
            f"files/{file_hash}/sigma_analysis",
        )

    def curated_collections(self, resource_id: str, resource_type: str, collection_type: str) -> dict:
        """Returns curated collections."""
        if resource_type not in TYPE_TO_ENDPOINT:
            raise DemistoException(f'Could not find resource type of "{resource_type}"')
        if collection_type not in ("campaign", "malware-family", "threat-actor"):
            raise DemistoException(f'Could not find collection type of "{collection_type}"')

        if resource_type == "url":
            resource_id = encode_url_to_base64(resource_id)

        collection_type_filter = f"collection_type:{collection_type}"
        if collection_type == "malware-family":
            collection_type_filter = f"({collection_type_filter} OR collection_type:software-tookit)"

        return self._http_request(
            "GET",
            f"{TYPE_TO_ENDPOINT[resource_type]}/{resource_id}/associations",
            params={
                "filter": f"owner:Mandiant {collection_type_filter}",
                "exclude_attributes": "aggregations",
            },
            ok_codes=(404, 429, 200),
        )


class ScoreCalculator:
    """
    Calculating DBotScore of files, ip, etc.
    """

    DEFAULT_SUSPICIOUS_THRESHOLD = 5
    DEFAULT_RELATIONSHIP_SUSPICIOUS_THRESHOLD = 2
    GTI_MALICIOUS_VERDICT = "VERDICT_MALICIOUS"
    GTI_SUSPICIOUS_VERDICT = "VERDICT_SUSPICIOUS"

    logs: List[str]

    # General
    trusted_vendors_threshold: int
    trusted_vendors: List[str]
    gti_malicious: bool
    gti_suspicious: bool

    # IP
    ip_threshold: dict[str, int]

    # URL
    url_threshold: dict[str, int]

    # Domain
    domain_threshold: dict[str, int]
    domain_popularity_ranking: int

    # File
    file_threshold: dict[str, int]
    sigma_ids_threshold: int
    crowdsourced_yara_rules_enabled: bool
    crowdsourced_yara_rules_threshold: int

    def __init__(self, params: dict):
        self.trusted_vendors = argToList(params["preferredVendors"])
        self.trusted_vendors_threshold = arg_to_number_must_int(
            params["preferredVendorsThreshold"], arg_name="Preferred Vendor Threshold", required=True
        )
        self.file_threshold = {
            "malicious": arg_to_number_must_int(params["fileThreshold"], arg_name="File Malicious Threshold", required=True),
            "suspicious": arg_to_number_must_int(
                params["fileSuspiciousThreshold"] or self.DEFAULT_SUSPICIOUS_THRESHOLD,
                arg_name="File Suspicious Threshold",
                required=True,
            ),
        }
        self.ip_threshold = {
            "malicious": arg_to_number_must_int(params["ipThreshold"], arg_name="IP Malicious Threshold", required=True),
            "suspicious": arg_to_number_must_int(
                params["ipSuspiciousThreshold"] or self.DEFAULT_SUSPICIOUS_THRESHOLD,
                arg_name="IP Suspicious Threshold",
                required=True,
            ),
        }
        self.url_threshold = {
            "malicious": arg_to_number_must_int(params["urlThreshold"], arg_name="URL Malicious Threshold", required=True),
            "suspicious": arg_to_number_must_int(
                params["urlSuspiciousThreshold"] or self.DEFAULT_SUSPICIOUS_THRESHOLD,
                arg_name="URL Suspicious Threshold",
                required=True,
            ),
        }
        self.domain_threshold = {
            "malicious": arg_to_number_must_int(params["domainThreshold"], arg_name="Domain Malicious Threshold", required=True),
            "suspicious": arg_to_number_must_int(
                params["domainSuspiciousThreshold"] or self.DEFAULT_SUSPICIOUS_THRESHOLD,
                arg_name="Domain Suspicious Threshold",
                required=True,
            ),
        }
        self.crowdsourced_yara_rules_enabled = argToBoolean(params["crowdsourced_yara_rules_enabled"])
        self.crowdsourced_yara_rules_threshold = arg_to_number_must_int(params["yaraRulesThreshold"])
        self.sigma_ids_threshold = arg_to_number_must_int(
            params["SigmaIDSThreshold"], arg_name="Sigma and Intrusion Detection Rules Threshold", required=True
        )
        self.domain_popularity_ranking = arg_to_number_must_int(
            params["domain_popularity_ranking"], arg_name="Domain Popularity Ranking Threshold", required=True
        )
        self.gti_malicious = argToBoolean(params.get("gti_malicious", False))
        self.gti_suspicious = argToBoolean(params.get("gti_suspicious", False))
        self.logs = []

    def get_logs(self) -> str:
        """Returns the log string"""
        return "\n".join(self.logs)

    def _is_by_threshold(self, analysis_stats: dict, threshold: int, suspicious: bool = False) -> bool:
        """Determines whatever the indicator malicious/suspicious by threshold.
        if number of malicious (+ suspicious) >= threshold -> Malicious (Suspicious)

        Args:
            analysis_stats: the analysis stats from the response.
            threshold: the threshold of the indicator type.
            suspicious: whether suspicious is also added.

        Returns:
            Whatever the indicator is malicious/suspicious by threshold.
        """
        total = analysis_stats.get("malicious", 0)
        if suspicious:
            total += analysis_stats.get("suspicious", 0)
        verdict = "suspicious" if suspicious else "malicious"
        self.logs.append(f"{total} vendors found {verdict}.\nThe {verdict} threshold is {threshold}.")
        if total >= threshold:
            self.logs.append(f"Found as {verdict}: {total} >= {threshold}.")
            return True
        self.logs.append(f"Not found {verdict} by threshold: {total} < {threshold}.")
        return False

    def is_suspicious_by_threshold(self, analysis_stats: dict, threshold: int) -> bool:
        """Determines whatever the indicator suspicious by threshold.
        if number of malicious + suspicious >= threshold -> Suspicious

        Args:
            analysis_stats: the analysis stats from the response
            threshold: the threshold of the indicator type.

        Returns:
            Whatever the indicator is suspicious by threshold.
        """
        return self._is_by_threshold(analysis_stats, threshold, suspicious=True)

    def is_good_by_popularity_ranks(self, popularity_ranks: dict) -> Optional[bool]:
        """Analyzing popularity ranks.
        if popularity ranks exist and average rank is < threshold -> Good
        Args:
            popularity_ranks: the popularity ranks object from response

        Returns:
            Whatever the indicator is good or not by popularity rank.
        """
        if popularity_ranks:
            self.logs.append("Found popularity ranks. Analyzing.")
            average = sum(rank.get("rank", 0) for rank in popularity_ranks.values()) / len(popularity_ranks)
            self.logs.append(f"The average of the ranks is {average} and the threshold is {self.domain_popularity_ranking}")
            if average <= self.domain_popularity_ranking:
                self.logs.append("Indicator is good by popularity ranks.")
                return True
            else:
                self.logs.append("Indicator might not be good by it's popularity ranks.")
                return False
        self.logs.append("Could not determine rank by popularity, No popularity ranks data.")
        return None

    def is_suspicious_by_rules(self, file_response: dict) -> bool:
        """Check if indicator is suspicious by rules analysis.

        crowdsourced_yara_results >= yara_rules_threshold ||
        sigma_analysis_stats.high + critical >= sigma_id_threshold ||
        crowdsourced_ids_stats.high + critical >= sigma_id_threshold -> suspicious

        Args:
            file_response: the file response

        Returns:
            Whatever the file is suspicious by rules analysis.
        """
        data = file_response.get("data", {})
        if self.crowdsourced_yara_rules_enabled:
            self.logs.append("Crowdsourced Yara Rules analyzing enabled.")
            if (total_yara_rules := len(data.get("crowdsourced_yara_results", []))) >= self.crowdsourced_yara_rules_threshold:
                self.logs.append(
                    "Found malicious by finding more Crowdsourced Yara Rules than threshold. \n"
                    f"{total_yara_rules} >= {self.crowdsourced_yara_rules_threshold}"
                )
                return True
            if sigma_rules := data.get("sigma_analysis_stats"):
                self.logs.append("Found sigma rules, analyzing.")
                sigma_high, sigma_critical = sigma_rules.get("high", 0), sigma_rules.get("critical", 0)
                if (sigma_high + sigma_critical) >= self.sigma_ids_threshold:
                    self.logs.append(f"Found malicious, {sigma_high + sigma_critical} >= {self.sigma_ids_threshold}. ")
                    return True
                else:
                    self.logs.append("Not found malicious by sigma. ")
            else:
                self.logs.append("Not found sigma analysis. Skipping. ")
            if crowdsourced_ids_stats := data.get("crowdsourced_ids_stats"):
                self.logs.append("Found crowdsourced IDS analysis, analyzing. ")
                ids_high, ids_critical = crowdsourced_ids_stats.get("high"), crowdsourced_ids_stats.get("critical")
                if (ids_high + ids_critical) >= self.sigma_ids_threshold:
                    self.logs.append(f"Found malicious, {(ids_high + ids_critical) >= self.sigma_ids_threshold}.")
                    return True
                else:
                    self.logs.append("Not found malicious by sigma.")
            else:
                self.logs.append("Not found crowdsourced IDS analysis. Skipping.")
        else:
            self.logs.append("Crowdsourced Yara Rules analyzing is not enabled. Skipping.")
        return False

    def is_preferred_vendors_pass_malicious(self, analysis_results: dict) -> bool:
        """Is the indicator counts as malicious by predefined malicious vendors.
        trusted_vendors.malicious >= trusted_vendors_threshold -> Malicious
        The function takes only the latest 20 results.

        Args:
            analysis_results: The results of the analysis.

        Returns:
            Whatever the indicator is malicious or not by preferred vendors.
        """
        recent = {key: analysis_results[key] for key in list(analysis_results.keys())[:20]}
        preferred_vendor_scores = {vendor: recent[vendor] for vendor in self.trusted_vendors if vendor in recent}
        malicious_trusted_vendors = [item for item in preferred_vendor_scores.values() if item.get("category") == "malicious"]
        if len(malicious_trusted_vendors) >= self.trusted_vendors_threshold:
            self.logs.append(
                f"{len(malicious_trusted_vendors)} trusted vendors found the hash malicious. \n"
                f"The trusted vendors threshold is {self.trusted_vendors_threshold}. \n"
                f"Malicious check: {(len(malicious_trusted_vendors) >= self.trusted_vendors_threshold)=}. "
            )
            return True
        else:
            self.logs.append(
                f"Those preferred vendors found the hash malicious: {malicious_trusted_vendors}. "
                f"They do not pass the threshold {self.trusted_vendors_threshold}. "
            )
            return False

    def is_malicious_by_threshold(self, analysis_stats: dict, threshold: int) -> bool:
        """Determines whatever the indicator malicious by threshold.
        if number of malicious >= threshold -> Malicious

        Args:
            analysis_stats: the analysis stats from the response
            threshold: the threshold of the indicator type.

        Returns:
            Whatever the indicator is malicious by threshold.
        """
        return self._is_by_threshold(analysis_stats, threshold)

    def score_by_threshold(self, analysis_stats: dict, threshold: dict[str, int]) -> int:
        """Determines the DBOTSCORE of the indicator by threshold only.

        Returns:
            DBotScore of the indicator. Can by Common.DBotScore.BAD, Common.DBotScore.SUSPICIOUS or
            Common.DBotScore.GOOD
        """
        if self.is_malicious_by_threshold(analysis_stats, threshold["malicious"]):
            return Common.DBotScore.BAD
        if self.is_suspicious_by_threshold(analysis_stats, threshold["suspicious"]):
            return Common.DBotScore.SUSPICIOUS
        return Common.DBotScore.GOOD

    def score_by_results_and_stats(self, indicator: str, raw_response: dict, threshold: dict[str, int]) -> int:
        """Determines indicator score by popularity preferred vendors and threshold.

        Args:
            indicator: The indicator we analyzing.
            raw_response: The raw response from API.
            threshold: Threshold of the indicator.

        Returns:
            DBotScore of the indicator. Can by Common.DBotScore.BAD, Common.DBotScore.SUSPICIOUS or
            Common.DBotScore.GOOD
        """
        self.logs.append(f'Basic analyzing of "{indicator}"')
        data = raw_response.get("data", {})
        attributes = data.get("attributes", {})
        popularity_ranks = attributes.get("popularity_ranks")
        last_analysis_results = attributes.get("last_analysis_results")
        last_analysis_stats = attributes.get("last_analysis_stats")
        if self.is_good_by_popularity_ranks(popularity_ranks):
            return Common.DBotScore.GOOD
        if self.is_preferred_vendors_pass_malicious(last_analysis_results):
            return Common.DBotScore.BAD
        return self.score_by_threshold(last_analysis_stats, threshold)

    def is_malicious_by_gti(self, gti_assessment: dict) -> bool:
        """Determines if an IoC is malicious according to its GTI assessment."""
        if self.gti_malicious:
            return gti_assessment.get("verdict", {}).get("value") == self.GTI_MALICIOUS_VERDICT
        return False

    def is_suspicious_by_gti(self, gti_assessment: dict) -> bool:
        """Determines if an IoC is suspicious according to its GTI assessment."""
        if self.gti_suspicious:
            return gti_assessment.get("verdict", {}).get("value") == self.GTI_SUSPICIOUS_VERDICT
        return False

    def file_score(self, given_hash: str, raw_response: dict) -> int:
        """Analyzing file score.
        The next parameters are analyzed:
            Preferred vendors
            Score by threshold
            Score by rules analysis (YARA, IDS and Sigma, if presents)

        Args:
            given_hash: The hash we're analyzing
            raw_response: The response from the API

        Returns:
            DBotScore of the indicator. Can by Common.DBotScore.BAD, Common.DBotScore.SUSPICIOUS or
            Common.DBotScore.GOOD
        """
        self.logs.append(f"Analysing file hash {given_hash}.")
        data = raw_response.get("data", {})
        attributes = data.get("attributes", {})
        analysis_results = attributes.get("last_analysis_results", {})
        analysis_stats = attributes.get("last_analysis_stats", {})

        # GTI assessment
        if self.is_malicious_by_gti(attributes.get("gti_assessment", {})):
            return Common.DBotScore.BAD

        # Trusted vendors
        if self.is_preferred_vendors_pass_malicious(analysis_results):
            return Common.DBotScore.BAD

        score = self.score_by_threshold(analysis_stats, self.file_threshold)
        if score == Common.DBotScore.BAD:
            return Common.DBotScore.BAD

        suspicious_by_rules = self.is_suspicious_by_rules(raw_response)
        if score == Common.DBotScore.SUSPICIOUS and suspicious_by_rules:
            self.logs.append(
                f'Hash: "{given_hash}" was found malicious as the hash is suspicious both by threshold and rules analysis.'
            )
            return Common.DBotScore.BAD
        elif suspicious_by_rules:
            self.logs.append(f'Hash: "{given_hash}" was found suspicious by rules analysis.')
            return Common.DBotScore.SUSPICIOUS
        elif score == Common.DBotScore.SUSPICIOUS:
            self.logs.append(f'Hash: "{given_hash}" was found suspicious by passing the threshold analysis.')
            return Common.DBotScore.SUSPICIOUS
        elif self.is_suspicious_by_gti(attributes.get("gti_assessment", {})):
            self.logs.append(f'Hash: "{given_hash}" was found suspicious by gti assessment.')
            return Common.DBotScore.SUSPICIOUS
        self.logs.append(f'Hash: "{given_hash}" was found good.')
        return Common.DBotScore.GOOD  # Nothing caught

    def ip_score(self, indicator: str, raw_response: dict) -> int:
        """Determines indicator score by popularity preferred vendors and threshold.

        Args:
            indicator: The indicator we analyzing.
            raw_response: The response from the API

        Returns:
            DBotScore of the indicator. Can by Common.DBotScore.BAD, Common.DBotScore.SUSPICIOUS or
            Common.DBotScore.GOOD
        """
        data = raw_response.get("data", {})
        attributes = data.get("attributes", {})

        # GTI assessment
        if self.is_malicious_by_gti(attributes.get("gti_assessment", {})):
            return Common.DBotScore.BAD

        score = self.score_by_results_and_stats(indicator, raw_response, self.ip_threshold)
        if score == Common.DBotScore.GOOD and self.is_suspicious_by_gti(attributes.get("gti_assessment", {})):
            score = Common.DBotScore.SUSPICIOUS

        return score

    def url_score(self, indicator: str, raw_response: dict) -> int:
        """Determines indicator score by popularity preferred vendors and threshold.

        Args:
            indicator: The indicator we analyzing.
            raw_response: The raw response from API.

        Returns:
            DBotScore of the indicator. Can by Common.DBotScore.BAD, Common.DBotScore.SUSPICIOUS or
            Common.DBotScore.GOOD
        """
        data = raw_response.get("data", {})
        attributes = data.get("attributes", {})

        # GTI assessment
        if self.is_malicious_by_gti(attributes.get("gti_assessment", {})):
            return Common.DBotScore.BAD

        score = self.score_by_results_and_stats(indicator, raw_response, self.url_threshold)
        if score == Common.DBotScore.GOOD and self.is_suspicious_by_gti(attributes.get("gti_assessment", {})):
            score = Common.DBotScore.SUSPICIOUS

        return score

    def domain_score(self, indicator: str, raw_response: dict) -> int:
        """Determines indicator score by popularity preferred vendors and threshold.

        Args:
            indicator: The indicator we analyzing.
            raw_response: The raw response from API.

        Returns:
            DBotScore of the indicator. Can by Common.DBotScore.BAD, Common.DBotScore.SUSPICIOUS or
            Common.DBotScore.GOOD
        """
        data = raw_response.get("data", {})
        attributes = data.get("attributes", {})

        if self.is_malicious_by_gti(attributes.get("gti_assessment", {})):
            return Common.DBotScore.BAD

        score = self.score_by_results_and_stats(indicator, raw_response, self.domain_threshold)
        if score == Common.DBotScore.GOOD and self.is_suspicious_by_gti(attributes.get("gti_assessment", {})):
            score = Common.DBotScore.SUSPICIOUS

        return score

    def calculate_cve_dbot_score(self, cvss_score) -> int:
        """Calculates the DBotScore for a CVE based on its CVSS score.

        Args:
            cvss_score: The CVSS score of the CVE.

        Returns:
            DBotScore of the indicator. Can by Common.DBotScore.BAD, Common.DBotScore.SUSPICIOUS or
            Common.DBotScore.GOOD
        """
        try:
            score = float(cvss_score)
        except ValueError:
            return Common.DBotScore.NONE
        if not score:
            return Common.DBotScore.NONE
        elif 0.0 <= score <= 3.9:
            return Common.DBotScore.GOOD
        elif 3.9 < score <= 7.9:
            return Common.DBotScore.SUSPICIOUS
        elif 7.9 < score <= 10.0:
            return Common.DBotScore.BAD
        else:
            return Common.DBotScore.NONE

    # endregion


# region Helper functions


def create_relationships(entity_a: str, entity_a_type: str, relationships_response: dict, reliability):
    """
    Create a list of entityRelationship object from the api result
    entity_a: (str) - source of the relationship
    entity_a_type: (str) - type of the source of the relationship
    relationships_response: (dict) - the relationship response from the api
    reliability: The reliability of the source.

    Returns a list of EntityRelationship objects.
    """
    relationships_list: List[EntityRelationship] = []
    for relationship_type, relationship_type_raw in relationships_response.items():
        relationships_data = relationship_type_raw.get("data", [])
        if relationships_data:
            if isinstance(relationships_data, dict):
                relationships_data = [relationships_data]

            for relation in relationships_data:
                name = RELATIONSHIP_TYPE.get(entity_a_type.lower(), {}).get(relationship_type)
                entity_b = relation.get("id", "")
                entity_b_type = INDICATOR_TYPE.get(relation.get("type", "").lower())
                if entity_b and entity_b_type and name:
                    if entity_b_type == FeedIndicatorType.URL:
                        entity_b = dict_safe_get(relation, ["context_attributes", "url"])
                    relationships_list.append(
                        EntityRelationship(
                            entity_a=entity_a,
                            entity_a_type=entity_a_type,
                            name=name,
                            entity_b=entity_b,
                            entity_b_type=entity_b_type,
                            source_reliability=reliability,
                            brand=INTEGRATION_NAME,
                        )
                    )
                else:
                    demisto.info(
                        f"WARNING: Relationships will not be created to entity A {entity_a} with relationship name {name}"
                    )
    return relationships_list


def create_relationships_cve(
    entity_a: str, entity_a_type: str, relationships_response: dict, reliability: DBotScoreReliability
) -> List[EntityRelationship]:
    """
    Create relationships between CVE and related files (MD5 hashes from sources)

    Args:
        entity_a (str): The source of the relationship
        entity_a_type (str): The type of the source of the relationship
        relationships_response (dict): The relationship response from the api
        reliability (DBotScoreReliability): The reliability of the source.

    Returns:
        List[EntityRelationship]: List of EntityRelationship objects
    """
    relationships_list: List[EntityRelationship] = []

    # Extract sources from CVE response
    sources = relationships_response.get("data", {}).get("attributes", {}).get("sources", [])

    for source in sources:
        md5_hash = source.get("md5")

        if md5_hash:  # Only create relationship if MD5 exists
            relationships_list.append(
                EntityRelationship(
                    entity_a=entity_a,
                    entity_a_type=entity_a_type,
                    name=RELATIONSHIP_TYPE.get("cve", {}).get("referrer_cve"),
                    entity_b=md5_hash,
                    entity_b_type=FeedIndicatorType.File,
                    source_reliability=reliability,
                    brand=INTEGRATION_NAME,
                )
            )

    return relationships_list


def arg_to_number_must_int(arg: Any, arg_name: Optional[str] = None, required: bool = False):
    """Wrapper of arg_to_number that must return int
    For mypy fixes.
    """
    arg_num = arg_to_number(arg, arg_name, required)
    assert isinstance(arg_num, int)
    return arg_num


def epoch_to_timestamp(epoch: Union[int, str]) -> Optional[str]:
    """Converts epoch timestamp to a string.

    Args:
        epoch: Time to convert

    Returns:
        A formatted string if succeeded. if not, returns None.
    """
    try:
        return datetime.utcfromtimestamp(int(epoch)).strftime("%Y-%m-%d %H:%M:%SZ")
    except (TypeError, OSError, ValueError):
        return None


def decrease_data_size(data: Union[dict, list]) -> Union[dict, list]:
    """Minifying data size.

    Args:
        data: the data object from raw response

    Returns:
        the same data without:
            data['attributes']['last_analysis_results']
            data['attributes']['pe_info']
            data['attributes']['crowdsourced_ids_results']
            data['attributes']['autostart_locations']
            data['attributes']['sandbox_verdicts']
            data['attributes']['sigma_analysis_summary']
    """
    attributes_to_remove = [
        "last_analysis_results",
        "pe_info",
        "crowdsourced_ids_results",
        "autostart_locations",
        "sandbox_verdicts",
        "sigma_analysis_summary",
    ]
    if isinstance(data, list):
        data = [decrease_data_size(item) for item in data]
    else:
        for attribute in attributes_to_remove:
            data["attributes"].pop(attribute, None)
    return data


def _get_error_result(client: Client, ioc_id: str, ioc_type: str, message: str) -> CommandResults:
    dbot_type = ioc_type.upper()
    assert dbot_type in ("FILE", "DOMAIN", "IP", "URL", "CVE")
    common_type = dbot_type if dbot_type in ("IP", "URL", "CVE") else dbot_type.capitalize()
    desc = f'{common_type} "{ioc_id}" {message}'
    dbot = Common.DBotScore(
        ioc_id, getattr(DBotScoreType, dbot_type), INTEGRATION_NAME, Common.DBotScore.NONE, desc, client.reliability
    )
    options: dict[str, Common.DBotScore | str] = {"dbot_score": dbot}
    if dbot_type == "FILE":
        if (hash_type := get_hash_type(ioc_id)) != "Unknown":
            options[hash_type] = ioc_id
    elif dbot_type == "CVE":
        options.update({"id": ioc_id, "cvss": "0.0", "published": "", "modified": "", "description": desc})
    else:
        options[dbot_type.lower()] = ioc_id
    return CommandResults(indicator=getattr(Common, common_type)(**options), readable_output=desc)


def build_unknown_output(client: Client, ioc_id: str, ioc_type: str) -> CommandResults:
    return _get_error_result(client, ioc_id, ioc_type, "was not found in GoogleThreatIntelligence.")


def build_quota_exceeded_output(client: Client, ioc_id: str, ioc_type: str) -> CommandResults:
    return _get_error_result(client, ioc_id, ioc_type, "was not enriched. Quota was exceeded.")


def build_error_output(client: Client, ioc_id: str, ioc_type: str, error_msg: str = None) -> CommandResults:
    msg = "could not be processed."
    if error_msg:
        msg += f" Error: {error_msg}"
    return _get_error_result(client, ioc_id, ioc_type, msg)


def build_unknown_file_output(client: Client, file: str) -> CommandResults:
    return build_unknown_output(client, file, "file")


def build_quota_exceeded_file_output(client: Client, file: str) -> CommandResults:
    return build_quota_exceeded_output(client, file, "file")


def build_error_file_output(client: Client, file: str, error_msg: str = None) -> CommandResults:
    return build_error_output(client, file, "file", error_msg)


def build_unknown_domain_output(client: Client, domain: str) -> CommandResults:
    return build_unknown_output(client, domain, "domain")


def build_quota_exceeded_domain_output(client: Client, domain: str) -> CommandResults:
    return build_quota_exceeded_output(client, domain, "domain")


def build_error_domain_output(client: Client, domain: str, error_msg: str = None) -> CommandResults:
    return build_error_output(client, domain, "domain", error_msg)


def build_unknown_url_output(client: Client, url: str) -> CommandResults:
    return build_unknown_output(client, url, "url")


def build_quota_exceeded_url_output(client: Client, url: str) -> CommandResults:
    return build_quota_exceeded_output(client, url, "url")


def build_error_url_output(client: Client, url: str, error_msg: str = None) -> CommandResults:
    return build_error_output(client, url, "url", error_msg)


def build_unknown_ip_output(client: Client, ip: str) -> CommandResults:
    return build_unknown_output(client, ip, "ip")


def build_quota_exceeded_ip_output(client: Client, ip: str) -> CommandResults:
    return build_quota_exceeded_output(client, ip, "ip")


def build_error_ip_output(client: Client, ip: str, error_msg: str = None) -> CommandResults:
    return build_error_output(client, ip, "ip", error_msg)


def build_skipped_enrichment_ip_output(client: Client, ip: str) -> CommandResults:
    return _get_error_result(
        client, ip, "ip", "was not enriched. Reputation lookups have been disabled for private IP addresses."
    )


def build_unknown_cve_output(client: Client, cve_id: str) -> CommandResults:
    return build_unknown_output(client, cve_id, "cve")


def build_quota_exceeded_cve_output(client: Client, cve_id: str) -> CommandResults:
    return build_quota_exceeded_output(client, cve_id, "cve")


def build_error_cve_output(client: Client, cve_id: str, error_msg: str = None) -> CommandResults:
    return build_error_output(client, cve_id, "cve", error_msg)


def _get_domain_indicator(client: Client, score_calculator: ScoreCalculator, domain: str, raw_response: dict):
    data = raw_response.get("data", {})
    attributes = data.get("attributes", {})
    last_analysis_stats = attributes.get("last_analysis_stats", {})
    detection_engines = sum(last_analysis_stats.values())
    positive_detections = last_analysis_stats.get("malicious", 0)
    whois = get_whois(attributes.get("whois", ""))

    relationships_response = data.get("relationships", {})
    relationships_list = create_relationships(
        entity_a=domain,
        entity_a_type=FeedIndicatorType.Domain,
        relationships_response=relationships_response,
        reliability=client.reliability,
    )

    score = score_calculator.domain_score(domain, raw_response)

    logs = score_calculator.get_logs()
    demisto.debug(logs)

    return Common.Domain(
        domain=domain,
        name_servers=whois["Name Server"],
        creation_date=whois["Creation Date"],
        updated_date=whois["Updated Date"],
        expiration_date=whois["Registry Expiry Date"],
        admin_name=whois["Admin Organization"],
        admin_email=whois["Admin Email"],
        admin_country=whois["Admin Country"],
        registrant_email=whois["Registrant Email"],
        registrant_country=whois["Registrant Country"],
        registrar_name=whois["Registrar"],
        registrar_abuse_email=whois["Registrar Abuse Contact Email"],
        registrar_abuse_phone=whois["Registrar Abuse Contact Phone"],
        detection_engines=detection_engines,
        positive_detections=positive_detections,
        dbot_score=Common.DBotScore(
            domain,
            DBotScoreType.DOMAIN,
            INTEGRATION_NAME,
            score=score,
            malicious_description=logs,
            reliability=client.reliability,
        ),
        relationships=relationships_list,
    )


def _get_url_indicator(client: Client, score_calculator: ScoreCalculator, url: str, raw_response: dict):
    data = raw_response.get("data", {})
    attributes = data.get("attributes", {})
    last_analysis_stats = attributes.get("last_analysis_stats", {})
    detection_engines = sum(last_analysis_stats.values())
    positive_detections = last_analysis_stats.get("malicious", 0)

    relationships_response = data.get("relationships", {})
    relationships_list = create_relationships(
        entity_a=url,
        entity_a_type=FeedIndicatorType.URL,
        relationships_response=relationships_response,
        reliability=client.reliability,
    )

    score = score_calculator.url_score(url, raw_response)

    logs = score_calculator.get_logs()
    demisto.debug(logs)

    return Common.URL(
        url,
        category=attributes.get("categories"),
        detection_engines=detection_engines,
        positive_detections=positive_detections,
        relationships=relationships_list,
        dbot_score=Common.DBotScore(
            url, DBotScoreType.URL, INTEGRATION_NAME, score=score, reliability=client.reliability, malicious_description=logs
        ),
    )


def _get_ip_indicator(client: Client, score_calculator: ScoreCalculator, ip: str, raw_response: dict):
    data = raw_response.get("data", {})
    attributes = data.get("attributes", {})
    last_analysis_stats = attributes.get("last_analysis_stats", {})
    detection_engines = sum(last_analysis_stats.values())
    positive_engines = last_analysis_stats.get("malicious", 0)

    relationships_response = data.get("relationships", {})
    relationships_list = create_relationships(
        entity_a=ip,
        entity_a_type=FeedIndicatorType.IP,
        relationships_response=relationships_response,
        reliability=client.reliability,
    )

    score = score_calculator.ip_score(ip, raw_response)

    logs = score_calculator.get_logs()
    demisto.debug(logs)

    return Common.IP(
        ip,
        asn=attributes.get("asn"),
        geo_country=attributes.get("country"),
        detection_engines=detection_engines,
        positive_engines=positive_engines,
        as_owner=attributes.get("as_owner"),
        relationships=relationships_list,
        dbot_score=Common.DBotScore(
            ip, DBotScoreType.IP, INTEGRATION_NAME, score=score, malicious_description=logs, reliability=client.reliability
        ),
    )


def _get_file_indicator(client: Client, score_calculator: ScoreCalculator, file_hash: str, raw_response: dict):
    data = raw_response.get("data", {})
    attributes = data.get("attributes", {})
    exiftool = attributes.get("exiftool", {})
    signature_info = attributes.get("signature_info", {})

    score = score_calculator.file_score(file_hash, raw_response)

    logs = score_calculator.get_logs()
    demisto.debug(logs)

    relationships_response = data.get("relationships", {})
    relationships_list = create_relationships(
        entity_a=file_hash,
        entity_a_type=FeedIndicatorType.File,
        relationships_response=relationships_response,
        reliability=client.reliability,
    )

    return Common.File(
        dbot_score=Common.DBotScore(
            file_hash,
            DBotScoreType.FILE,
            integration_name=INTEGRATION_NAME,
            score=score,
            malicious_description=logs,
            reliability=client.reliability,
        ),
        name=exiftool.get("OriginalFileName"),
        size=attributes.get("size"),
        sha1=attributes.get("sha1"),
        sha256=attributes.get("sha256"),
        file_type=exiftool.get("MIMEType"),
        md5=attributes.get("md5"),
        ssdeep=attributes.get("ssdeep"),
        extension=exiftool.get("FileTypeExtension"),
        company=exiftool.get("CompanyName"),
        product_name=exiftool.get("ProductName"),
        tags=attributes.get("tags"),
        signature=Common.FileSignature(
            authentihash=attributes.get("authentihash"),
            copyright=signature_info.get("copyright"),
            file_version=signature_info.get("file version"),
            description=signature_info.get("description"),
            internal_name=signature_info.get("internal name"),
            original_name=signature_info.get("original name"),
        ),
        relationships=relationships_list,
    )


def _extract_cve_data(raw_response: dict) -> dict:
    """
    Extract and process CVE data from API response.

    Args:
        raw_response: Raw API response from CVE endpoint

    Returns:
        Dictionary containing processed CVE data
    """
    data = raw_response.get("data", {})
    attributes = data.get("attributes", {})

    # Extract CVE-specific information
    description = attributes.get("description", "")
    executive_summary = attributes.get("executive_summary", "")

    # CVSS scores
    cvss = attributes.get("cvss", {})
    cvss_v3 = cvss.get("cvssv3_x", {})
    cvss_v4 = cvss.get("cvssv4_x", {})
    cvss_v3_score = cvss_v3.get("base_score", 0) if cvss_v3 else 0
    cvss_v4_score = cvss_v4.get("score", 0) if cvss_v4 else 0
    cvss_v3_vector = cvss_v3.get("vector", "") if cvss_v3 else ""
    cvss_v4_vector = cvss_v4.get("vector", "") if cvss_v4 else ""

    # Risk and exploitation information
    risk_rating = attributes.get("risk_rating", "")
    exploitation_state = attributes.get("exploitation_state", "")
    exploit_availability = attributes.get("exploit_availability", "")
    priority = attributes.get("priority", "")

    # Process dates
    creation_date = attributes.get("creation_date")
    date_of_disclosure = attributes.get("date_of_disclosure")
    last_modification_date = attributes.get("last_modification_date")

    if creation_date:
        creation_date = timestamp_to_datestring(creation_date * 1000)
    if last_modification_date:
        last_modification_date = timestamp_to_datestring(last_modification_date * 1000)
    if date_of_disclosure:
        date_of_disclosure = timestamp_to_datestring(date_of_disclosure * 1000)

    # Sources and counters
    sources = attributes.get("sources", [])
    tags = attributes.get("tags", [])
    counters = attributes.get("counters", {})

    extracted_data = {
        "description": description,
        "executive_summary": executive_summary,
        "cvss_v3_score": cvss_v3_score,
        "cvss_v4_score": cvss_v4_score,
        "cvss_v3_vector": cvss_v3_vector,
        "cvss_v4_vector": cvss_v4_vector,
        "risk_rating": risk_rating,
        "exploitation_state": exploitation_state,
        "exploit_availability": exploit_availability,
        "priority": priority,
        "creation_date": creation_date,
        "date_of_disclosure": date_of_disclosure,
        "last_modification_date": last_modification_date,
        "sources_count": len(sources),
        "tags": tags,
        "files_count": counters.get("files"),
        "domains_count": counters.get("domains"),
        "ip_addresses_count": counters.get("ip_addresses"),
        "urls_count": counters.get("urls"),
    }

    return extracted_data


def _create_cve_indicator(
    client: Client, score_calculator: ScoreCalculator, cve_id: str, cve_data: dict, raw_response: dict
) -> tuple[Common.CVE, list]:
    """
    Create CVE indicator with relationships and DBot score.

    Args:
        client: Client instance
        score_calculator: Score calculator instance
        cve_id: CVE identifier
        cve_data: Processed CVE data from _extract_cve_data
        raw_response: Raw API response

    Returns:
        Tuple of (CVE indicator, relationships list)
    """
    # Calculate DBot score
    cvss_score = cve_data.get("cvss_v4_score") if cve_data.get("cvss_v4_score") else cve_data.get("cvss_v3_score")
    score = score_calculator.calculate_cve_dbot_score(cvss_score)

    dbot_score = Common.DBotScore(
        indicator=cve_id,
        indicator_type=DBotScoreType.CVE,
        integration_name=INTEGRATION_NAME,
        score=score,
        reliability=client.reliability,
    )

    # Create relationships
    relationships = create_relationships_cve(
        entity_a=cve_id, entity_a_type=FeedIndicatorType.CVE, relationships_response=raw_response, reliability=client.reliability
    )

    # Create CVE indicator
    cve_indicator = Common.CVE(
        id=cve_id,
        cvss=str(cvss_score) if cvss_score else "0.0",
        published=cve_data.get("date_of_disclosure", ""),
        modified=cve_data.get("last_modification_date", ""),
        description=cve_data.get("description", "No description available"),
        cvss_vector=cve_data.get("cvss_v4_vector", "")
        if cve_data.get("cvss_v4_vector", "")
        else cve_data.get("cvss_v3_vector", ""),
        dbot_score=dbot_score,
        relationships=relationships,
        tags=cve_data.get("tags", ""),
        stix_id=cve_id,
    )

    return cve_indicator, relationships


def build_domain_output(
    client: Client, score_calculator: ScoreCalculator, domain: str, raw_response: dict, extended_data: bool
) -> CommandResults:
    data = raw_response.get("data", {})
    attributes = data.get("attributes", {})

    last_analysis_stats = attributes.get("last_analysis_stats", {})
    positive_engines = last_analysis_stats.get("malicious", 0)
    detection_engines = sum(last_analysis_stats.values())

    whois = get_whois(attributes.get("whois", ""))

    relationships_response = data.get("relationships", {})
    relationships_list = create_relationships(
        entity_a=domain,
        entity_a_type=FeedIndicatorType.Domain,
        relationships_response=relationships_response,
        reliability=client.reliability,
    )

    domain_indicator = _get_domain_indicator(client, score_calculator, domain, raw_response)

    if not extended_data:
        data = decrease_data_size(data)

    return CommandResults(
        outputs_prefix=f"{INTEGRATION_ENTRY_CONTEXT}.Domain",
        outputs_key_field="id",
        indicator=domain_indicator,
        readable_output=tableToMarkdown(
            f"Domain data of {domain}",
            {
                **data,
                **attributes,
                **whois,
                "last_modified": epoch_to_timestamp(attributes.get("last_modification_date")),
                "positives": f"{positive_engines}/{detection_engines}",
                "gti_threat_score": attributes.get("gti_assessment", {}).get("threat_score", {}).get("value"),
                "gti_severity": attributes.get("gti_assessment", {}).get("severity", {}).get("value"),
                "gti_verdict": attributes.get("gti_assessment", {}).get("verdict", {}).get("value"),
            },
            headers=[
                "id",
                "Registrant Country",
                "Registrar",
                "last_modified",
                "reputation",
                "positives",
                "gti_threat_score",
                "gti_severity",
                "gti_verdict",
            ],
            removeNull=True,
            headerTransform=string_to_table_header,
        ),
        outputs=data,
        raw_response=raw_response,
        relationships=relationships_list,
    )


def build_url_output(
    client: Client, score_calculator: ScoreCalculator, url: str, raw_response: dict, extended_data: bool
) -> CommandResults:
    data = raw_response.get("data", {})
    attributes = data.get("attributes", {})

    last_analysis_stats = attributes.get("last_analysis_stats", {})
    positive_detections = last_analysis_stats.get("malicious", 0)
    detection_engines = sum(last_analysis_stats.values())

    relationships_response = data.get("relationships", {})
    relationships_list = create_relationships(
        entity_a=url,
        entity_a_type=FeedIndicatorType.URL,
        relationships_response=relationships_response,
        reliability=client.reliability,
    )

    url_indicator = _get_url_indicator(client, score_calculator, url, raw_response)

    if not extended_data:
        data = decrease_data_size(data)

    return CommandResults(
        outputs_prefix=f"{INTEGRATION_ENTRY_CONTEXT}.URL",
        outputs_key_field="id",
        indicator=url_indicator,
        readable_output=tableToMarkdown(
            f'URL data of "{url}"',
            {
                **data,
                **attributes,
                "url": url,
                "last_modified": epoch_to_timestamp(attributes.get("last_modification_date")),
                "positives": f"{positive_detections}/{detection_engines}",
                "gti_threat_score": attributes.get("gti_assessment", {}).get("threat_score", {}).get("value"),
                "gti_severity": attributes.get("gti_assessment", {}).get("severity", {}).get("value"),
                "gti_verdict": attributes.get("gti_assessment", {}).get("verdict", {}).get("value"),
            },
            headers=[
                "url",
                "title",
                "has_content",
                "last_http_response_content_sha256",
                "last_modified",
                "reputation",
                "positives",
                "gti_threat_score",
                "gti_severity",
                "gti_verdict",
            ],
            removeNull=True,
            headerTransform=string_to_table_header,
        ),
        outputs=data,
        raw_response=raw_response,
        relationships=relationships_list,
    )


def build_private_url_output(url: str, raw_response: dict) -> CommandResults:
    data = raw_response.get("data", {})
    attributes = data.get("attributes", {})

    last_analysis_stats = attributes.get("last_analysis_stats", {})
    positive_detections = last_analysis_stats.get("malicious", 0)
    detection_engines = sum(last_analysis_stats.values())

    return CommandResults(
        outputs_prefix=f"{INTEGRATION_ENTRY_CONTEXT}.URL",
        outputs_key_field="id",
        readable_output=tableToMarkdown(
            f'URL data of "{url}"',
            {
                **attributes,
                "positives": f"{positive_detections}/{detection_engines}",
            },
            headers=[
                "url",
                "title",
                "last_http_response_content_sha256",
                "positives",
            ],
            removeNull=True,
            headerTransform=string_to_table_header,
        ),
        outputs=data,
        raw_response=raw_response,
    )


def build_ip_output(
    client: Client, score_calculator: ScoreCalculator, ip: str, raw_response: dict, extended_data: bool
) -> CommandResults:
    data = raw_response.get("data", {})
    attributes = data.get("attributes", {})

    last_analysis_stats = attributes.get("last_analysis_stats", {})
    positive_engines = last_analysis_stats.get("malicious", 0)
    detection_engines = sum(last_analysis_stats.values())

    relationships_response = data.get("relationships", {})
    relationships_list = create_relationships(
        entity_a=ip,
        entity_a_type=FeedIndicatorType.IP,
        relationships_response=relationships_response,
        reliability=client.reliability,
    )

    ip_indicator = _get_ip_indicator(client, score_calculator, ip, raw_response)

    if not extended_data:
        data = decrease_data_size(data)

    return CommandResults(
        outputs_prefix=f"{INTEGRATION_ENTRY_CONTEXT}.IP",
        outputs_key_field="id",
        indicator=ip_indicator,
        readable_output=tableToMarkdown(
            f"IP reputation of {ip}:",
            {
                **data,
                **attributes,
                "last_modified": epoch_to_timestamp(attributes.get("last_modification_date")),
                "positives": f"{positive_engines}/{detection_engines}",
                "gti_threat_score": attributes.get("gti_assessment", {}).get("threat_score", {}).get("value"),
                "gti_severity": attributes.get("gti_assessment", {}).get("severity", {}).get("value"),
                "gti_verdict": attributes.get("gti_assessment", {}).get("verdict", {}).get("value"),
            },
            headers=[
                "id",
                "network",
                "country",
                "as_owner",
                "last_modified",
                "reputation",
                "positives",
                "gti_threat_score",
                "gti_severity",
                "gti_verdict",
            ],
            headerTransform=string_to_table_header,
        ),
        outputs=data,
        raw_response=raw_response,
        relationships=relationships_list,
    )


def build_file_output(
    client: Client, score_calculator: ScoreCalculator, file_hash: str, raw_response: dict, extended_data: bool
) -> CommandResults:
    data = raw_response.get("data", {})
    attributes = data.get("attributes", {})

    last_analysis_stats = attributes.get("last_analysis_stats", {})
    malicious = last_analysis_stats.get("malicious", 0)
    total = sum(last_analysis_stats.values())

    relationships_response = data.get("relationships", {})
    relationships_list = create_relationships(
        entity_a=file_hash,
        entity_a_type=FeedIndicatorType.File,
        relationships_response=relationships_response,
        reliability=client.reliability,
    )

    file_indicator = _get_file_indicator(client, score_calculator, file_hash, raw_response)

    if not extended_data:
        data = decrease_data_size(data)

    return CommandResults(
        outputs_prefix=f"{INTEGRATION_ENTRY_CONTEXT}.File",
        outputs_key_field="id",
        indicator=file_indicator,
        readable_output=tableToMarkdown(
            f"Results of file hash {file_hash}",
            {
                **data,
                **attributes,
                "positives": f"{malicious}/{total}",
                "creation_date": epoch_to_timestamp(attributes.get("creation_date")),
                "last_modified": epoch_to_timestamp(attributes.get("last_modification_date", 0)),
                "gti_threat_score": attributes.get("gti_assessment", {}).get("threat_score", {}).get("value"),
                "gti_severity": attributes.get("gti_assessment", {}).get("severity", {}).get("value"),
                "gti_verdict": attributes.get("gti_assessment", {}).get("verdict", {}).get("value"),
            },
            headers=[
                "sha1",
                "sha256",
                "md5",
                "meaningful_name",
                "type_extension",
                "creation_date",
                "last_modified",
                "reputation",
                "positives",
                "gti_threat_score",
                "gti_severity",
                "gti_verdict",
            ],
            removeNull=True,
            headerTransform=string_to_table_header,
        ),
        outputs=data,
        raw_response=raw_response,
        relationships=relationships_list,
    )


def build_cve_output(client: Client, score_calculator: ScoreCalculator, cve_id: str, raw_response: dict) -> CommandResults:
    """
    Build CommandResults for CVE data from collections endpoint.

    Args:
        client: Client instance
        score_calculator: Score calculator instance
        cve_id: CVE identifier
        raw_response: Raw API response

    Returns:
        CommandResults with CVE information
    """
    # Extract and process CVE data
    cve_data = _extract_cve_data(raw_response)

    # Create CVE indicator and relationships
    cve_indicator, relationships = _create_cve_indicator(client, score_calculator, cve_id, cve_data, raw_response)

    context_data = remove_empty_elements(raw_response.get("data", {}))

    # Prepare human-readable output
    hr_data = {
        "CVE ID": cve_id,
        "Description": cve_data.get("description", ""),
        "Executive Summary": cve_data.get("executive_summary", ""),
        "Risk Rating": cve_data.get("risk_rating", ""),
        "Priority": cve_data.get("priority", ""),
        "CVSS v3.x Score": cve_data.get("cvss_v3_score"),
        "CVSS v3.x Vector": cve_data.get("cvss_v3_vector"),
        "CVSS v4.x Score": cve_data.get("cvss_v4_score"),
        "CVSS v4.x Vector": cve_data.get("cvss_v4_vector"),
        "Exploitation State": cve_data.get("exploitation_state"),
        "Exploit Availability": cve_data.get("exploit_availability"),
        "Date Of Disclosure": cve_data.get("date_of_disclosure", ""),
        "Creation Date": cve_data.get("creation_date", ""),
        "Last Modified": cve_data.get("last_modification_date", ""),
        "Sources": cve_data.get("sources_count"),
        "Related Files": cve_data.get("files_count"),
        "Related Domains": cve_data.get("domains_count"),
        "Related IPs": cve_data.get("ip_addresses_count"),
        "Related URLs": cve_data.get("urls_count"),
    }

    hr_for_cve = tableToMarkdown(
        f"CVE Information: {cve_id}",
        hr_data,
        removeNull=True,
        headers=[
            "CVE ID",
            "Risk Rating",
            "Priority",
            "Exploitation State",
            "Exploit Availability",
            "CVSS v3.x Score",
            "CVSS v4.x Score",
            "CVSS v3.x Vector",
            "CVSS v4.x Vector",
            "Date Of Disclosure",
            "Creation Date",
            "Last Modified",
            "Sources",
            "Description",
            "Related Files",
            "Related Domains",
            "Related IPs",
            "Related URLs",
            "Executive Summary",
        ],
    )

    return CommandResults(
        outputs_prefix=f"{INTEGRATION_ENTRY_CONTEXT}.CVE",
        outputs_key_field="id",
        indicator=cve_indicator,
        readable_output=hr_for_cve,
        outputs=context_data,
        raw_response=raw_response,
        relationships=relationships,
    )


def build_private_file_output(file_hash: str, raw_response: dict) -> CommandResults:
    data = raw_response.get("data", {})
    attributes = data.get("attributes", {})
    threat_severity = attributes.get("threat_severity", {})
    threat_severity_level = threat_severity.get("threat_severity_level", "")
    threat_severity_data = threat_severity.get("threat_severity_data", {})
    popular_threat_category = threat_severity_data.get("popular_threat_category", "")
    threat_verdict = attributes.get("threat_verdict", "")
    return CommandResults(
        outputs_prefix=f"{INTEGRATION_ENTRY_CONTEXT}.File",
        outputs_key_field="id",
        readable_output=tableToMarkdown(
            f"Results of file hash {file_hash}",
            {
                **attributes,
                "threat_severity_level": SEVERITY_LEVELS.get(threat_severity_level, threat_severity_level),
                "popular_threat_category": popular_threat_category,
                "threat_verdict": VERDICTS.get(threat_verdict, threat_verdict),
            },
            headers=[
                "sha1",
                "sha256",
                "md5",
                "meaningful_name",
                "type_extension",
                "threat_severity_level",
                "popular_threat_category",
                "threat_verdict",
            ],
            removeNull=True,
            headerTransform=string_to_table_header,
        ),
        outputs=data,
        raw_response=raw_response,
    )


def get_whois(whois_string: str) -> defaultdict:
    """Gets a WHOIS string and returns a parsed dict of the WHOIS String.

    Args:
        whois_string: whois from domain api call

    Returns:
        A parsed whois

    Examples:
        >>> get_whois('key1:value\\nkey2:value2')
        defaultdict({'key1': 'value', 'key2': 'value2'})
    """
    whois: defaultdict = defaultdict(lambda: None)
    for line in whois_string.splitlines():
        key: str
        value: str
        try:
            key, value = line.split(sep=":", maxsplit=1)
        except ValueError:
            demisto.debug(f"Could not unpack Whois string: {line}. Skipping")
            continue
        key = key.strip()
        value = value.strip()
        if key in whois:
            if not isinstance(whois[key], list):
                whois[key] = [whois[key]]
            whois[key].append(value)
        else:
            whois[key] = value
    return whois


def get_file_context(entry_id: str) -> dict:
    """Gets a File object from context.

    Args:
        entry_id: The entry ID of the file

    Returns:
        File object contains Name, Hashes and more information
    """
    context = demisto.dt(demisto.context(), f'File(val.EntryID === "{entry_id}")')
    if not context:
        return {}
    if isinstance(context, list):
        return context[0]
    return context


def validate_cve_values(cve_ids: list[str]) -> tuple[list[str], list[str]]:
    """
    Validate CVE format and return valid/invalid CVE lists.

    Args:
        cve_ids: List of CVE identifiers to validate

    Returns:
        Tuple of (valid_cves, invalid_cves)
    """

    valid_cves = []
    invalid_cves = []

    # CVE format: CVE-YYYY-NNNNN (where YYYY is year, NNNNN is 4+ digits)
    cve_pattern = re.compile(r"^CVE-\d{4}-\d{4,}$", re.IGNORECASE)

    for cve_id in cve_ids:
        normalized_cve = cve_id.upper().strip()
        if cve_pattern.match(normalized_cve):
            valid_cves.append(normalized_cve)
        else:
            invalid_cves.append(cve_id)

    return valid_cves, invalid_cves


def raise_if_ip_not_valid(ip: str):
    """Raises an error if ip is not valid

    Args:
        ip: ip address

    Raises:
        ValueError: If IP is not valid

    Examples:
        >>> raise_if_ip_not_valid('not ip at all')
        Traceback (most recent call last):
         ...
        ValueError: IP "not ip at all" is not valid
        >>> raise_if_ip_not_valid('8.8.8.8')
    """
    if not is_ip_valid(ip, accept_v6_ips=True):
        raise ValueError(f'IP "{ip}" is not valid')


def raise_if_hash_not_valid(file_hash: str):
    """Raises an error if file_hash is not valid

    Args:
        file_hash: file hash

    Raises:
        ValueError: if hash is not of type SHA-256, SHA-1 or MD5

    Examples:
        >>> raise_if_hash_not_valid('not a hash')
        Traceback (most recent call last):
         ...
        ValueError: Hash "not a hash" is not of type SHA-256, SHA-1 or MD5
        >>> raise_if_hash_not_valid('7e641f6b9706d860baf09fe418b6cc87')
    """
    if get_hash_type(file_hash) not in ("sha256", "sha1", "md5"):
        raise ValueError(f'Hash "{file_hash}" is not of type SHA-256, SHA-1 or MD5')


def encode_url_to_base64(url: str) -> str:
    """Gets a string (in this case, url but it can not be) and return it as base64 without padding ('=')

    Args:
         url: A string to encode

    Returns:
         Base64 encoded string with no padding

    Examples:
        >>> encode_url_to_base64('https://example.com')
        'aHR0cHM6Ly9leGFtcGxlLmNvbQ'
    """
    return base64.urlsafe_b64encode(url.encode()).decode().strip("=")


# endregion

# region Reputation commands


def ip_command(
    client: Client, score_calculator: ScoreCalculator, args: dict, relationships: str, disable_private_ip_lookup: bool
) -> List[CommandResults]:
    """
    1 API Call for regular
    """
    ips = argToList(args["ip"])
    results: List[CommandResults] = []
    execution_metrics = ExecutionMetrics()
    override_private_lookup = argToBoolean(args.get("override_private_lookup", False))

    for ip in ips:
        raise_if_ip_not_valid(ip)
        if disable_private_ip_lookup and ipaddress.ip_address(ip).is_private and not override_private_lookup:
            results.append(build_skipped_enrichment_ip_output(client, ip))
            execution_metrics.success += 1
            continue
        try:
            raw_response = client.ip(ip, relationships)
            if raw_response.get("error", {}).get("code") == "QuotaExceededError":
                execution_metrics.quota_error += 1
                results.append(build_quota_exceeded_ip_output(client, ip))
                continue
            if raw_response.get("error", {}).get("code") == "NotFoundError":
                results.append(build_unknown_ip_output(client, ip))
                continue
        except Exception as exc:
            # If anything happens, just keep going
            demisto.debug(f'Could not process IP: "{ip}"\n {exc!s}')
            execution_metrics.general_error += 1
            results.append(build_error_ip_output(client, ip, str(exc)))
            continue
        execution_metrics.success += 1
        results.append(
            build_ip_output(client, score_calculator, ip, raw_response, argToBoolean(args.get("extended_data", False)))
        )
    if execution_metrics.is_supported():
        _metric_results = execution_metrics.metrics
        metric_results = cast(CommandResults, _metric_results)
        results.append(metric_results)
    return results


def file_command(client: Client, score_calculator: ScoreCalculator, args: dict, relationships: str) -> List[CommandResults]:
    """
    1 API Call
    """
    files = argToList(args["file"])
    extended_data = argToBoolean(args.get("extended_data", False))
    results: List[CommandResults] = []
    execution_metrics = ExecutionMetrics()

    for file in files:
        try:
            raise_if_hash_not_valid(file)
            raw_response = client.file(file, relationships)
            if raw_response.get("error", {}).get("code") == "QuotaExceededError":
                execution_metrics.quota_error += 1
                results.append(build_quota_exceeded_file_output(client, file))
                continue
            if raw_response.get("error", {}).get("code") == "NotFoundError":
                results.append(build_unknown_file_output(client, file))
                continue
            results.append(build_file_output(client, score_calculator, file, raw_response, extended_data))
            execution_metrics.success += 1
        except Exception as exc:
            # If anything happens, just keep going
            demisto.debug(f'Could not process file: "{file}"\n {exc!s}')
            execution_metrics.general_error += 1
            results.append(build_error_file_output(client, file, str(exc)))
            continue
    if execution_metrics.is_supported():
        _metric_results = execution_metrics.metrics
        metric_results = cast(CommandResults, _metric_results)
        results.append(metric_results)
    return results


def private_file_command(client: Client, args: dict) -> List[CommandResults]:
    """
    1 API Call
    """
    files = argToList(args["file"])
    results: List[CommandResults] = []
    execution_metrics = ExecutionMetrics()

    for file in files:
        try:
            raise_if_hash_not_valid(file)
            raw_response = client.private_file(file)
            if raw_response.get("error", {}).get("code") == "QuotaExceededError":
                execution_metrics.quota_error += 1
                results.append(build_quota_exceeded_file_output(client, file))
                continue
            if raw_response.get("error", {}).get("code") == "NotFoundError":
                results.append(build_unknown_file_output(client, file))
                continue
            results.append(build_private_file_output(file, raw_response))
            execution_metrics.success += 1
        except Exception as exc:
            # If anything happens, just keep going
            demisto.debug(f'Could not process private file: "{file}"\n {exc!s}')
            execution_metrics.general_error += 1
            results.append(build_error_file_output(client, file, str(exc)))
            continue
    if execution_metrics.is_supported():
        _metric_results = execution_metrics.metrics
        metric_results = cast(CommandResults, _metric_results)
        results.append(metric_results)
    return results


def url_command(client: Client, score_calculator: ScoreCalculator, args: dict, relationships: str) -> List[CommandResults]:
    """
    1 API Call for regular
    """
    urls = argToList(args["url"])
    extended_data = argToBoolean(args.get("extended_data", False))
    results: List[CommandResults] = []
    execution_metrics = ExecutionMetrics()

    for url in urls:
        try:
            raw_response = client.url(url, relationships)
            if raw_response.get("error", {}).get("code") == "QuotaExceededError":
                execution_metrics.quota_error += 1
                results.append(build_quota_exceeded_url_output(client, url))
                continue
            if raw_response.get("error", {}).get("code") == "NotFoundError":
                results.append(build_unknown_url_output(client, url))
                continue
        except Exception as exc:
            # If anything happens, just keep going
            demisto.debug(f'Could not process URL: "{url}".\n {exc!s}')
            execution_metrics.general_error += 1
            results.append(build_error_url_output(client, url, str(exc)))
            continue
        execution_metrics.success += 1
        results.append(build_url_output(client, score_calculator, url, raw_response, extended_data))
    if execution_metrics.is_supported():
        _metric_results = execution_metrics.metrics
        metric_results = cast(CommandResults, _metric_results)
        results.append(metric_results)
    return results


def cve_command(client: Client, score_calculator: ScoreCalculator, args: dict) -> List[CommandResults]:
    """
    Get CVE information from Google Threat Intelligence collections endpoint.

    Args:
        client: Client instance
        args: Command arguments containing 'cve' parameter

    Returns:
        List of CommandResults with CVE information
    """
    cve_ids = argToList(args.get("cve", []))
    cve_ids = [cve_id.strip() for cve_id in cve_ids if cve_id.strip()]

    results: List[CommandResults] = []
    execution_metrics = ExecutionMetrics()

    # Validate CVE format (CVE-YYYY-NNNNN)
    valid_cves, invalid_cves = validate_cve_values(cve_ids)

    if invalid_cves:
        return_warning(
            "The following CVEs were found invalid: {}".format(", ".join(invalid_cves)), exit=len(invalid_cves) == len(cve_ids)
        )

    for cve_id in valid_cves:
        # Normalize CVE ID to uppercase
        cve_id = cve_id.upper().strip()

        try:
            raw_response = client.cve(cve_id)

            if raw_response.get("error", {}).get("code") == "QuotaExceededError":
                execution_metrics.quota_error += 1
                results.append(build_quota_exceeded_cve_output(client, cve_id))
                continue
            if raw_response.get("error", {}).get("code") == "NotFoundError":
                results.append(build_unknown_cve_output(client, cve_id))
                continue
        except Exception as exc:
            # If anything happens, just keep going
            demisto.debug(f'Could not process CVE: "{cve_id}".\n {exc!s}')
            execution_metrics.general_error += 1
            results.append(build_error_cve_output(client, cve_id, str(exc)))
            continue
        execution_metrics.success += 1
        results.append(build_cve_output(client, score_calculator, cve_id, raw_response))

    if execution_metrics.is_supported():
        _metric_results = execution_metrics.metrics
        metric_results = cast(CommandResults, _metric_results)
        results.append(metric_results)
    return results


def private_url_command(client: Client, args: dict) -> List[CommandResults]:
    """
    1 API Call
    """
    urls = argToList(args["url"])
    results: List[CommandResults] = []
    execution_metrics = ExecutionMetrics()

    for url in urls:
        try:
            raw_response = client.private_url(url)
            if raw_response.get("error", {}).get("code") == "QuotaExceededError":
                execution_metrics.quota_error += 1
                results.append(build_quota_exceeded_url_output(client, url))
                continue
            if raw_response.get("error", {}).get("code") == "NotFoundError":
                results.append(build_unknown_url_output(client, url))
                continue
        except Exception as exc:
            # If anything happens, just keep going
            demisto.debug(f'Could not process private URL: "{url}".\n {exc!s}')
            execution_metrics.general_error += 1
            results.append(build_error_url_output(client, url, str(exc)))
            continue
        execution_metrics.success += 1
        results.append(build_private_url_output(url, raw_response))
    if execution_metrics.is_supported():
        _metric_results = execution_metrics.metrics
        metric_results = cast(CommandResults, _metric_results)
        results.append(metric_results)
    return results


def domain_command(client: Client, score_calculator: ScoreCalculator, args: dict, relationships: str) -> List[CommandResults]:
    """
    1 API Call for regular
    """
    execution_metrics = ExecutionMetrics()
    domains = argToList(args["domain"])
    results: List[CommandResults] = []
    for domain in domains:
        try:
            raw_response = client.domain(domain, relationships)
            if raw_response.get("error", {}).get("code") == "QuotaExceededError":
                execution_metrics.quota_error += 1
                results.append(build_quota_exceeded_domain_output(client, domain))
                continue
            if raw_response.get("error", {}).get("code") == "NotFoundError":
                results.append(build_unknown_domain_output(client, domain))
                continue
        except Exception as exc:
            # If anything happens, just keep going
            demisto.debug(f'Could not process domain: "{domain}"\n {exc!s}')
            execution_metrics.general_error += 1
            results.append(build_error_domain_output(client, domain, str(exc)))
            continue
        execution_metrics.success += 1
        result = build_domain_output(
            client, score_calculator, domain, raw_response, argToBoolean(args.get("extended_data", False))
        )
        results.append(result)
    if execution_metrics.is_supported():
        _metric_results = execution_metrics.metrics
        metric_results = cast(CommandResults, _metric_results)
        results.append(metric_results)

    return results


# endregion


# region Scan commands
def file_rescan_command(client: Client, args: dict) -> CommandResults:
    """
    1 API Call
    """
    file_hash = args["file"]
    raise_if_hash_not_valid(file_hash)
    raw_response = client.file_rescan(file_hash)
    data = raw_response["data"]
    data["hash"] = file_hash
    context = {
        f"{INTEGRATION_ENTRY_CONTEXT}.Submission(val.id && val.id === obj.id)": data,
        "vtScanID": data.get("id"),  # BC preservation
    }
    return CommandResults(
        readable_output=tableToMarkdown(
            f'File "{file_hash}" resubmitted.', data, removeNull=True, headerTransform=underscoreToCamelCase
        ),
        outputs=context,
        raw_response=raw_response,
    )


def get_working_id(id_: str, entry_id: str) -> str:
    """Sometimes new scanned files ID will be only a number. Should connect them with base64(MD5:_id).
    Fixes bug in Google Threat Intelligence API.

    Args:
        entry_id: the entry id connected to the file
        id_: id given from the API

    Returns:
        A working ID that we can use in other commands.
    """
    if (isinstance(id_, str) and id_.isnumeric()) or isinstance(id_, int):
        demisto.debug(f"Got an integer id from file-scan. {id_=}, {entry_id=}\n")
        raise DemistoException(
            f"Got an int {id_=} as analysis report. This is a bug in Google Threat Intelligence API.\n"
            f"While Google Threat Intelligence team is fixing the problem, try to resend the file."
        )
    return id_


def file_scan(client: Client, args: dict) -> List[CommandResults]:
    """
    1 API Call
    """
    return upload_file(client, args)


def private_file_scan(client: Client, args: dict) -> List[CommandResults]:
    """
    1 API Call
    """
    return upload_file(client, args, True)


def upload_file(client: Client, args: dict, private: bool = False) -> List[CommandResults]:
    """
    1 API Call
    """
    entry_ids = argToList(args["entryID"])
    upload_url = args.get("uploadURL")
    if len(entry_ids) > 1 and upload_url:
        raise DemistoException("You can supply only one entry ID with an upload URL.")
    results = []
    for entry_id in entry_ids:
        try:
            file_obj = demisto.getFilePath(entry_id)
            file_path = file_obj["path"]
            if private:
                raw_response = client.private_file_scan(file_path)
            else:
                raw_response = client.file_scan(file_path, upload_url)
            data = raw_response.get("data", {})
            # add current file as identifiers
            data.update(get_file_context(entry_id))
            id_ = data.get("id")
            demisto.debug(f'Result from vt-scan-file {entry_id=} {id_=} {data.get("type")=}')
            id_ = get_working_id(id_, entry_id)
            data["id"] = id_
            context = {
                f"{INTEGRATION_ENTRY_CONTEXT}.Submission(val.id && val.id === obj.id)": data,
                "vtScanID": id_,  # BC preservation
            }
            results.append(
                CommandResults(
                    readable_output=tableToMarkdown(
                        f'The file has been submitted "{file_obj["name"]}"',
                        data,
                        headers=["id", "EntryID", "MD5", "SHA1", "SHA256"],
                        removeNull=True,
                    ),
                    outputs=context,
                    raw_response=raw_response,
                )
            )
        except Exception as exc:
            err = f"Could not process {entry_id=}.\n{exc!s}"
            demisto.debug(err)
            demisto.results({"Type": entryTypes["error"], "ContentsFormat": formats["text"], "Contents": err})
    return results


def file_scan_and_get_analysis(client: Client, score_calculator: ScoreCalculator, args: dict, file_relationships: str):
    """Calls to file-scan and gti-analysis-get."""
    interval = int(args.get("interval_in_seconds", 60))
    extended = argToBoolean(args.get("extended_data", False))

    if not args.get("id"):
        command_results = file_scan(client, args)
        command_result = command_results[0]
        outputs = command_result.outputs
        if not isinstance(outputs, dict):
            raise DemistoException("outputs is expected to be a dict")
        scheduled_command = ScheduledCommand(
            command=f"{COMMAND_PREFIX}-file-scan-and-analysis-get",
            next_run_in_seconds=interval,
            args={
                "entryID": args.get("entryID"),
                "id": outputs.get("vtScanID"),
                "file": outputs.get(f"{INTEGRATION_ENTRY_CONTEXT}.Submission(val.id && val.id === obj.id)", {}).get("SHA256"),
                "interval_in_seconds": interval,
                "extended_data": extended,
            },
            timeout_in_seconds=6000,
        )
        command_result.scheduled_command = scheduled_command
        return command_result

    command_result = get_analysis_command(client, args)
    outputs = command_result.outputs
    if not isinstance(outputs, dict):
        raise DemistoException("outputs is expected to be a dict")
    if outputs.get("data", {}).get("attributes", {}).get("status") == "completed":
        return file_command(client, score_calculator, args, file_relationships)
    scheduled_command = ScheduledCommand(
        command=f"{COMMAND_PREFIX}-file-scan-and-analysis-get",
        next_run_in_seconds=interval,
        args={
            "entryID": args.get("entryID"),
            "id": outputs.get("id"),
            "file": args.get("file"),
            "interval_in_seconds": interval,
            "extended_data": extended,
        },
        timeout_in_seconds=6000,
    )
    return CommandResults(scheduled_command=scheduled_command)


def private_file_scan_and_get_analysis(client: Client, args: dict):
    """Calls to gti-privatescanning-file-scan and gti-privatescanning-analysis-get."""
    interval = int(args.get("interval_in_seconds", 60))

    if not args.get("id"):
        command_results = private_file_scan(client, args)
        command_result = command_results[0]
        outputs = command_result.outputs
        if not isinstance(outputs, dict):
            raise DemistoException("outputs is expected to be a dict")
        scheduled_command = ScheduledCommand(
            command=f"{COMMAND_PREFIX}-private-file-scan-and-analysis-get",
            next_run_in_seconds=interval,
            args={
                "entryID": args.get("entryID"),
                "id": outputs.get("vtScanID"),
                "interval_in_seconds": interval,
            },
            timeout_in_seconds=6000,
        )
        command_result.scheduled_command = scheduled_command
        return command_result

    command_result = private_get_analysis_command(client, args)
    outputs = command_result.outputs
    if not isinstance(outputs, dict):
        raise DemistoException("outputs is expected to be a dict")
    if outputs.get("data", {}).get("attributes", {}).get("status") == "completed":
        return command_result
    scheduled_command = ScheduledCommand(
        command=f"{COMMAND_PREFIX}-private-file-scan-and-analysis-get",
        next_run_in_seconds=interval,
        args={
            "entryID": args.get("entryID"),
            "id": outputs.get("id"),
            "interval_in_seconds": interval,
        },
        timeout_in_seconds=6000,
    )
    return CommandResults(scheduled_command=scheduled_command)


def url_scan_and_get_analysis(client: Client, score_calculator: ScoreCalculator, args: dict, url_relationships: str):
    """Calls to url-scan and gti-analysis-get."""
    interval = int(args.get("interval_in_seconds", 60))
    extended = argToBoolean(args.get("extended_data", False))

    if not args.get("id"):
        command_result = scan_url_command(client, args)
        outputs = command_result.outputs
        if not isinstance(outputs, dict):
            raise DemistoException("outputs is expected to be a dict")
        scheduled_command = ScheduledCommand(
            command=f"{COMMAND_PREFIX}-url-scan-and-analysis-get",
            next_run_in_seconds=interval,
            args={
                "url": args.get("url"),
                "id": outputs.get("vtScanID"),
                "interval_in_seconds": interval,
                "extended_data": extended,
            },
            timeout_in_seconds=6000,
        )
        command_result.scheduled_command = scheduled_command
        return command_result

    command_result = get_analysis_command(client, args)
    outputs = command_result.outputs
    if not isinstance(outputs, dict):
        raise DemistoException("outputs is expected to be a dict")
    if outputs.get("data", {}).get("attributes", {}).get("status") == "completed":
        return url_command(client, score_calculator, args, url_relationships)
    scheduled_command = ScheduledCommand(
        command=f"{COMMAND_PREFIX}-url-scan-and-analysis-get",
        next_run_in_seconds=interval,
        args={
            "url": args.get("url"),
            "id": outputs.get("id"),
            "interval_in_seconds": interval,
            "extended_data": extended,
        },
        timeout_in_seconds=6000,
    )
    return CommandResults(scheduled_command=scheduled_command)


def private_url_scan_and_get_analysis(client: Client, args: dict):
    """Calls to gti-privatescanning-url-scan and gti-privatescanning-analysis-get."""
    interval = int(args.get("interval_in_seconds", 60))

    if not args.get("id"):
        command_result = private_scan_url_command(client, args)
        outputs = command_result.outputs
        if not isinstance(outputs, dict):
            raise DemistoException("outputs is expected to be a dict")
        scheduled_command = ScheduledCommand(
            command=f"{COMMAND_PREFIX}-private-url-scan-and-analysis-get",
            next_run_in_seconds=interval,
            args={
                "url": args.get("url"),
                "id": outputs.get("vtScanID"),
                "interval_in_seconds": interval,
            },
            timeout_in_seconds=6000,
        )
        command_result.scheduled_command = scheduled_command
        return command_result

    command_result = private_get_analysis_command(client, args)
    outputs = command_result.outputs
    if not isinstance(outputs, dict):
        raise DemistoException("outputs is expected to be a dict")
    if outputs.get("data", {}).get("attributes", {}).get("status") == "completed":
        return command_result
    scheduled_command = ScheduledCommand(
        command=f"{COMMAND_PREFIX}-private-url-scan-and-analysis-get",
        next_run_in_seconds=interval,
        args={
            "url": args.get("url"),
            "id": outputs.get("id"),
            "interval_in_seconds": interval,
        },
        timeout_in_seconds=6000,
    )
    return CommandResults(scheduled_command=scheduled_command)


def get_upload_url(client: Client) -> CommandResults:
    """
    1 API Call
    """
    raw_response = client.get_upload_url()
    upload_url = raw_response["data"]
    context = {
        f"{INTEGRATION_ENTRY_CONTEXT}.FileUploadURL": upload_url,
        "vtUploadURL": upload_url,  # BC preservation
    }
    return CommandResults(
        readable_output=tableToMarkdown("New upload url acquired!", {"Upload url": upload_url}),
        outputs=context,
        raw_response=raw_response,
    )


def scan_url_command(client: Client, args: dict) -> CommandResults:
    """
    1 API Call
    """
    return scan_url(client, args)


def private_scan_url_command(client: Client, args: dict) -> CommandResults:
    """
    1 API Call
    """
    return scan_url(client, args, True)


def scan_url(client: Client, args: dict, private: bool = False) -> CommandResults:
    """
    1 API Call
    """
    url = args["url"]
    raw_response: Dict[str, Any] = {}
    data: Dict[str, Any] = {}
    context: Dict[str, Any] = {}
    headers = ["id", "url"]

    try:
        if private:
            raw_response = client.private_url_scan(url)
        else:
            raw_response = client.url_scan(url)
        data = raw_response["data"]

        data["url"] = url
        context = {
            f"{INTEGRATION_ENTRY_CONTEXT}.Submission(val.id && val.id === obj.id)": data,
            "vtScanID": data.get("id"),  # BC preservation
        }
    except DemistoException as e:
        error = e.res.json().get("error")

        # Invalid url, probably due to an unknown TLD
        if error["code"] == "InvalidArgumentError":
            data = {"url": url, "id": "", "error": error["message"]}
            headers.append("error")
        else:
            raise e

    return CommandResults(
        readable_output=tableToMarkdown("New url submission:", data, headers=headers), outputs=context, raw_response=raw_response
    )


# endregion


# region Comments commands
def get_comments_command(client: Client, args: dict) -> CommandResults:
    """
    1 API Call

    BC Break - No NotBefore argument
    added limit
    """
    limit = arg_to_number_must_int(args.get("limit"), arg_name="limit", required=True)
    resource = args["resource"]
    if before := args.get("before"):
        before = parse(before)
        assert before is not None, f'Could not parse the before date "{before}"'
        before = before.replace(tzinfo=None)

    resource_type = args.get("resource_type")
    if not resource_type:
        try:
            raise_if_hash_not_valid(resource)
            resource_type = "file"
        except ValueError:
            resource_type = "url"
    resource_type = resource_type.lower()
    # Will find if there's one and only one True in the list.
    if resource_type == "ip":
        raise_if_ip_not_valid(resource)
        raw_response = client.get_ip_comments(resource, limit)
    elif resource_type == "url":
        raw_response = client.get_url_comments(resource, limit)
    elif resource_type in ("hash", "file"):
        raise_if_hash_not_valid(resource)
        raw_response = client.get_hash_comments(resource, limit)
    elif resource_type == "domain":
        raw_response = client.get_domain_comments(resource, limit)
    else:
        raise DemistoException(f'Could not find resource type of "{resource_type}"')

    data = raw_response.get("data", {})
    context = {"indicator": resource, "comments": data}
    comments = []
    for comment in data:
        attributes = comment.get("attributes", {})
        votes = attributes.get("votes", {})

        if date := parse(str(attributes.get("date"))):
            date = date.replace(tzinfo=None)

        if date and before and date > before:
            continue
        comments.append(
            {
                "Date": epoch_to_timestamp(attributes.get("date")),
                "Text": attributes.get("text"),
                "Positive Votes": votes.get("positive"),
                "Abuse Votes": votes.get("abuse"),
                "Negative Votes": votes.get("negative"),
            }
        )

    return CommandResults(
        f"{INTEGRATION_ENTRY_CONTEXT}.Comments",
        "id",
        readable_output=tableToMarkdown(
            f'Google Threat Intelligence comments of {resource_type}: "{resource}"',
            comments,
            headers=["Date", "Text", "Positive Votes", "Abuse Votes", "Negative Votes"],
        ),
        outputs=context,
        raw_response=raw_response,
    )


def add_comments_command(client: Client, args: dict) -> CommandResults:
    """
    1 API Call
    """
    resource = args["resource"]
    comment = args["comment"]
    resource_type = args.get("resource_type")
    if not resource_type:
        try:
            raise_if_hash_not_valid(resource)
            resource_type = "file"
        except ValueError:
            resource_type = "url"
    resource_type = resource_type.lower()
    if resource_type == "ip":
        raise_if_ip_not_valid(resource)
        raw_response = client.add_comment_to_ip(resource, comment)
    elif resource_type == "url":
        raw_response = client.add_comment_to_url(resource, comment)
    elif resource_type == "domain":
        raw_response = client.add_comment_to_domain(resource, comment)
    elif resource_type == "file":
        raise_if_hash_not_valid(resource)
        raw_response = client.add_comment_to_file(resource, comment)
    else:
        raise DemistoException(f'Could not find resource type of "{resource_type}"')
    data = raw_response["data"]
    attributes = data.get("attributes", {})
    votes = attributes.get("votes", {})
    return CommandResults(
        f"{INTEGRATION_ENTRY_CONTEXT}.Comments.comments",
        "id",
        readable_output=tableToMarkdown(
            "Comment has been added!",
            {
                "Date": epoch_to_timestamp(attributes.get("date")),
                "Text": attributes.get("text"),
                "Positive Votes": votes.get("positive"),
                "Abuse Votes": votes.get("abuse"),
                "Negative Votes": votes.get("negative"),
            },
            headers=["Date", "Text", "Positive Votes", "Abuse Votes", "Negative Votes"],
        ),
        outputs=data,
        raw_response=raw_response,
    )


def get_comments_by_id_command(client: Client, args: dict) -> CommandResults:
    """
    1 API Call
    """
    comment_id = args["id"]
    raw_response = client.get_comment_by_id(comment_id)
    data = raw_response["data"]
    attributes = data.get("attributes", {})
    votes = attributes.get("votes", {})
    return CommandResults(
        f"{INTEGRATION_ENTRY_CONTEXT}.Comments.comments",
        "id",
        readable_output=tableToMarkdown(
            f"Comment of ID {comment_id}",
            {
                "Date": epoch_to_timestamp(attributes.get("date")),
                "Text": attributes.get("text"),
                "Positive Votes": votes.get("positive"),
                "Abuse Votes": votes.get("abuse"),
                "Negative Votes": votes.get("negative"),
            },
            headers=["Date", "Text", "Positive Votes", "Abuse Votes", "Negative Votes"],
        ),
        outputs=data,
        raw_response=raw_response,
    )


# endregion


def file_sandbox_report_command(client: Client, args: dict) -> List[CommandResults]:
    """
    1 API Call
    """
    execution_metrics = ExecutionMetrics()
    results: List[CommandResults] = []
    file_hash = args["file"]
    limit = arg_to_number(args["limit"], "limit", required=True)
    assert isinstance(limit, int)  # mypy fix
    raise_if_hash_not_valid(file_hash)
    raw_response = client.file_sandbox_report(file_hash, limit)
    if "data" in raw_response:
        data = raw_response["data"]
        execution_metrics.quota_error += 1
        results.append(
            CommandResults(
                f"{INTEGRATION_ENTRY_CONTEXT}.SandboxReport",
                "id",
                readable_output=tableToMarkdown(
                    f"Sandbox Reports for file hash: {file_hash}",
                    [{"id": item["id"], **item["attributes"], "link": item["links"]["self"]} for item in data],
                    headers=["analysis_date", "last_modification_date", "sandbox_name", "link"],
                    removeNull=True,
                    headerTransform=underscoreToCamelCase,
                ),
                outputs=data,
                raw_response=raw_response,
            )
        )
    elif raw_response.get("error", {}).get("code") == "NotFoundError":
        results.append(build_unknown_file_output(client, file_hash))
    else:
        execution_metrics.quota_error += 1
        results.append(build_quota_exceeded_file_output(client, file_hash))

    if execution_metrics.is_supported():
        _metric_results = execution_metrics.metrics
        metric_results = cast(CommandResults, _metric_results)
        results.append(metric_results)

    return results


def passive_dns_data(client: Client, args: dict) -> CommandResults:
    """
    1 API Call
    """

    id = {}
    if "ip" in args:
        id["value"] = args["ip"]
        id["type"] = "ip"
        raise_if_ip_not_valid(id["value"])
    elif "domain" in args:
        id["value"] = args["domain"]
        id["type"] = "domain"
    elif "id" in args:
        id["value"] = args["id"]
        if is_ip_valid(id["value"]):
            id["type"] = "ip"
        else:
            id["type"] = "domain"
    else:
        return CommandResults(readable_output="No IP address or domain was given.")

    limit = arg_to_number_must_int(args["limit"], arg_name="limit", required=True)

    try:
        raw_response = client.passive_dns_data(id, limit)
    except Exception:
        return CommandResults(readable_output=f'{"IP" if id["type"] == "ip" else "Domain"} {id["value"]} was not found.')

    data = raw_response["data"]
    return CommandResults(
        f"{INTEGRATION_ENTRY_CONTEXT}.PassiveDNS",
        "id",
        readable_output=tableToMarkdown(
            f'Passive DNS data for {"IP" if id["type"] == "ip" else "domain"} {id["value"]}',
            [{"id": item["id"], **item["attributes"]} for item in data],
            headers=["id", "date", "host_name", "ip_address", "resolver"],
            removeNull=True,
            headerTransform=underscoreToCamelCase,
        ),
        outputs=data,
        raw_response=raw_response,
    )


def search_command(client: Client, args: dict) -> CommandResults:
    """
    1 API Call
    """
    query = args["query"]
    limit = arg_to_number_must_int(args.get("limit"), "limit", required=True)
    raw_response = client.search(query, limit)
    data = raw_response.get("data", [])
    if not argToBoolean(args.get("extended_data", False)):
        data = decrease_data_size(data)
    return CommandResults(
        f"{INTEGRATION_ENTRY_CONTEXT}.SearchResults",
        "id",
        readable_output=tableToMarkdown(
            f"Search result of query {query}",
            [item.get("attributes") for item in data],
            removeNull=True,
            headerTransform=underscoreToCamelCase,
        ),
        outputs=data,
        raw_response=raw_response,
    )


def get_analysis_command(client: Client, args: dict) -> CommandResults:
    """
    1 API Call
    """
    analysis_id = args["id"]
    raw_response = client.get_analysis(analysis_id)
    data = raw_response.get("data", {})
    if not argToBoolean(args.get("extended_data", False)):
        data = decrease_data_size(data)
    return CommandResults(
        f"{INTEGRATION_ENTRY_CONTEXT}.Analysis",
        "id",
        readable_output=tableToMarkdown(
            "Analysis results:",
            {**data.get("attributes", {}), "id": analysis_id},
            headers=["id", "stats", "status"],
            headerTransform=underscoreToCamelCase,
        ),
        outputs={**raw_response, "id": analysis_id},
        raw_response=raw_response,
    )


def private_get_analysis_command(client: Client, args: dict) -> CommandResults:
    """
    1-2 API Call
    """
    analysis_id = args["id"]
    raw_response = client.get_private_analysis(analysis_id)
    data = raw_response.get("data", {})
    attributes = data.get("attributes", {})

    if sha256 := raw_response.get("meta", {}).get("file_info", {}).get("sha256"):
        attributes["sha256"] = sha256

    if url := raw_response.get("meta", {}).get("url_info", {}).get("url"):
        attributes["url"] = url

    if attributes.get("status", "") == "completed":
        stats = {}
        item_response = client.get_private_item_from_analysis(analysis_id)
        item_attributes = item_response.get("data", {}).get("attributes", {})

        # File attributes
        if threat_severity := item_attributes.get("threat_severity"):
            if severity_level := threat_severity.get("threat_severity_level"):
                stats["threat_severity_level"] = SEVERITY_LEVELS.get(severity_level, severity_level)
            if popular_threat_category := threat_severity.get("threat_severity_data", {}).get("popular_threat_category"):
                stats["popular_threat_category"] = popular_threat_category
        if verdict := item_attributes.get("threat_verdict"):
            stats["threat_verdict"] = VERDICTS.get(verdict, verdict)

        # URL attributes
        if (last_analysis_stats := item_attributes.get("last_analysis_stats")) and (
            detection_engines := sum(last_analysis_stats.values())
        ):
            positive_detections = last_analysis_stats.get("malicious", 0)
            stats["positives"] = f"{positive_detections}/{detection_engines}"

        attributes.update(stats)
        for field in ["title", "last_http_response_content_sha256"]:
            if value := item_attributes.get(field):
                attributes[field] = value

    return CommandResults(
        f"{INTEGRATION_ENTRY_CONTEXT}.Analysis",
        "id",
        readable_output=tableToMarkdown(
            "Analysis results:",
            {**attributes, "id": analysis_id},
            headers=[
                # Common headers
                "id",
                "status",
                # File attributes
                "sha256threat_severity_level",
                "popular_threat_category",
                "threat_verdict",
                # URL attributes
                "url",
                "title",
                "last_http_response_content_sha256",
                "positives",
            ],
            removeNull=True,
            headerTransform=string_to_table_header,
        ),
        outputs={**raw_response, "id": analysis_id},
        raw_response=raw_response,
    )


def check_module(client: Client) -> str:
    """
    1 API Call
    """
    client.get_ip_comments("8.8.8.8", 1)
    return "ok"


def delete_comment(client: Client, args: dict) -> CommandResults:
    """Delete a comments"""
    id_ = args["id"]
    client.delete_comment(id_)
    return CommandResults(readable_output=f"Comment {id_} has been deleted!")


def file_sigma_analysis_command(client: Client, args: dict) -> CommandResults:
    """Get last sigma analysis for a given file"""
    file_hash = args["file"]
    only_stats = argToBoolean(args.get("only_stats", False))
    raw_response = client.file(file_hash)
    data = raw_response["data"]

    if "sigma_analysis_stats" not in data["attributes"] or "sigma_analysis_results" not in data["attributes"]:
        return CommandResults(readable_output=f"No Sigma analyses for file {file_hash} were found.")

    if only_stats:
        return CommandResults(
            f"{INTEGRATION_ENTRY_CONTEXT}.SigmaAnalysis",
            "id",
            readable_output=tableToMarkdown(
                f"Summary of the last Sigma analysis for file {file_hash}:",
                {
                    **data["attributes"]["sigma_analysis_stats"],
                    "**TOTAL**": sum(data["attributes"]["sigma_analysis_stats"].values()),
                },
                headers=["critical", "high", "medium", "low", "**TOTAL**"],
                removeNull=True,
                headerTransform=underscoreToCamelCase,
            ),
            outputs=data,
            raw_response=data["attributes"]["sigma_analysis_stats"],
        )
    else:
        return CommandResults(
            f"{INTEGRATION_ENTRY_CONTEXT}.SigmaAnalysis",
            "id",
            readable_output=tableToMarkdown(
                f"Matched rules for file {file_hash} in the last Sigma analysis:",
                data["attributes"]["sigma_analysis_results"],
                headers=[
                    "rule_level",
                    "rule_description",
                    "rule_source",
                    "rule_title",
                    "rule_id",
                    "rule_author",
                    "match_context",
                ],
                removeNull=True,
                headerTransform=underscoreToCamelCase,
            ),
            outputs=data,
            raw_response=data["attributes"]["sigma_analysis_results"],
        )


def get_assessment_command(client: Client, score_calculator: ScoreCalculator, args: dict) -> CommandResults:
    """Get Google Threat Intelligence assessment for a given resource."""
    resource = args["resource"]
    resource_type = args.get("resource_type", "file").lower()
    if resource_type in ("hash", "file"):
        raise_if_hash_not_valid(resource)
        raw_response = client.file(resource)
        if raw_response.get("error", {}).get("code") == "QuotaExceededError":
            return build_quota_exceeded_file_output(client, resource)
        if raw_response.get("error", {}).get("code") == "NotFoundError":
            return build_unknown_file_output(client, resource)
        indicator = _get_file_indicator(client, score_calculator, resource, raw_response)
    elif resource_type == "ip":
        raise_if_ip_not_valid(resource)
        raw_response = client.ip(resource)
        if raw_response.get("error", {}).get("code") == "QuotaExceededError":
            return build_quota_exceeded_ip_output(client, resource)
        if raw_response.get("error", {}).get("code") == "NotFoundError":
            return build_unknown_ip_output(client, resource)
        indicator = _get_ip_indicator(client, score_calculator, resource, raw_response)
    elif resource_type == "url":
        raw_response = client.url(resource)
        if raw_response.get("error", {}).get("code") == "QuotaExceededError":
            return build_quota_exceeded_url_output(client, resource)
        if raw_response.get("error", {}).get("code") == "NotFoundError":
            return build_unknown_url_output(client, resource)
        indicator = _get_url_indicator(client, score_calculator, resource, raw_response)
    elif resource_type == "domain":
        raw_response = client.domain(resource)
        if raw_response.get("error", {}).get("code") == "QuotaExceededError":
            return build_quota_exceeded_domain_output(client, resource)
        if raw_response.get("error", {}).get("code") == "NotFoundError":
            return build_unknown_domain_output(client, resource)
        indicator = _get_domain_indicator(client, score_calculator, resource, raw_response)
    else:
        raise DemistoException(f'Could not find resource type of "{resource_type}"')

    data = raw_response.get("data", {})
    data.pop("relationships", None)
    gti_assessment = data.get("attributes", {}).get("gti_assessment", {})

    if data:
        if gti_assessment:
            data["attributes"] = {"gti_assessment": gti_assessment}
        else:
            data.pop("attributes", None)

    return CommandResults(
        f"{INTEGRATION_ENTRY_CONTEXT}.Assessment",
        "id",
        indicator=indicator,
        readable_output=tableToMarkdown(
            f'Google Threat Intelligence assessment of {resource_type}: "{resource}"',
            {
                "threat_score": gti_assessment.get("threat_score", {}).get("value"),
                "severity": gti_assessment.get("severity", {}).get("value"),
                "verdict": gti_assessment.get("verdict", {}).get("value"),
            },
            headers=[
                "threat_score",
                "severity",
                "verdict",
            ],
            headerTransform=string_to_table_header,
        ),
        outputs=data,
        raw_response=raw_response,
    )


def _get_curated_collections_command(client: Client, args: dict, collection_type: str) -> CommandResults:
    """Get Google Threat Intelligence collections for a given resource."""
    resource = args["resource"]
    resource_type = args.get("resource_type", "file").lower()
    raw_response = client.curated_collections(resource, resource_type, collection_type)

    data = raw_response.get("data", [])
    collections = []
    for collection in data:
        attributes = collection.get("attributes", {})
        targeted_regions = {
            item.get("country_iso2") for item in attributes.get("targeted_regions_hierarchy", []) if item.get("country_iso2")
        }
        targeted_industries = {
            item.get("industry_group") for item in attributes.get("targeted_industries_tree", []) if item.get("industry_group")
        }
        collections.append(
            {
                "name": attributes.get("name"),
                "last_modification_date": epoch_to_timestamp(attributes.get("last_modification_date")),
                "targeted_regions": ", ".join(targeted_regions),
                "targeted_industries": ", ".join(targeted_industries),
                "link": f'https://www.virustotal.com/gui/collection/{collection["id"]}',
            }
        )

    type_str = collection_type.replace("-", " ")
    type_context = type_str.title().replace(" ", "")
    type_title = f"{type_str[:-1]}ies" if type_str.endswith("y") else f"{type_str}s"

    return CommandResults(
        outputs_prefix=f"{INTEGRATION_ENTRY_CONTEXT}.{type_context}",
        outputs_key_field="id",
        readable_output=tableToMarkdown(
            f'Curated {type_title} of {resource_type}: "{resource}"',
            collections,
            headers=[
                "name",
                "last_modification_date",
                "targeted_regions",
                "targeted_industries",
                "link",
            ],
            headerTransform=string_to_table_header,
        ),
        outputs={
            "id": resource,
            "collections": data,
        },
        raw_response=raw_response,
    )


def get_curated_campaigns_command(client: Client, args: dict) -> CommandResults:
    """Get Google Threat Intelligence campaigns for a given resource."""
    return _get_curated_collections_command(client, args, "campaign")


def get_curated_malware_families_command(client: Client, args: dict) -> CommandResults:
    """Get Google Threat Intelligence malware families for a given resource."""
    return _get_curated_collections_command(client, args, "malware-family")


def get_curated_threat_actors_command(client: Client, args: dict) -> CommandResults:
    """Get Google Threat Intelligence threat actors for a given resource."""
    return _get_curated_collections_command(client, args, "threat-actor")


def arg_to_relationships(arg):
    """Get an argument and return the relationship list."""
    return (",".join(argToList(arg))).replace("* ", "").replace(" ", "_")


def main(params: dict, args: dict, command: str):
    results: Union[CommandResults, str, List[CommandResults]]
    handle_proxy()
    client = Client(params)
    score_calculator = ScoreCalculator(params)

    ip_relationships = arg_to_relationships(params.get("ip_relationships"))
    url_relationships = arg_to_relationships(params.get("url_relationships"))
    domain_relationships = arg_to_relationships(params.get("domain_relationships"))
    file_relationships = arg_to_relationships(params.get("file_relationships"))

    disable_private_ip_lookup = argToBoolean(params.get("disable_private_ip_lookup", False))

    demisto.debug(f"Command called {command}")
    if command == "test-module":
        results = check_module(client)
    elif command == "file":
        results = file_command(client, score_calculator, args, file_relationships)
    elif command == "ip":
        results = ip_command(client, score_calculator, args, ip_relationships, disable_private_ip_lookup)
    elif command == "url":
        results = url_command(client, score_calculator, args, url_relationships)
    elif command == "domain":
        results = domain_command(client, score_calculator, args, domain_relationships)
    elif command == "cve":
        results = cve_command(client, score_calculator, args)
    elif command == f"{COMMAND_PREFIX}-file-sandbox-report":
        results = file_sandbox_report_command(client, args)
    elif command == f"{COMMAND_PREFIX}-passive-dns-data":
        results = passive_dns_data(client, args)
    elif command == f"{COMMAND_PREFIX}-comments-get":
        results = get_comments_command(client, args)
    elif command == f"{COMMAND_PREFIX}-comments-add":
        results = add_comments_command(client, args)
    elif command == f"{COMMAND_PREFIX}-comments-get-by-id":
        results = get_comments_by_id_command(client, args)
    elif command == f"{COMMAND_PREFIX}-comments-delete":
        results = delete_comment(client, args)
    elif command == "url-scan":
        results = scan_url_command(client, args)
    elif command == "file-scan":
        results = file_scan(client, args)
    elif command == "file-rescan":
        results = file_rescan_command(client, args)
    elif command == f"{COMMAND_PREFIX}-file-scan-upload-url":
        results = get_upload_url(client)
    elif command == f"{COMMAND_PREFIX}-search":
        results = search_command(client, args)
    elif command == f"{COMMAND_PREFIX}-analysis-get":
        results = get_analysis_command(client, args)
    elif command == f"{COMMAND_PREFIX}-file-sigma-analysis":
        results = file_sigma_analysis_command(client, args)
    elif command == f"{COMMAND_PREFIX}-privatescanning-file":
        results = private_file_command(client, args)
    elif command == f"{COMMAND_PREFIX}-privatescanning-file-scan":
        results = private_file_scan(client, args)
    elif command == f"{COMMAND_PREFIX}-privatescanning-url":
        results = private_url_command(client, args)
    elif command == f"{COMMAND_PREFIX}-privatescanning-url-scan":
        results = private_scan_url_command(client, args)
    elif command == f"{COMMAND_PREFIX}-privatescanning-analysis-get":
        results = private_get_analysis_command(client, args)
    elif command == f"{COMMAND_PREFIX}-assessment-get":
        results = get_assessment_command(client, score_calculator, args)
    elif command == f"{COMMAND_PREFIX}-file-scan-and-analysis-get":
        results = file_scan_and_get_analysis(client, score_calculator, args, file_relationships)
    elif command == f"{COMMAND_PREFIX}-private-file-scan-and-analysis-get":
        results = private_file_scan_and_get_analysis(client, args)
    elif command == f"{COMMAND_PREFIX}-url-scan-and-analysis-get":
        results = url_scan_and_get_analysis(client, score_calculator, args, url_relationships)
    elif command == f"{COMMAND_PREFIX}-private-url-scan-and-analysis-get":
        results = private_url_scan_and_get_analysis(client, args)
    elif command == f"{COMMAND_PREFIX}-curated-campaigns-get":
        results = get_curated_campaigns_command(client, args)
    elif command == f"{COMMAND_PREFIX}-curated-malware-families-get":
        results = get_curated_malware_families_command(client, args)
    elif command == f"{COMMAND_PREFIX}-curated-threat-actors-get":
        results = get_curated_threat_actors_command(client, args)
    else:
        raise NotImplementedError(f"Command {command} not implemented")
    return_results(results)


if __name__ in ("builtins", "__builtin__", "__main__"):
    try:
        main(demisto.params(), demisto.args(), demisto.command())
    except Exception as exception:
        return_error(exception)