CensysV2

Built on the industry’s most comprehensive Internet Map, the Censys Platform delivers unmatched visibility into global internet assets, adversary infrastructure, and evolving threats.

Data Enrichment & Threat Intelligence · Censys

Details

IDCensysV2
ProviderCensys
CategoryData Enrichment & Threat Intelligence
From Version6.0.0
Docker Imagedemisto/python3:3.12.13.10116658
Supported ModulesAgentix XSIAM

README

Built on the industry’s most comprehensive Internet Map, the Censys Platform delivers unmatched visibility into global internet assets, adversary infrastructure, and evolving threats.
This integration was integrated and tested with version 2.0 of Censys.

Some changes have been made that might affect your existing content.
If you are upgrading from a previous of this integration, see Breaking Changes.

Configure Censys v2 in Cortex

Parameter Description Required
Server URL The URL of the Censys API server. True
API Token Personal Access Token from Censys Platform True
Organization ID The unique identifier for your Censys organization. True
Trust any certificate (not secure)   False
Use system proxy settings   False
Determine IP score by labels (for paid subscribers) Censys API provides reputation data exclusively to paid subscribers.
When set to True, the integration will use labels to determine the IP score.
False
IP Malicious labels Used only when `Determine IP score by labels` is set.
Labels to classify IP as Malicious.
Input can be an array or comma-separated values.
False
IP Suspicious labels Used when `Determine IP score by labels` is set.
Labels to classify IP as Suspicious.
Input can be an array or comma-separated values.
False
Malicious labels threshold Determines the minimum number of labels returned that are classified as malicious for IP. False
Suspicious labels threshold Determines the minimum number of labels returned that are classified as suspicious for IP. False
Source Reliability Reliability of the source providing the intelligence data.  

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.

cen-view


Returns detailed information for an IP address or SHA256 within the specified index.

Base Command

cen-view

Input

Argument Name Description Required
query The IP address of the requested host. Required
index The index from which to retrieve data. Possible values are: ipv4, certificates. Required

Context Output

Path Type Description
Censys.View.autonomous_system.asn Number The autonomous system number (ASN) that the host is in.
Censys.View.autonomous_system.bgp_prefix String The autonomous system’s CIDR.
Censys.View.autonomous_system.country_code String The autonomous system’s two-letter, ISO 3166-1 alpha-2 country code (e.g., US, CN, GB, RU).
Censys.View.autonomous_system.description String A brief description of the autonomous system.
Censys.View.autonomous_system.name String The friendly name of the autonomous system.
Censys.View.dns.names String DNS Names.
Censys.View.ip String The host’s IP address.
Censys.View.location.continent String The continent of the host’s detected location (e.g., North America, Europe, Asia, South America, Africa, Oceania).
Censys.View.location.coordinates Unknown The estimated coordinates of the host’s detected location.
Censys.View.location.country String The name of the country of the host’s detected location.
Censys.View.location.country_code String The two-letter ISO 3166-1 alpha-2 country code of the host’s detected location (e.g., US, CN, GB, RU).
Censys.View.location.postal_code String The postal code (if applicable) of the host’s detected location.
Censys.View.location.timezone String The IANA time zone database name of the host’s detected location.
Censys.View.services.dns Unknown DNS information.
Censys.View.services.port Number The port the service was reached at.
Censys.View.services.protocol String The name of the service on the port. This is typically the L7 protocol (e.g., “HTTP”); however, in the case that a more specific HTTP-based protocol is found (e.g., Kubernetes or Prometheus), the field will show that. This field indicates where protocol-specific data will be located.
Censys.View.services.transport_protocol String The transport protocol (known in OSI model as L4) used to contact this service (i.e., UDP or TCP).
Censys.View.services.banner String The banner as a part of the protocol scan. That field will be nested in the protocol-specific data under the service_name field.
Censys.View.services.cert Unknown A subset of the parsed details of the certificate, including the issuer, subject, fingerprint, names, public keys, and signature.
Censys.View.fingerprint_sha256 String The SHA2-256 digest over the DER encoding of the certificate.
Censys.View.fingerprint_md5 String The MD5 digest over the DER encoding of the certificate.
Censys.View.fingerprint_sha1 String The SHA1 digest over the DER encoding of the certificate.
Censys.View.fingerprint_sha256 String The SHA2-256 digest over the DER encoding of the certificate.
Censys.View.parsed.issuer.common_name String Common name.
Censys.View.parsed.issuer.country String Country name.
Censys.View.parsed.issuer.organization String Organization name.
Censys.View.parsed.issuer_dn String Information about the certificate authority that issued the certificate.
Censys.View.parsed.serial_number String The issuer-specific identifier of the certificate.
Censys.View.parsed.signature.signature_algorithm.name String Name of signature algorithm, e.g., SHA1-RSA or ECDSA-SHA512. Unknown algorithms get an integer ID.
Censys.View.parsed.signature.signature_algorithm.oid String The object identifier of the signature algorithm, in dotted-decimal notation.
Censys.View.parsed.subject.common_name String Common name.
Censys.View.parsed.subject.country String Country name.
Censys.View.parsed.subject.locality String Locality name.
Censys.View.parsed.subject.organization String The name of the organization to which the certificate was issued, if available.
Censys.View.parsed.subject.province String State of province name.
Censys.View.parsed.subject_dn String Information about the entity that was issued the certificate.
Censys.View.parsed.subject_key_info.fingerprint_sha256 String The SHA2-256 digest calculated over the certificate’s DER encoding.
Censys.View.parsed.subject_key_info.key_algorithm.name String Name of public key type, e.g., RSA or ECDSA.
IP.Address String IP address.
IP.ASN String The autonomous system name for the IP address, for example: “AS8948”.
IP.Geo.Location String The geolocation where the IP address is located, in the format: latitude:longitude.
IP.Geo.Country String The country in which the IP address is located.
IP.Geo.Description String Additional information about the location.
IP.ASOwner String The autonomous system owner of the IP.
DBotScore.Indicator String The indicator that was tested.
DBotScore.Type String The indicator type.
DBotScore.Vendor String The vendor used to calculate the score.
DBotScore.Score Number The actual score.

Command example

!cen-view index=ipv4 query=8.8.8.8

Context Example

{
    "Censys": {
        "View": {
            "autonomous_system": {
                "asn": 15169,
                "bgp_prefix": "8.8.8.0/24",
                "country_code": "US",
                "description": "GOOGLE - Google LLC",
                "name": "GOOGLE - Google LLC"
            },
            "dns": {
                "forward_dns": {
                    "2.fangji123.xyz": {
                        "name": "2.fangji123.xyz",
                        "record_type": "a",
                        "resolve_time": "2026-01-28T02:58:34Z"
                    }
                }
            }
        }
    }
}

cen-search


Return previews of hosts matching a specified search query or a list of certificates that match the given query.

Base Command

cen-search

Input

Argument Name Description Required
query Query used to search for hosts with matching attributes. Uses the Censys Search Language. Required
page_size The maximum number of hits to return in each response (minimum of 0, maximum of 100). (Applies for the host search.). Default is 50. Optional
limit The number of results to return. Default is 50. Optional
index The index from which to retrieve data. Possible values are: ipv4, certificates. Required
fields The fields to return. (Applies for the certificates search.). Optional

Context Output

Path Type Description
Censys.Search.autonomous_system.asn Number The autonomous system number (ASN) that the host is in.
Censys.Search.autonomous_system.bgp_prefix String The autonomous system’s CIDR.
Censys.Search.autonomous_system.country_code String The autonomous system’s two-letter, ISO 3166-1 alpha-2 country code (e.g., US, CN, GB, RU).
Censys.Search.autonomous_system.description String A brief description of the autonomous system.
Censys.Search.autonomous_system.name String The friendly name of the autonomous system.
Censys.Search.ip String The host’s IP address.
Censys.Search.location.continent String The continent of the host’s detected location (e.g., North America, Europe, Asia, South America, Africa, Oceania).
Censys.Search.location.coordinates Unknown The estimated coordinates of the host’s detected location.
Censys.Search.location.country String The country of the host’s detected location.
Censys.Search.location.country_code String The two-letter ISO 3166-1 alpha-2 country code of the host’s detected location (e.g., US, CN, GB, RU).
Censys.Search.location.timezone String The IANA time zone database name of the host’s detected location.
Censys.Search.services.port Number The port the service was reached at.
Censys.Search.services.protocol String The name of the service on the port. This is typically the L7 protocol (e.g., “HTTP”); however, in case a more specific HTTP-based protocol is found (e.g., Kubernetes or Prometheus), the field will show that. This field indicates where protocol-specific data will be located.
Censys.Search.services.transport_protocol String The transport protocol (known in OSI model as L4) used to contact this service (i.e., UDP or TCP).
Censys.Search.fingerprint_sha256 String SHA 256 fingerprint.
Censys.Search.parsed.issuer.organization Unknown The organization name.
Censys.Search.names Unknown Common names for the entity.
Censys.Search.parsed.subject_dn String Distinguished name of the entity that the certificate belongs to.
Censys.Search.parsed.validity_period.not_after Date Timestamp of when the certificate expires. Time zone is UTC.
Censys.Search.parsed.validity_period.not_before Date Timestamp of when the certificate is first valid. Time zone is UTC.
Censys.Search.parsed.issuer_dn String Distinguished name of the entity that has signed and issued the certificate.
Censys.Search.parsed.subject.common_name String Common name(s) from the certificate subject.
Censys.Search.parsed.signature.self_signed Boolean Whether the certificate is self-signed.
Censys.Search.valid_to String Timestamp of when the certificate is valid to.
Censys.Search.self_signed Boolean Whether the certificate is self-signed.

Command example

!cen-search index=certificates query="cert.parsed.issuer.common_name: \"Let's Encrypt\"" limit=1

Context Example

{
    "Censys": {
        "Search": {
            "fingerprint_sha256": "0003da4aee3b252097bfc7f871ab6fbe3e08eb94c34ff5cea91aaa29248d3c8b",
            "parsed": {
                "issuer": {
                    "organization": [
                        "Let's Encrypt"
                    ]
                },
                "issuer_dn": "C=US, ST=Let's Encrypt, O=Let's Encrypt, CN=Let's Encrypt Authority X3",
                "subject_dn": "C=AU, ST=Some-State, O=Internet Widgits Pty Ltd",
                "validity_period": {
                    "not_after": "2026-04-15T00:50:59Z",
                    "not_before": "2025-04-15T00:50:59Z"
                }
            }
        }
    }
}

Human Readable Output

Search results for query “cert.parsed.issuer.common_name: “Let’s Encrypt””

Issuer Issuer DN SHA256 Subject DN Validity not after Validity not before
Let’s Encrypt C=US, ST=Let’s Encrypt, O=Let’s Encrypt, CN=Let’s Encrypt Authority X3 0003da4aee3b252097bfc7f871ab6fbe3e08eb94c34ff5cea91aaa29248d3c8b C=AU, ST=Some-State, O=Internet Widgits Pty Ltd 2026-04-15T00:50:59Z 2025-04-15T00:50:59Z

Command example

!cen-search index=ipv4 query="host.services.protocol:HTTP" limit=1

Context Example

{
    "Censys": {
        "Search": {
            "autonomous_system": {
                "asn": 4766,
                "bgp_prefix": "10.0.0.0/12",
                "country_code": "KR",
                "description": "KIXS-AS-KR Korea Telecom",
                "name": "KIXS-AS-KR Korea Telecom"
            },
            "dns": {
            }
        }
    }
}

domain


Return all related IPs as relationships.

Base Command

domain

Input

Argument Name Description Required
domain A comma-separated list of domains to check. Required
port A comma-separated list of ports associated with the domain. Default is 80,443. Optional

Context Output

Path Type Description
Censys.Domain.location.postal_code String The postal code of the location associated with the domain.
Censys.Domain.location.province String The province name of the location associated with the domain.
Censys.Domain.location.country_code String The country code of the location associated with the domain.
Censys.Domain.location.timezone String The time zone of the location associated with the domain.
Censys.Domain.location.country String The country name of the location associated with the domain.
Censys.Domain.location.coordinates.longitude Number The longitude coordinate of the location associated with the domain.
Censys.Domain.location.coordinates.latitude Number The latitude coordinate of the location associated with the domain.
Censys.Domain.location.continent String The continent name of the location associated with the domain.
Censys.Domain.location.city String The city name of the location associated with the domain.
Censys.Domain.autonomous_system.country_code String The country code of the autonomous system associated with the domain.
Censys.Domain.autonomous_system.asn Number The Autonomous System Number (ASN) associated with the domain.
Censys.Domain.autonomous_system.name String The name of the autonomous system associated with the domain.
Censys.Domain.autonomous_system.bgp_prefix String The BGP prefix of the autonomous system associated with the domain.
Censys.Domain.autonomous_system.description String The description of the autonomous system associated with the domain.
Censys.Domain.services.transport_protocol String The transport protocol used by the service associated with the domain.
Censys.Domain.services.port Number The port number associated with the service associated with the domain.
Censys.Domain.services.protocol String The name of the service associated with the domain.
Censys.Domain.services.cert String The SSL/TLS certificate associated with the service associated with the domain.
Censys.Domain.ip String The IP address associated with the domain.
Censys.Domain.dns.reverse_dns.names String The reverse DNS names associated with the domain.
Censys.Domain.hostname String The hostname of the web property associated with the domain.
Censys.Domain.port Number The port number of the web property associated with the domain.
Censys.Domain.labels.value String Labels associated with the web property.
Censys.Domain.threats.name String Threat names associated with the web property.
Censys.Domain.vulns.id String Vulnerability IDs associated with the web property.
Censys.Domain.vulns.cvss Number CVSS scores for vulnerabilities associated with the web property.
Censys.Domain.vulns.severity String Severity levels for vulnerabilities associated with the web property.
Censys.Domain.software.vendor String Software vendors detected on the web property.
Censys.Domain.software.product String Software products detected on the web property.
Censys.Domain.software.version String Software versions detected on the web property.
Censys.Domain.cert.fingerprint_sha256 String SHA-256 fingerprint of the certificate associated with the web property.
Censys.Domain.cert.parsed.subject_dn String Subject DN of the certificate associated with the web property.
Censys.Domain.cert.parsed.issuer_dn String Issuer DN of the certificate associated with the web property.
Censys.Domain.tls.version_selected String TLS version selected for the web property.
Censys.Domain.tls.cipher_selected String Cipher suite selected for the web property.
Censys.Domain.endpoints.endpoint_type String Endpoint types associated with the web property.
Censys.Domain.endpoints.path String Endpoint paths associated with the web property.
Censys.Domain.jarm.fingerprint String JARM fingerprint of the web property.
Censys.Domain.scan_time String Scan time for the web property.
Domain.Name string The domain.
Domain.Relationships.EntityA string The domain name.
Domain.Relationships.EntityAType string The entity type.
Domain.Relationships.EntityB string The entity B.
Domain.Relationships.EntityBType string The entity B type.
Domain.Relationships.Relationship string The relationship type.
DBotScore.Indicator unknown The indicator that was tested.
DBotScore.Type unknown The indicator type.
DBotScore.Score unknown The actual score.
DBotScore.Vendor unknown The vendor used to calculate the score.

Command example

!domain domain=amazon.com,google.com

Context Example

{
    "Censys": {
        "Domain": [
            {
                "autonomous_system": {
                    "asn": 14618,
                    "bgp_prefix": "10.0.0.0/13",
                    "country_code": "US",
                    "description": "AMAZON-AES - Amazon.com, Inc.",
                    "name": "AMAZON-AES - Amazon.com, Inc."
                },
                "dns": {
                    "forward_dns": {
                        "amazon.com": {
                            "name": "amazon.com",
                            "record_type": "a",
                            "resolve_time": "2026-01-27T20:29:15Z"
                        }
                    },
                    "names": [
                        "amazon.com"
                    ],
                    "reverse_dns": {
                        "names": [
                            "ec2-192-0-2-1.compute-1.amazonaws.com"
                        ],
                        "resolve_time": "2026-01-13T16:21:30Z"
                    }
                },
                "ip": "192.0.2.1",
                "location": {
                    "city": "Ashburn",
                    "continent": "North America",
                    "coordinates": {
                        "latitude": 39.04372,
                        "longitude": -77.48749
                    },
                    "country": "United States",
                    "country_code": "US",
                    "postal_code": "20147",
                    "province": "Virginia",
                    "timezone": "America/New_York"
                },
                "service_count": 2,
                "services": [
                    {
                        "port": 80,
                        "protocol": "HTTP",
                        "transport_protocol": "tcp"
                    },
                    {
                        "banner": "HTTP/1.1 400 Bad Request\r\nServer: Server\r\nDate:  <REDACTED>\r\nContent-Type: text/html\r\nTransfer-Encoding: chunked\r\nConnection: close\r\n",
                        "banner_hash_sha256": "0269a8a467d7591227ba20e7be6f0992ff31791f5235e31a60fc5ff168a4c921",
                        "cert": {
                            "added_at": "2025-11-06T17:17:35Z",
                            "ct": {
                                "entries": {
                                    "cloudflare_nimbus_2026": {
                                        "added_to_ct_at": "2025-11-06T17:48:17Z",
                                        "ct_to_censys_at": "2025-11-06T18:54:38Z",
                                        "index": 846730169
                                    },
                                    "google_argon_2026_h2": {
                                        "added_to_ct_at": "2025-11-06T17:41:18Z",
                                        "ct_to_censys_at": "2025-11-06T17:45:17Z",
                                        "index": 189639680
                                    },
                                    "google_xenon_2026_h2": {
                                        "added_to_ct_at": "2025-11-06T17:41:18Z",
                                        "ct_to_censys_at": "2025-11-06T17:51:37Z",
                                        "index": 143726358
                                    },
                                    "letsencrypt_ct_oak_2026_h2": {
                                        "added_to_ct_at": "2025-11-06T17:41:18Z",
                                        "ct_to_censys_at": "2025-11-06T17:49:49Z",
                                        "index": 117540704
                                    },
                                    "letsencrypt_ct_sycamore_2026_h2": {
                                        "added_to_ct_at": "2025-11-06T17:45:49Z",
                                        "ct_to_censys_at": "2025-12-12T18:19:25Z",
                                        "index": 22212155
                                    },
                                    "letsencrypt_ct_willow_2026_h2": {
                                        "added_to_ct_at": "2025-11-06T17:46:09Z",
                                        "ct_to_censys_at": "2025-12-12T19:58:13Z",
                                        "index": 22208638
                                    },
                                    "trustasia_log_2026_a": {
                                        "added_to_ct_at": "2025-11-17T04:30:41Z",
                                        "ct_to_censys_at": "2025-11-17T18:18:36Z",
                                        "index": 88656657
                                    },
                                    "trustasia_log_2026_b": {
                                        "added_to_ct_at": "2025-11-10T06:27:14Z",
                                        "ct_to_censys_at": "2025-11-10T06:32:24Z",
                                        "index": 86980442
                                    }
                                }
                            },
                            "ever_seen_in_scan": true,
                            "fingerprint_md5": "3a20cd834e379eb01e8fca18625a095b",
                            "fingerprint_sha1": "3152b1059fa057395743ea0ca8068c6dccd133c5",
                            "fingerprint_sha256": "8c062771b98a854ef04f86bc5e3a97366a927c6c3fcc2647c67b988aceea3092",
                            "modified_at": "2025-12-12T19:58:13Z",
                            "names": [
                                "*.aa.peg.a2z.com",
                                "*.ab.peg.a2z.com",
                                "*.ac.peg.a2z.com",
                                "*.bz.peg.a2z.com",
                                "*.peg.a2z.com",
                                "amazon.co.jp",
                                "amazon.co.uk",
                                "amazon.com",
                                "amazon.com.au",
                                "amazon.de",
                                "amazon.jp",
                                "amzn.com",
                                "buckeye-retail-website.amazon.com",
                                "buybox.amazon.com",
                                "corporate.amazon.com",
                                "edgeflow-dp.aero.04f01a85e-frontier.amazon.com.au",
                                "edgeflow-dp.aero.47cf2c8c9-frontier.amazon.com",
                                "edgeflow-dp.aero.4d5ad1d2b-frontier.amazon.co.jp",
                                "edgeflow-dp.aero.abe2c2f23-frontier.amazon.de",
                                "edgeflow-dp.aero.bfbdc3ca1-frontier.amazon.co.uk",
                                "edgeflow.aero.04f01a85e-frontier.amazon.com.au",
                                "edgeflow.aero.47cf2c8c9-frontier.amazon.com",
                                "edgeflow.aero.4d5ad1d2b-frontier.amazon.co.jp",
                                "edgeflow.aero.abe2c2f23-frontier.amazon.de",
                                "edgeflow.aero.bfbdc3ca1-frontier.amazon.co.uk",
                                "home.amazon.com",
                                "huddles.amazon.com",
                                "iphone.amazon.com",
                                "origin-www.amazon.co.jp",
                                "origin-www.amazon.co.uk",
                                "origin-www.amazon.com",
                                "origin-www.amazon.com.au",
                                "origin-www.amazon.de",
                                "origin2-www.amazon.co.jp",
                                "origin2-www.amazon.com",
                                "uedata.amazon.co.uk",
                                "uedata.amazon.com",
                                "us.amazon.com",
                                "www.amazon.co.jp",
                                "www.amazon.co.uk",
                                "www.amazon.com",
                                "www.amazon.com.au",
                                "www.amazon.de",
                                "www.amazon.jp",
                                "www.amzn.com",
                                "yp.amazon.com"
                            ],
                            "parent_spki_fingerprint_sha256": "a0f06408dfb8d5e0095d4a968536efd3ecdc75025691b142170e7eb66c85b39a",
                            "parent_spki_subject_fingerprint_sha256": "a0f06408dfb8d5e0095d4a968536efd3ecdc75025691b142170e7eb66c85b39a",
                            "parse_status": "success",
                            "parsed": {
                                "extensions": {
                                    "authority_info_access": {
                                        "issuer_urls": [
                                            "http://example.com/cacerts/DigiCertGlobalCAG2.crt"
                                        ],
                                        "ocsp_urls": [
                                            "http://example.com/ocsp"
                                        ]
                                    },
                                    "authority_key_id": "246e2b2dd06a925151256901aa9a47a689e74020",
                                    "basic_constraints": {},
                                    "certificate_policies": [
                                        {
                                            "cps": [
                                                "http://example.com/CPS"
                                            ],
                                            "id": "1.2.3.4.5.6.7"
                                        }
                                    ],
                                    "crl_distribution_points": [
                                        "http://example.com/crl/DigiCertGlobalCAG2.crl",
                                        "http://example.com/crl2/DigiCertGlobalCAG2.crl"
                                    ],
                                    "extended_key_usage": {
                                        "client_auth": true,
                                        "server_auth": true
                                    },
                                    "key_usage": {
                                        "digital_signature": true,
                                        "key_encipherment": true,
                                        "value": 5
                                    },
                                    "signed_certificate_timestamps": [
                                        {
                                            "log_id": "d809553b944f7affc816196f944f85abb0f8fc5e8755260f15d12e72bb454b14",
                                            "signature": {
                                                "hash_algorithm": "SHA256",
                                                "signature": "304402203a1a41e357a63d9b599cadecafc2215d60f6b884187b02df237bb196c262d4dd02201431d3cca905bc2ba7bdbc5891269976330bd6696fcc6e4509ace0c82a5b80d8",
                                                "signature_algorithm": "ECDSA"
                                            },
                                            "timestamp": "2025-11-06T16:37:35Z"
                                        },
                                        {
                                            "log_id": "c2317e574519a345ee7f38deb29041ebc7c2215a22bf7fd5b5ad769ad90e52cd",
                                            "signature": {
                                                "hash_algorithm": "SHA256",
                                                "signature": "3045022100fd699c45d2e93df414102920a416677928078dd171201f18250ada49aecf84f202204f3f00142c85bb1e2973c106b856c7b9ec2af1958acfbdcc8c6aedf3e5d00d64",
                                                "signature_algorithm": "ECDSA"
                                            },
                                            "timestamp": "2025-11-06T16:37:35Z"
                                        },
                                        {
                                            "log_id": "944e4387faecc1ef81f3192426a8186501c7d35f3802013f72677d55372e19d8",
                                            "signature": {
                                                "hash_algorithm": "SHA256",
                                                "signature": "30440220432960ef2fde72dab8edc759403700640c61392d80df91c3688876a43b9d24f2022013695dd7abbe84eac82469bb7a6c37afd8a8999eac07d1ed330e41e1495b186d",
                                                "signature_algorithm": "ECDSA"
                                            },
                                            "timestamp": "2025-11-06T16:37:35Z"
                                        }
                                    ],
                                    "subject_alt_name": {
                                        "dns_names": [
                                            "amazon.co.uk",
                                            "uedata.amazon.co.uk",
                                            "www.amazon.co.uk",
                                            "origin-www.amazon.co.uk",
                                            "*.peg.a2z.com",
                                            "amazon.com",
                                            "amzn.com",
                                            "uedata.amazon.com",
                                            "us.amazon.com",
                                            "www.amazon.com",
                                            "www.amzn.com",
                                            "corporate.amazon.com",
                                            "buybox.amazon.com",
                                            "iphone.amazon.com",
                                            "yp.amazon.com",
                                            "home.amazon.com",
                                            "origin-www.amazon.com",
                                            "origin2-www.amazon.com",
                                            "buckeye-retail-website.amazon.com",
                                            "huddles.amazon.com",
                                            "amazon.de",
                                            "www.amazon.de",
                                            "origin-www.amazon.de",
                                            "amazon.co.jp",
                                            "amazon.jp",
                                            "www.amazon.jp",
                                            "www.amazon.co.jp",
                                            "origin-www.amazon.co.jp",
                                            "*.aa.peg.a2z.com",
                                            "*.ab.peg.a2z.com",
                                            "*.ac.peg.a2z.com",
                                            "origin-www.amazon.com.au",
                                            "www.amazon.com.au",
                                            "*.bz.peg.a2z.com",
                                            "amazon.com.au",
                                            "origin2-www.amazon.co.jp",
                                            "edgeflow.aero.4d5ad1d2b-frontier.amazon.co.jp",
                                            "edgeflow.aero.04f01a85e-frontier.amazon.com.au",
                                            "edgeflow.aero.47cf2c8c9-frontier.amazon.com",
                                            "edgeflow.aero.abe2c2f23-frontier.amazon.de",
                                            "edgeflow.aero.bfbdc3ca1-frontier.amazon.co.uk",
                                            "edgeflow-dp.aero.4d5ad1d2b-frontier.amazon.co.jp",
                                            "edgeflow-dp.aero.04f01a85e-frontier.amazon.com.au",
                                            "edgeflow-dp.aero.47cf2c8c9-frontier.amazon.com",
                                            "edgeflow-dp.aero.bfbdc3ca1-frontier.amazon.co.uk",
                                            "edgeflow-dp.aero.abe2c2f23-frontier.amazon.de"
                                        ]
                                    },
                                    "subject_key_id": "aaf8a5eaec987c7117d41fbd39c95f7b71020a1e"
                                },
                                "issuer": {
                                    "common_name": [
                                        "DigiCert Global CA G2"
                                    ],
                                    "country": [
                                        "US"
                                    ],
                                    "organization": [
                                        "DigiCert Inc"
                                    ]
                                },
                                "issuer_dn": "C=US, O=DigiCert Inc, CN=DigiCert Global CA G2",
                                "ja4x": "a373a9f83c6b_7022c563de38_2cdf432ec278",
                                "serial_number": "1377932119697704108067612670015473867",
                                "serial_number_hex": "0109614c77ec09ea900f923281c688cb",
                                "signature": {
                                    "signature_algorithm": {
                                        "name": "SHA256-RSA",
                                        "oid": "1.2.840.113549.1.1.11"
                                    },
                                    "valid": true,
                                    "value": "8fcff8d419d57562f4f719a070ea5a2c02083c40f966aab18848094b6cc9b76156f887193adfe5a09f3f384f060dfd0b31acfdd0c0cb7e86d51e681940044fb2f116f59b58c2d962b7796e9727c029f695b5790c2ed398b3f8129088a30327951477e11df26c7eb3675edf61051e9f64b97d85d58ee3d5b411cf17be2fd9431edfa0a32c4a1f5672465a0bb5c0f60f995c68a743bc4db9fb58e3c975a50055a92edc81ae9da05609de2dc49870f4ccb1f52f772aff214190a8ac9c3dda583ce7e0b5deb5157d583a2a0dfb4e8f80f07cd6cf8e3ddd18aff99660740f32cb45c4d2ec1ef30db280ae0de0ef77e12f5637bf4bef8e1cc245a3f29855a81bd466f5"
                                },
                                "subject": {
                                    "common_name": [
                                        "*.peg.a2z.com"
                                    ]
                                },
                                "subject_dn": "CN=*.peg.a2z.com",
                                "subject_key_info": {
                                    "fingerprint_sha256": "325f1c87dc001e02a27de95ec7774bfb6d4b2ccf9ef5d5161696ff9936410fba",
                                    "key_algorithm": {
                                        "name": "RSA",
                                        "oid": "1.2.840.113549.1.1.1"
                                    },
                                    "rsa": {
                                        "exponent": 65537,
                                        "length": 2048,
                                        "modulus": "b865ad75cfa6bc86c43f193a00b6c712d249f7a0c2d8410dbd65a7480333439802acae4eed23ef679fd90931caa55b8949faf283d76b8767e983cde784d3c5ec860361165458fbbb24989b1abff67129eeba7d33f808a68b518641a05839ec5f87846863e3ba9379c230d23091a8d6c758b486d19a2d11ae97c5c06e951d5d3ecf927fc162b42fd00cfc623f2fa886cd8f14448fc155cd12e48bbe571fbafb532299fc9e816683953d254865fafe657097195a205dd53bcf400dc65c7b2960e46a02ec48534e517c1cb3f211cc75ca70166bba67d4587420cc0c2083aba4f0858dcbb2bc74f2f7ac14e9dd4d24516bd53037559263fd5a50656f39940aba6ce3"
                                    }
                                },
                                "validity_period": {
                                    "length_seconds": 27648000,
                                    "not_after": "2026-09-21T23:59:59Z",
                                    "not_before": "2025-11-06T00:00:00Z"
                                },
                                "version": 3
                            },
                            "revocation": {
                                "crl": {
                                    "reason": "unspecified"
                                },
                                "ocsp": {
                                    "reason": "unspecified"
                                }
                            },
                            "spki_fingerprint_sha256": "395a16ab1bc812de8784405859a631ac6519e85543fd9e7dbc8c52b33f865dc8",
                            "spki_subject_fingerprint_sha256": "395a16ab1bc812de8784405859a631ac6519e85543fd9e7dbc8c52b33f865dc8",
                            "tbs_fingerprint_sha256": "9cd2c97a60d07862c482661096c0239fcc60a689fd86db77133908a4dc562c4d",
                            "tbs_no_ct_fingerprint_sha256": "34752e5613070cd06115be2c4a2b8df47a53faef804055febc682db29a889f64",
                            "validated_at": "2026-01-27T19:29:18Z",
                            "validation": {
                                "apple": {
                                    "chains": [
                                        {
                                            "sha256fp": [
                                                "8fac576439c9fd3ef153b51f9edd0d381b5df7b87559cebeca04297dd44a639b",
                                                "cb3ccbb76031e5e0138f8dd39a23f9de47ffc35e43c1144cea27d46a5ab1cb5f"
                                            ]
                                        },
                                        {
                                            "sha256fp": [
                                                "8fac576439c9fd3ef153b51f9edd0d381b5df7b87559cebeca04297dd44a639b",
                                                "6523c34f1e879add7603cb2048a898a5e2f0c6c4b512c0d22782b85d43ae3371",
                                                "4348a0e9444c78cb265e058d5e8944b4d84f9662bd26db257f8934a443c70161"
                                            ]
                                        },
                                        {
                                            "sha256fp": [
                                                "8fac576439c9fd3ef153b51f9edd0d381b5df7b87559cebeca04297dd44a639b",
                                                "79d57b15dfa65c2870eafe11b637765909cfe937b49c15ce7f194030cab395ad",
                                                "4348a0e9444c78cb265e058d5e8944b4d84f9662bd26db257f8934a443c70161"
                                            ]
                                        },
                                        {
                                            "sha256fp": [
                                                "8fac576439c9fd3ef153b51f9edd0d381b5df7b87559cebeca04297dd44a639b",
                                                "a0d609a7e3c434e878a9a1c1bd065b8dcf33aa7efee1b11bc75cce5e5a042080",
                                                "7431e5f4c3c1ce4690774f0b61e05440883ba9a01ed00ba6abd7806ed3b118cf"
                                            ]
                                        },
                                        {
                                            "sha256fp": [
                                                "8fac576439c9fd3ef153b51f9edd0d381b5df7b87559cebeca04297dd44a639b",
                                                "caf8ad697f7bda712ab127a8ad8b83f74a91a0de1784a1b483fef9ac79b67513",
                                                "7431e5f4c3c1ce4690774f0b61e05440883ba9a01ed00ba6abd7806ed3b118cf"
                                            ]
                                        }
                                    ],
                                    "ever_valid": true,
                                    "had_trusted_path": true,
                                    "has_trusted_path": true,
                                    "is_valid": true,
                                    "parents": [
                                        "8fac576439c9fd3ef153b51f9edd0d381b5df7b87559cebeca04297dd44a639b"
                                    ],
                                    "type": "leaf"
                                },
                                "chrome": {
                                    "chains": [
                                        {
                                            "sha256fp": [
                                                "8fac576439c9fd3ef153b51f9edd0d381b5df7b87559cebeca04297dd44a639b",
                                                "cb3ccbb76031e5e0138f8dd39a23f9de47ffc35e43c1144cea27d46a5ab1cb5f"
                                            ]
                                        },
                                        {
                                            "sha256fp": [
                                                "8fac576439c9fd3ef153b51f9edd0d381b5df7b87559cebeca04297dd44a639b",
                                                "6523c34f1e879add7603cb2048a898a5e2f0c6c4b512c0d22782b85d43ae3371",
                                                "4348a0e9444c78cb265e058d5e8944b4d84f9662bd26db257f8934a443c70161"
                                            ]
                                        },
                                        {
                                            "sha256fp": [
                                                "8fac576439c9fd3ef153b51f9edd0d381b5df7b87559cebeca04297dd44a639b",
                                                "79d57b15dfa65c2870eafe11b637765909cfe937b49c15ce7f194030cab395ad",
                                                "4348a0e9444c78cb265e058d5e8944b4d84f9662bd26db257f8934a443c70161"
                                            ]
                                        },
                                        {
                                            "sha256fp": [
                                                "8fac576439c9fd3ef153b51f9edd0d381b5df7b87559cebeca04297dd44a639b",
                                                "a0d609a7e3c434e878a9a1c1bd065b8dcf33aa7efee1b11bc75cce5e5a042080",
                                                "7431e5f4c3c1ce4690774f0b61e05440883ba9a01ed00ba6abd7806ed3b118cf"
                                            ]
                                        },
                                        {
                                            "sha256fp": [
                                                "8fac576439c9fd3ef153b51f9edd0d381b5df7b87559cebeca04297dd44a639b",
                                                "caf8ad697f7bda712ab127a8ad8b83f74a91a0de1784a1b483fef9ac79b67513",
                                                "7431e5f4c3c1ce4690774f0b61e05440883ba9a01ed00ba6abd7806ed3b118cf"
                                            ]
                                        }
                                    ],
                                    "ever_valid": true,
                                    "had_trusted_path": true,
                                    "has_trusted_path": true,
                                    "is_valid": true,
                                    "parents": [
                                        "8fac576439c9fd3ef153b51f9edd0d381b5df7b87559cebeca04297dd44a639b"
                                    ],
                                    "type": "leaf"
                                },
                                "microsoft": {
                                    "chains": [
                                        {
                                            "sha256fp": [
                                                "8fac576439c9fd3ef153b51f9edd0d381b5df7b87559cebeca04297dd44a639b",
                                                "cb3ccbb76031e5e0138f8dd39a23f9de47ffc35e43c1144cea27d46a5ab1cb5f"
                                            ]
                                        },
                                        {
                                            "sha256fp": [
                                                "8fac576439c9fd3ef153b51f9edd0d381b5df7b87559cebeca04297dd44a639b",
                                                "0ba8c0d459b76abc0825294f565e24f4f169d4a4819d0692d371522d297724b8",
                                                "2399561127a57125de8cefea610ddf2fa078b5c8067f4e828290bfb860e84b3c"
                                            ]
                                        },
                                        {
                                            "sha256fp": [
                                                "8fac576439c9fd3ef153b51f9edd0d381b5df7b87559cebeca04297dd44a639b",
                                                "6523c34f1e879add7603cb2048a898a5e2f0c6c4b512c0d22782b85d43ae3371",
                                                "4348a0e9444c78cb265e058d5e8944b4d84f9662bd26db257f8934a443c70161"
                                            ]
                                        },
                                        {
                                            "sha256fp": [
                                                "8fac576439c9fd3ef153b51f9edd0d381b5df7b87559cebeca04297dd44a639b",
                                                "79d57b15dfa65c2870eafe11b637765909cfe937b49c15ce7f194030cab395ad",
                                                "4348a0e9444c78cb265e058d5e8944b4d84f9662bd26db257f8934a443c70161"
                                            ]
                                        },
                                        {
                                            "sha256fp": [
                                                "8fac576439c9fd3ef153b51f9edd0d381b5df7b87559cebeca04297dd44a639b",
                                                "a0d609a7e3c434e878a9a1c1bd065b8dcf33aa7efee1b11bc75cce5e5a042080",
                                                "7431e5f4c3c1ce4690774f0b61e05440883ba9a01ed00ba6abd7806ed3b118cf"
                                            ]
                                        }
                                    ],
                                    "ever_valid": true,
                                    "had_trusted_path": true,
                                    "has_trusted_path": true,
                                    "is_valid": true,
                                    "parents": [
                                        "8fac576439c9fd3ef153b51f9edd0d381b5df7b87559cebeca04297dd44a639b"
                                    ],
                                    "type": "leaf"
                                },
                                "nss": {
                                    "chains": [
                                        {
                                            "sha256fp": [
                                                "8fac576439c9fd3ef153b51f9edd0d381b5df7b87559cebeca04297dd44a639b",
                                                "cb3ccbb76031e5e0138f8dd39a23f9de47ffc35e43c1144cea27d46a5ab1cb5f"
                                            ]
                                        },
                                        {
                                            "sha256fp": [
                                                "8fac576439c9fd3ef153b51f9edd0d381b5df7b87559cebeca04297dd44a639b",
                                                "6523c34f1e879add7603cb2048a898a5e2f0c6c4b512c0d22782b85d43ae3371",
                                                "4348a0e9444c78cb265e058d5e8944b4d84f9662bd26db257f8934a443c70161"
                                            ]
                                        },
                                        {
                                            "sha256fp": [
                                                "8fac576439c9fd3ef153b51f9edd0d381b5df7b87559cebeca04297dd44a639b",
                                                "79d57b15dfa65c2870eafe11b637765909cfe937b49c15ce7f194030cab395ad",
                                                "4348a0e9444c78cb265e058d5e8944b4d84f9662bd26db257f8934a443c70161"
                                            ]
                                        },
                                        {
                                            "sha256fp": [
                                                "8fac576439c9fd3ef153b51f9edd0d381b5df7b87559cebeca04297dd44a639b",
                                                "a0d609a7e3c434e878a9a1c1bd065b8dcf33aa7efee1b11bc75cce5e5a042080",
                                                "7431e5f4c3c1ce4690774f0b61e05440883ba9a01ed00ba6abd7806ed3b118cf"
                                            ]
                                        },
                                        {
                                            "sha256fp": [
                                                "8fac576439c9fd3ef153b51f9edd0d381b5df7b87559cebeca04297dd44a639b",
                                                "caf8ad697f7bda712ab127a8ad8b83f74a91a0de1784a1b483fef9ac79b67513",
                                                "7431e5f4c3c1ce4690774f0b61e05440883ba9a01ed00ba6abd7806ed3b118cf"
                                            ]
                                        }
                                    ],
                                    "ever_valid": true,
                                    "had_trusted_path": true,
                                    "has_trusted_path": true,
                                    "is_valid": true,
                                    "parents": [
                                        "8fac576439c9fd3ef153b51f9edd0d381b5df7b87559cebeca04297dd44a639b"
                                    ],
                                    "type": "leaf"
                                }
                            },
                            "validation_level": "dv",
                            "zlint": {
                                "failed_lints": [
                                    "n_subject_common_name_included"
                                ],
                                "notices_present": true,
                                "timestamp": "2025-11-06T17:17:34Z",
                                "version": 3
                            }
                        },
                        "endpoints": [
                            {
                                "banner": "HTTP/1.1 400 Bad Request\r\nServer: Server\r\nDate:  <REDACTED>\r\nContent-Type: text/html\r\nTransfer-Encoding: chunked\r\nConnection: close\r\n",
                                "banner_hash_sha256": "0269a8a467d7591227ba20e7be6f0992ff31791f5235e31a60fc5ff168a4c921",
                                "endpoint_type": "HTTP",
                                "hostname": "192.0.2.1",
                                "http": {
                                    "body": "<!DOCTYPE html><html><head><title>x</title></head><body></body></html>\n",
                                    "body_hash_sha1": "e441bba8b691ad0fff0bccb75974880018ab41d6",
                                    "body_hash_sha256": "73f8ae8c11daa6ad905107970e55c3c64cd7133561e9e91e650aab092ba7245e",
                                    "body_size": 71,
                                    "headers": {
                                        "Connection": {
                                            "headers": [
                                                "close"
                                            ]
                                        },
                                        "Content-Type": {
                                            "headers": [
                                                "text/html"
                                            ]
                                        },
                                        "Date": {
                                            "headers": [
                                                "<REDACTED>"
                                            ]
                                        },
                                        "Server": {
                                            "headers": [
                                                "Server"
                                            ]
                                        },
                                        "Transfer-Encoding": {
                                            "headers": [
                                                "chunked"
                                            ]
                                        }
                                    },
                                    "html_tags": [
                                        "<title>x</title>"
                                    ],
                                    "html_title": "x",
                                    "protocol": "HTTP/1.1",
                                    "status_code": 400,
                                    "status_reason": "Bad Request",
                                    "supported_versions": [
                                        "HTTP/1.1"
                                    ],
                                    "uri": "https://192.0.2.1/"
                                },
                                "ip": "192.0.2.1",
                                "path": "/",
                                "port": 443,
                                "scan_time": "2026-01-27T21:48:42Z",
                                "transport_protocol": "tcp"
                            }
                        ],
                        "ip": "8.8.8.8",
                        "ja4tscan": {
                            "fingerprint": "62643_2-4-8-1-3_1460_7_1-2-4-9-17",
                            "scan_time": "2026-01-27T04:00:58Z"
                        },
                        "port": 443,
                        "protocol": "HTTP",
                        "scan_time": "2026-01-27T21:48:42Z",
                        "tls": {
                            "cipher_selected": "TLS_AES_128_GCM_SHA256",
                            "fingerprint_sha256": "8c062771b98a854ef04f86bc5e3a97366a927c6c3fcc2647c67b988aceea3092",
                            "ja3s": "f4febc55ea12b31ae17cfb7e614afda8",
                            "ja4s": "t130200_1301_a56c5b993250",
                            "presented_chain": [
                                {
                                    "fingerprint_sha256": "8fac576439c9fd3ef153b51f9edd0d381b5df7b87559cebeca04297dd44a639b",
                                    "issuer_dn": "C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Global Root G2",
                                    "subject_dn": "C=US, O=DigiCert Inc, CN=DigiCert Global CA G2"
                                },
                                {
                                    "fingerprint_sha256": "aadadd5a879d2eb8c41a89597291292709d42052f5b6399541c694c3b7353cd1",
                                    "issuer_dn": "C=US, O=VeriSign\\, Inc., OU=VeriSign Trust Network, OU=(c) 2006 VeriSign\\, Inc. - For authorized use only, CN=VeriSign Class 3 Public Primary Certification Authority - G5",
                                    "subject_dn": "C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Global Root G2"
                                }
                            ],
                            "version_selected": "tlsv1_3",
                            "versions": [
                                {
                                    "ja3s": "f4febc55ea12b31ae17cfb7e614afda8",
                                    "ja4s": "t130200_1301_a56c5b993250",
                                    "version": "tlsv1_3"
                                },
                                {
                                    "ja3s": "2b1f517a72b7346c86d59ef328167d49",
                                    "ja4s": "t120300_c02f_cbb8871a0652",
                                    "version": "tlsv1_2"
                                },
                                {
                                    "ja3s": "24abcc4acb0869d8e569d403dfe55a99",
                                    "ja4s": "t110300_c013_cbb8871a0652",
                                    "version": "tlsv1_1"
                                },
                                {
                                    "ja3s": "7ac2b84fdf4dcd940d5099b55a649c04",
                                    "ja4s": "t100300_c013_cbb8871a0652",
                                    "version": "tlsv1_0"
                                }
                            ]
                        },
                        "transport_protocol": "tcp"
                    }
                ],
                "whois": {
                    "network": {
                        "allocation_type": "REALLOCATION",
                        "cidrs": [
                            "10.0.0.0/13"
                        ],
                        "created": "2024-02-21T00:00:00Z",
                        "handle": "AMAZON-IAD",
                        "name": "Amazon Data Services Northern Virginia",
                        "updated": "2024-02-21T00:00:00Z"
                    },
                    "organization": {
                        "abuse_contacts": [
                            {
                                "email": "abuse@example.com",
                                "handle": "AEA8-ARIN",
                                "name": "Amazon EC2 Abuse"
                            }
                        ],
                        "admin_contacts": [
                            {
                                "email": "admin@example.com",
                                "handle": "IPMAN40-ARIN",
                                "name": "IP Management"
                            }
                        ],
                        "city": "Herndon",
                        "country": "US",
                        "handle": "ADSN-1",
                        "name": "Amazon Data Services Northern Virginia",
                        "postal_code": "20171",
                        "state": "VA",
                        "street": "13200 Woodland Park Road",
                        "tech_contacts": [
                            {
                                "email": "noc@example.com",
                                "handle": "ANO24-ARIN",
                                "name": "Amazon EC2 Network Operations"
                            }
                        ]
                    }
                }
            }        
        ]
    },
    "DBotScore": [
        {
            "Indicator": "amazon.com",
            "Reliability": "C - Fairly reliable",
            "Score": 0,
            "Type": "domain",
            "Vendor": "CensysV2"
        },
        {
            "Indicator": "google.com",
            "Reliability": "C - Fairly reliable",
            "Score": 3,
            "Type": "domain",
            "Vendor": "CensysV2"
        }
    ],
    "Domain": [
        {
            "Name": "amazon.com",
            "Relationships": [
                {
                    "EntityA": "amazon.com",
                    "EntityAType": "Domain",
                    "EntityB": "192.0.2.1",
                    "EntityBType": "IP",
                    "Relationship": "related-to"
                },
                {
                    "EntityA": "amazon.com",
                    "EntityAType": "Domain",
                    "EntityB": "192.0.2.2",
                    "EntityBType": "IP",
                    "Relationship": "related-to"
                },
                {
                    "EntityA": "amazon.com",
                    "EntityAType": "Domain",
                    "EntityB": "192.0.2.3",
                    "EntityBType": "IP",
                    "Relationship": "related-to"
                }
            ]
        },
        {
            "Malicious": {
                "Description": "Matched malicious labels: IPV6",
                "Vendor": "CensysV2"
            },
            "Name": "google.com",
            "Relationships": [
                {
                    "EntityA": "google.com",
                    "EntityAType": "Domain",
                    "EntityB": "2001:db8::1",
                    "EntityBType": "IP",
                    "Relationship": "related-to"
                },
                {
                    "EntityA": "google.com",
                    "EntityAType": "Domain",
                    "EntityB": "2001:db8::2",
                    "EntityBType": "IP",
                    "Relationship": "related-to"
                },
                {
                    "EntityA": "google.com",
                    "EntityAType": "Domain",
                    "EntityB": "2001:db8::3",
                    "EntityBType": "IP",
                    "Relationship": "related-to"
                },
                {
                    "EntityA": "google.com",
                    "EntityAType": "Domain",
                    "EntityB": "2001:db8::4",
                    "EntityBType": "IP",
                    "Relationship": "related-to"
                },
                {
                    "EntityA": "google.com",
                    "EntityAType": "Domain",
                    "EntityB": "2001:db8::5",
                    "EntityBType": "IP",
                    "Relationship": "related-to"
                },
                {
                    "EntityA": "google.com",
                    "EntityAType": "Domain",
                    "EntityB": "2001:db8::6",
                    "EntityBType": "IP",
                    "Relationship": "related-to"
                },
                {
                    "EntityA": "google.com",
                    "EntityAType": "Domain",
                    "EntityB": "2001:db8::7",
                    "EntityBType": "IP",
                    "Relationship": "related-to"
                },
                {
                    "EntityA": "google.com",
                    "EntityAType": "Domain",
                    "EntityB": "2001:db8::8",
                    "EntityBType": "IP",
                    "Relationship": "related-to"
                },
                {
                    "EntityA": "google.com",
                    "EntityAType": "Domain",
                    "EntityB": "2001:db8::9",
                    "EntityBType": "IP",
                    "Relationship": "related-to"
                },
                {
                    "EntityA": "google.com",
                    "EntityAType": "Domain",
                    "EntityB": "2001:db8::10",
                    "EntityBType": "IP",
                    "Relationship": "related-to"
                },
                {
                    "EntityA": "google.com",
                    "EntityAType": "Domain",
                    "EntityB": "192.0.2.10",
                    "EntityBType": "IP",
                    "Relationship": "related-to"
                },
                {
                    "EntityA": "google.com",
                    "EntityAType": "Domain",
                    "EntityB": "192.0.2.11",
                    "EntityBType": "IP",
                    "Relationship": "related-to"
                },
                {
                    "EntityA": "google.com",
                    "EntityAType": "Domain",
                    "EntityB": "192.0.2.12",
                    "EntityBType": "IP",
                    "Relationship": "related-to"
                },
                {
                    "EntityA": "google.com",
                    "EntityAType": "Domain",
                    "EntityB": "192.0.2.13",
                    "EntityBType": "IP",
                    "Relationship": "related-to"
                },
                {
                    "EntityA": "google.com",
                    "EntityAType": "Domain",
                    "EntityB": "192.0.2.14",
                    "EntityBType": "IP",
                    "Relationship": "related-to"
                },
                {
                    "EntityA": "google.com",
                    "EntityAType": "Domain",
                    "EntityB": "192.0.2.15",
                    "EntityBType": "IP",
                    "Relationship": "related-to"
                }
            ]
        }
    ]
}

Human Readable Output

Censys results for Domain amazon.com

Enriched Web Property Data

Hostname Port Scan Time Endpoint Types Endpoint Paths Labels Threat Names Vulns Names Vendors Products Versions sha256 Subject DN Issuer DN Common Names Not Before Not After
amazon.com 443 2026-03-10T07:52:06Z HTTP / WEB_SERVER, HTTPS OUTDATED_SOFTWARE CVE-2024-11111 f5 nginx 1.18.0 0000000000000000000000000000000000000000000000000000000000000001 CN=example.com C=US, O=Let’s Encrypt, CN=R11 example.com 2025-01-03T04:11:45Z 2025-04-03T04:11:44Z

Information for IP 8.8.8.8

ASN Network Protocols Routing Whois Last Updated
15169 GOOGLE - Google LLC 53/DNS, 443/UNKNOWN, 443/HTTP, 853/UNKNOWN 8.8.8.0/24 2023-12-28T00:00:00Z

Command example

!cen-view index=certificates query=9d3b51a6b80daf76e074730f19dc01e643ca0c3127d8f48be64cf3302f6622cc limit=1

Context Example

{
    "Censys": {
        "View": {
            "added_at": "1970-01-01T00:00:00Z",
            "ct": {
                "entries": {
                    "digicert_ct1": {
                        "added_to_ct_at": "2015-09-29T19:55:46Z",
                        "ct_to_censys_at": "2018-07-30T04:49:40Z",
                        "index": 165790
                    },
                    "google_aviator": {
                        "index": 8713649
                    },
                    "google_pilot": {
                        "added_to_ct_at": "2015-09-29T19:55:45Z",
                        "ct_to_censys_at": "2018-07-30T15:23:48Z",
                        "index": 9498499
                    },
                    "google_rocketeer": {
                        "added_to_ct_at": "2015-09-29T19:55:45Z",
                        "ct_to_censys_at": "2018-07-30T15:17:12Z",
                        "index": 6663198
                    },
                    "nordu_ct_plausible": {
                        "added_to_ct_at": "2015-10-19T23:17:33Z",
                        "ct_to_censys_at": "2018-07-30T19:53:59Z",
                        "index": 5744025
                    },
                    "symantec_ws_ct": {
                        "added_to_ct_at": "2015-09-29T19:55:46Z",
                        "ct_to_censys_at": "2018-07-30T04:22:53Z",
                        "index": 6913
                    }
                }
            },
            "ever_seen_in_scan": true,
            "fingerprint_md5": "0f263d5e56288c37ade29f7b9977f38d",
            "fingerprint_sha1": "8740f09afc54752b26b295cdc6393c6b8ffd9e6a",
            "fingerprint_sha256": "9d3b51a6b80daf76e074730f19dc01e643ca0c3127d8f48be64cf3302f6622cc",
            "modified_at": "2024-01-23T12:12:35Z",
            "names": [
                "*.android.com",
                "*.appengine.google.com",
                "*.cloud.google.com",
                "*.google-analytics.com",
                "*.google.ca",
                "*.google.cl",
                "*.google.co.in",
                "*.google.co.jp",
                "*.google.co.uk",
                "*.google.com",
                "*.google.com.ar",
                "*.google.com.au",
                "*.google.com.br",
                "*.google.com.co",
                "*.google.com.mx",
                "*.google.com.tr",
                "*.google.com.vn",
                "*.google.de",
                "*.google.es",
                "*.google.fr",
                "*.google.hu",
                "*.google.it",
                "*.google.nl",
                "*.google.pl",
                "*.google.pt",
                "*.googleadapis.com",
                "*.googleapis.cn",
                "*.googlecommerce.com",
                "*.googlevideo.com",
                "*.gstatic.cn",
                "*.gstatic.com",
                "*.gvt1.com",
                "*.gvt2.com",
                "*.metric.gstatic.com",
                "*.urchin.com",
                "*.url.google.com",
                "*.youtube-nocookie.com",
                "*.youtube.com",
                "*.youtubeeducation.com",
                "*.ytimg.com",
                "android.com",
                "g.co",
                "goo.gl",
                "google-analytics.com",
                "google.com",
                "googlecommerce.com",
                "urchin.com",
                "youtu.be",
                "youtube.com",
                "youtubeeducation.com"
            ],
            "parent_spki_subject_fingerprint_sha256": "ec0c72ce7689150e4f62d04f51f0f19713f77cf27ff43cab4035e9e54e846aa9",
            "parse_status": "success",
            "parsed": {
                "extensions": {
                    "authority_info_access": {
                        "issuer_urls": [
                            "http://pki.google.com/GIAG2.crt"
                        ],
                        "ocsp_urls": [
                            "http://clients1.google.com/ocsp"
                        ]
                    },
                    "authority_key_id": "4add06161bbcf668b576f581b6bb621aba5a812f",
                    "basic_constraints": {},
                    "certificate_policies": [
                        {
                            "id": "1.2.3.4.5.6.7.8.9"
                        },
                        {
                            "id": "1.2.3.4.5.6.7.8.10"
                        }
                    ],
                    "crl_distribution_points": [
                        "http://pki.google.com/GIAG2.crl"
                    ],
                    "extended_key_usage": {
                        "client_auth": true,
                        "server_auth": true
                    },
                    "key_usage": {
                        "digital_signature": true,
                        "value": 1
                    },
                    "subject_alt_name": {
                        "dns_names": [
                            "*.google.com",
                            "*.android.com",
                            "*.appengine.google.com",
                            "*.cloud.google.com",
                            "*.google-analytics.com",
                            "*.google.ca",
                            "*.google.cl",
                            "*.google.co.in",
                            "*.google.co.jp",
                            "*.google.co.uk",
                            "*.google.com.ar",
                            "*.google.com.au",
                            "*.google.com.br",
                            "*.google.com.co",
                            "*.google.com.mx",
                            "*.google.com.tr",
                            "*.google.com.vn",
                            "*.google.de",
                            "*.google.es",
                            "*.google.fr",
                            "*.google.hu",
                            "*.google.it",
                            "*.google.nl",
                            "*.google.pl",
                            "*.google.pt",
                            "*.googleadapis.com",
                            "*.googleapis.cn",
                            "*.googlecommerce.com",
                            "*.googlevideo.com",
                            "*.gstatic.cn",
                            "*.gstatic.com",
                            "*.gvt1.com",
                            "*.gvt2.com",
                            "*.metric.gstatic.com",
                            "*.urchin.com",
                            "*.url.google.com",
                            "*.youtube-nocookie.com",
                            "*.youtube.com",
                            "*.youtubeeducation.com",
                            "*.ytimg.com",
                            "android.com",
                            "g.co",
                            "goo.gl",
                            "google-analytics.com",
                            "google.com",
                            "googlecommerce.com",
                            "urchin.com",
                            "youtu.be",
                            "youtube.com",
                            "youtubeeducation.com"
                        ]
                    },
                    "subject_key_id": "19c6b145efc879529b4a57b15e0d543b011dce35"
                },
                "issuer": {
                    "common_name": [
                        "Google Internet Authority G2"
                    ],
                    "country": [
                        "US"
                    ],
                    "organization": [
                        "Google Inc"
                    ]
                },
                "issuer_dn": "C=US, O=Google Inc, CN=Google Internet Authority G2",
                "serial_number": "5878999135690490607",
                "serial_number_hex": "51966690cda902ef",
                "signature": {
                    "signature_algorithm": {
                        "name": "SHA256-RSA",
                        "oid": "1.2.840.113549.1.1.11"
                    },
                    "valid": true,
                    "value": "1e36357c79acc1c99ddec329d06a1695b2e82cc6ee884d6a699e035219fc804df3d090e7e910d88d9f2a3aa300dff16a732c33775bca074b279b6251924f597c160d3b5688b17a525da0818ed16654f7996ab2c81627ad59ee9b4be94b6c2e05873539fdb83b280cbbccf647ba1d44fb2b3beafe0efc9ba2e6258ef809a4cb0bbec54e09dd21236ca10962e6d7b1ae42328bcdc25fa57b650f8aeff1aaef90721098563e8a406567462674b39318f3a6ca54fc651d15ca8eecadff61484a9e3cb078100e6ab96d9d620798752dcf83bdd3b2be69bbdfc22c0e87aff10ce2305d855c6c9a1133e6fc207601f139f0c8fdb3dae5d21371eff9be66de79edcaef6a"
                },
                "subject": {
                    "common_name": [
                        "*.google.com"
                    ],
                    "country": [
                        "US"
                    ],
                    "locality": [
                        "Mountain View"
                    ],
                    "organization": [
                        "Google Inc"
                    ],
                    "province": [
                        "California"
                    ]
                },
                "subject_dn": "C=US, ST=California, L=Mountain View, O=Google Inc, CN=*.google.com",
                "subject_key_info": {
                    "ecdsa": {
                        "b": "5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b",
                        "curve": "P-256",
                        "gx": "6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296",
                        "gy": "4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5",
                        "length": 256,
                        "n": "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551",
                        "p": "ffffffff00000001000000000000000000000000ffffffffffffffffffffffff",
                        "pub": "04f680d0e5c3a1162f2420176176add7ba927c0cecb52453bfa84a16c9fe56219b1ec2b31bcf2ae30d5fb45c475edc79725bf57889a3b2a76ec940d567e66fce77",
                        "x": "f680d0e5c3a1162f2420176176add7ba927c0cecb52453bfa84a16c9fe56219b",
                        "y": "1ec2b31bcf2ae30d5fb45c475edc79725bf57889a3b2a76ec940d567e66fce77"
                    },
                    "fingerprint_sha256": "3d4a4bd778be7965e90a13ac361e1ed7836d24c15cd5c093f9cc7e7857f53ea0",
                    "key_algorithm": {
                        "name": "ECDSA",
                        "oid": "1.2.840.10045.2.1"
                    }
                },
                "validity_period": {
                    "length_seconds": 7708841,
                    "not_after": "2015-12-28T00:00:00Z",
                    "not_before": "2015-09-29T18:39:20Z"
                },
                "version": 3
            },
            "spki_subject_fingerprint_sha256": "5eb06b1c29ced84998d3d35a80fa17d3d39e4de96d25539485aecd6360f618dc",
            "tbs_fingerprint_sha256": "1661b59eb7d8cda44f800fabc9ef69ba01506309eedf027f2270105afd1663e4",
            "tbs_no_ct_fingerprint_sha256": "1661b59eb7d8cda44f800fabc9ef69ba01506309eedf027f2270105afd1663e4",
            "validated_at": "2023-09-09T05:55:46Z",
            "validation": {
                "apple": {
                    "chains": [
                        {
                            "sha256fp": [
                                "44336eb05c6c783dc177217a9f6fef75f4524e98045b390803ae9de69eb42b08",
                                "ff856a2d251dcd88d36656f450126798cfabaade40799c722de4d2b5db36a73a"
                            ]
                        },
                        {
                            "sha256fp": [
                                "9f630426df1d8abfd80ace98871ba833ab9742cb34838de2b5285ed54c0c7dcc",
                                "ff856a2d251dcd88d36656f450126798cfabaade40799c722de4d2b5db36a73a"
                            ]
                        },
                        {
                            "sha256fp": [
                                "a4124fdaf9cac7baee1cab32e3225d746500c09f3cf3ebb253ef3fbb088afd34",
                                "ff856a2d251dcd88d36656f450126798cfabaade40799c722de4d2b5db36a73a"
                            ]
                        },
                        {
                            "sha256fp": [
                                "c3f697a92a293d86f9a3ee7ccb970e20e0050b8728cc83ed1b996ce9005d4c36",
                                "ff856a2d251dcd88d36656f450126798cfabaade40799c722de4d2b5db36a73a"
                            ]
                        }
                    ],
                    "ever_valid": true,
                    "had_trusted_path": true,
                    "parents": [
                        "44336eb05c6c783dc177217a9f6fef75f4524e98045b390803ae9de69eb42b08",
                        "9f630426df1d8abfd80ace98871ba833ab9742cb34838de2b5285ed54c0c7dcc",
                        "a4124fdaf9cac7baee1cab32e3225d746500c09f3cf3ebb253ef3fbb088afd34",
                        "c3f697a92a293d86f9a3ee7ccb970e20e0050b8728cc83ed1b996ce9005d4c36"
                    ],
                    "type": "leaf"
                },
                "chrome": {},
                "microsoft": {
                    "chains": [
                        {
                            "sha256fp": [
                                "44336eb05c6c783dc177217a9f6fef75f4524e98045b390803ae9de69eb42b08",
                                "ff856a2d251dcd88d36656f450126798cfabaade40799c722de4d2b5db36a73a"
                            ]
                        },
                        {
                            "sha256fp": [
                                "9f630426df1d8abfd80ace98871ba833ab9742cb34838de2b5285ed54c0c7dcc",
                                "ff856a2d251dcd88d36656f450126798cfabaade40799c722de4d2b5db36a73a"
                            ]
                        },
                        {
                            "sha256fp": [
                                "a4124fdaf9cac7baee1cab32e3225d746500c09f3cf3ebb253ef3fbb088afd34",
                                "ff856a2d251dcd88d36656f450126798cfabaade40799c722de4d2b5db36a73a"
                            ]
                        },
                        {
                            "sha256fp": [
                                "c3f697a92a293d86f9a3ee7ccb970e20e0050b8728cc83ed1b996ce9005d4c36",
                                "ff856a2d251dcd88d36656f450126798cfabaade40799c722de4d2b5db36a73a"
                            ]
                        },
                        {
                            "sha256fp": [
                                "44336eb05c6c783dc177217a9f6fef75f4524e98045b390803ae9de69eb42b08",
                                "3c35cc963eb004451323d3275d05b353235053490d9cd83729a2faf5e7ca1cc0",
                                "08297a4047dba23680c731db6e317653ca7848e1bebd3a0b0179a707f92cf178"
                            ]
                        }
                    ],
                    "ever_valid": true,
                    "had_trusted_path": true,
                    "parents": [
                        "44336eb05c6c783dc177217a9f6fef75f4524e98045b390803ae9de69eb42b08",
                        "9f630426df1d8abfd80ace98871ba833ab9742cb34838de2b5285ed54c0c7dcc",
                        "a4124fdaf9cac7baee1cab32e3225d746500c09f3cf3ebb253ef3fbb088afd34",
                        "c3f697a92a293d86f9a3ee7ccb970e20e0050b8728cc83ed1b996ce9005d4c36"
                    ],
                    "type": "leaf"
                },
                "nss": {}
            },
            "validation_level": "ov",
            "zlint": {
                "failed_lints": [
                    "n_subject_common_name_included",
                    "w_ext_key_usage_not_critical"
                ],
                "notices_present": true,
                "timestamp": "2023-09-09T05:55:46Z",
                "version": 3,
                "warnings_present": true
            }
        }
    }
}

Human Readable Output

Information for certificate

Added At Browser Trust Modified At SHA 256 Validated At
1970-01-01T00:00:00Z nss: Invalid,
microsoft: Valid,
apple: Valid,
chrome: Invalid
2024-01-23T12:12:35Z 9d3b51a6b80daf76e074730f19dc01e643ca0c3127d8f48be64cf3302f6622cc 2023-09-09T05:55:46Z

cen-search


Returns previews of hosts matching a specified search query, or a list of certificates that match the given query.

Base Command

cen-search

Input

Argument Name Description Required
query Query used to search for hosts with matching attributes. Uses the Censys Search Language. Required
page_size The maximum number of hits to return in each response (minimum of 0, maximum of 100). Default is 50. (Applies for the host search.) Optional
limit The number of results to return. Default is 50. Optional
index The index from which to retrieve data. Possible values are: ipv4, certificates. Required
fields The fields to return. (Applies for the certificates search). Optional
page The page to return. (Applies for the certificates search). Default is 1. Optional

Context Output

Path Type Description
Censys.Search.autonomous_system.asn Number The autonomous system number (ASN) that the host is in.
Censys.Search.autonomous_system.bgp_prefix String The autonomous system’s CIDR.
Censys.Search.autonomous_system.country_code String he autonomous system’s two-letter, ISO 3166-1 alpha-2 country code (e.g., US, CN, GB, RU).
Censys.Search.autonomous_system.description String A brief description of the autonomous system.
Censys.Search.autonomous_system.name String The friendly name of the autonomous system.
Censys.Search.ip String The host’s IP address.
Censys.Search.location.continent String The continent of the host’s detected location (e.g., North America, Europe, Asia, South America, Africa, Oceania).
Censys.Search.location.coordinates Unknown The estimated coordinates of the host’s detected location.
Censys.Search.location.country String The country of the host’s detected location.
Censys.Search.location.country_code String The two-letter ISO 3166-1 alpha-2 country code of the host’s detected location (e.g., US, CN, GB, RU).
Censys.Search.location.registered_country String The host’s registered country.
Censys.Search.location.registered_country_code String The registered country’s two-letter, ISO 3166-1 alpha-2 country code (e.g., US, CN, GB, RU).
Censys.Search.location.timezone String The IANA time zone database name of the host’s detected location.
Censys.Search.services.port Number The port the service was reached at.
Censys.Search.services.service_name String The name of the service on the port. This is typically the L7 protocol (e.g., “HTTP”); however, in the case that a more specific HTTP-based protocol is found (e.g., Kubernetes or Prometheus), the field will show that. This field indicates where protocol-specific data will be located.
Censys.Search.services.transport_protocol String The transport protocol (known in OSI model as L4) used to contact this service (i.e., UDP or TCP).
Censys.Search.parsed.fingerprint_sha256 String SHA 256 fingerprint.
Censys.Search.parsed.issuer.organization Unknown The organization name.
Censys.Search.parsed.names Unknown Common names for the entity.
Censys.Search.parsed.subject_dn String Distinguished name of the entity that the certificate belongs to.
Censys.Search.parsed.validity.end Date Timestamp of when the certificate expires. Time zone is UTC.
Censys.Search.parsed.validity.start Date Timestamp of when the certificate is first valid. Time zone is UTC.
Censys.Search.parsed.issuer_dn String Distinguished name of the entity that has signed and issued the certificate.

Command Example

!cen-search index=certificates query="parsed.issuer.common_name: \"Let's Encrypt\"" limit=1

Context Example

{
    "Censys": {
        "Search": {
            "parsed": {
                "fingerprint_sha256": "f3ade17dffcadd9532aeb2514f10d66e22941393725aa65366ac286df9b1234",
                "issuer": {
                    "organization": [
                        "Let's Encrypt"
                    ]
                },
                "issuer_dn": "C=US, O=Let's Encrypt, CN=Let's Encrypt Authority X3",
                "names": [
                    "*.45g4rg43g4fr3434g.gb.net",
                    "45g4rg43g4fr3434g.gb.net"
                ],
                "subject_dn": "CN=45g4rg43g4fr3434g.gb.net",
                "validity": {
                    "end": "2021-01-10T14:46:11Z",
                    "start": "2020-10-12T14:46:11Z"
                }
            }
        }
    }
}

Human Readable Output

Search results for query “parsed.issuer.common_name: “Let’s Encrypt””

Issuer Issuer DN Names SHA256 Subject DN Validity
organization: Let’s Encrypt C=US, O=Let’s Encrypt, CN=Let’s Encrypt Authority X3 *.45g4rg43g4fr3434g.gb.net,
45g4rg43g4fr3434g.gb.net
f3ade17dffcadd9532aeb2514f10d66e22941393725aa65366ac286df9b442ec CN=45g4rg43g4fr3434g.gb.net start: 2020-10-12T14:46:11Z
end: 2021-01-10T14:46:11Z

ip


Runs reputation on IPs.

Base Command

ip

Input

Argument Name Description Required
ip IP address or a list of IP addresses to assess reputation. Required

Context Output

Path Type Description
Censys.IP.services.port Number The port number associated with the service running on the IP.
Censys.IP.services.transport_protocol String The transport protocol used by the service running on the IP.
Censys.IP.services.protocol String The name of the service running on the IP.
Censys.IP.services.cert String The SSL/TLS certificate associated with the service running on the IP.
Censys.IP.labels String Labels associated with the IP address (with premium access only).
Censys.IP.dns.reverse_dns.names String Reverse DNS names associated with the IP address.
Censys.IP.autonomous_system.country_code String The country code of the autonomous system associated with the IP address.
Censys.IP.autonomous_system.description String Description of the autonomous system associated with the IP address.
Censys.IP.autonomous_system.name String Name of the autonomous system associated with the IP address.
Censys.IP.autonomous_system.bgp_prefix String BGP prefix of the autonomous system associated with the IP address.
Censys.IP.autonomous_system.asn Number Autonomous System Number (ASN) of the autonomous system associated with the IP address.
Censys.IP.ip String The IP address.
Censys.IP.location.country String Country name of the location associated with the IP address.
Censys.IP.location.timezone String Time zone of the location associated with the IP address.
Censys.IP.location.province String Province name of the location associated with the IP address.
Censys.IP.location.coordinates.latitude Number Latitude coordinate of the location associated with the IP address.
Censys.IP.location.coordinates.longitude Number Longitude coordinate of the location associated with the IP address.
Censys.IP.location.continent String Continent name of the location associated with the IP address.
Censys.IP.location.postal_code String Postal code of the location associated with the IP address.
Censys.IP.location.city String City name of the location associated with the IP address.
Censys.IP.location.country_code String Country code of the location associated with the IP address.
Censys.IP.service_count Number The total number of services running on the IP address.
Censys.IP.services.labels.value String Labels associated with services running on the IP address.
Censys.IP.services.threats.name String Threat names associated with services running on the IP address.
Censys.IP.services.vulns String Vulnerabilities associated with services running on the IP address.
Censys.IP.services.scan_time String Scan time for services running on the IP address.
Censys.IP.dns.names String DNS names associated with the IP address.
Censys.IP.dns.forward_dns.names String Forward DNS names associated with the IP address.
Censys.IP.whois.network.name String WHOIS network name associated with the IP address.
Censys.IP.whois.network.cidrs String WHOIS network CIDR blocks associated with the IP address.
IP.Address unknown The IP address.
IP.ASN unknown The IP ASN.
IP.Geo.Country unknown The IP country.
IP.Geo.Location unknown The IP location.
IP.UpdatedDate unknown The IP last update.
IP.Port unknown The IP port.
DBotScore.Indicator unknown The indicator that was tested.
DBotScore.Type unknown The indicator type.
DBotScore.Score Number The actual score.
DBotScore.Reliability String Reliability of the source providing the intelligence data.
DBotScore.Vendor unknown The vendor used to calculate the score.

Command example

!ip ip=8.8.8.8,8.8.4.4

Context Example

{
    "services": [
        {
            "port": 53,
            "transport_protocol": "UDP",
            "extended_service_name": "DNS",
            "service_name": "DNS"
        },
        {
            "certificate": "5a7763efee07b08b18a4af2796bfaac46641a2f15c98e88c3d79fa9a06adfc87",
            "extended_service_name": "HTTPS",
            "port": 443,
            "transport_protocol": "TCP",
            "service_name": "HTTP"
        },
        {
            "service_name": "UNKNOWN",
            "transport_protocol": "QUIC",
            "extended_service_name": "UNKNOWN",
            "port": 443
        },
        {
            "transport_protocol": "TCP",
            "service_name": "UNKNOWN",
            "port": 853,
            "certificate": "5a7763efee07b08b18a4af2796bfaac46641a2f15c98e88c3d79fa9a06adfc87",
            "extended_service_name": "UNKNOWN"
        }
    ],
    "labels": ["database","email","file-sharing","iot","login-page"],
    "dns": {
        "reverse_dns": {
            "names": [
                "dns.google"
            ]
        }
    },
    "autonomous_system": {
        "country_code": "US",
        "description": "GOOGLE",
        "name": "GOOGLE",
        "bgp_prefix": "8.8.8.0/24",
        "asn": 15169
    },
    "ip": "8.8.8.8",
    "location": {
        "country": "United States",
        "timezone": "America/Los_Angeles",
        "province": "California",
        "coordinates": {
            "latitude": 37.4056,
            "longitude": -122.0775
        },
        "continent": "North America",
        "postal_code": "94043",
        "city": "Mountain View",
        "country_code": "US"
    },
    "last_updated_at": "2024-04-07T02:16:23.015Z"
}

Human Readable Output

Censys results for IP: 8.8.8.8

Enriched Host Data

IP Labels Service Count Service Ports Service Protocols Service Transport Protocols Reverse DNS Names Autonomous System Name Autonomous System ASN City Province Postal Code Country Country Code Continent Latitude Longitude
8.8.8.8 database, email, file-sharing, iot, login-page 4 53, 443, 443, 853 DNS, HTTP, UNKNOWN, UNKNOWN UDP, TCP, QUIC, TCP dns.google GOOGLE 15169 Mountain View California 94043 United States US North America 37.4056 -122.0775

cen-host-history-list


Retrieve the event history for a host (IP address).

Base Command

cen-host-history-list

Input

Argument Name Description Required
host_id Specify the IP address of a host. Required
start_time Specify the start time of the host timeline.

Supported date formats: 2 minutes, 2 hours, 2 days, 2 weeks, 2 months, 2 years, yyyy-mm-dd, yyyy-mm-ddTHH:MM:SSZ.

For example: 01 Jan 2026, 01 Jan 2026 04:45:33, 2026-01-10T14:05:44Z.
Required
end_time Specify the end time of the host timeline.

Supported date formats: 2 minutes, 2 hours, 2 days, 2 weeks, 2 months, 2 years, yyyy-mm-dd, yyyy-mm-ddTHH:MM:SSZ.

For example: 01 Jan 2026, 01 Jan 2026 04:45:33, 2026-01-10T14:05:44Z.
Required

Context Output

Path Type Description
Censys.HostEventHistory.ip String The IP address of the host.
Censys.HostEventHistory.total_events Number The total number of events associated with the host.
Censys.HostEventHistory.partial_data Boolean Whether the data is partial or not.
Censys.HostEventHistory.events.resource.service_scanned.scan.scan_time Date The timestamp when the service scan was performed.
Censys.HostEventHistory.events.resource.service_scanned.scan.ip String The IP address of the scanned service.
Censys.HostEventHistory.events.resource.service_scanned.scan.port Number The port number of the scanned service.
Censys.HostEventHistory.events.resource.service_scanned.scan.protocol String The protocol used by the scanned service.
Censys.HostEventHistory.events.resource.service_scanned.scan.transport_protocol String The transport protocol used during the service scan.
Censys.HostEventHistory.events.resource.service_scanned.scan.is_success Boolean Whether the service scan was successful or not.
Censys.HostEventHistory.events.resource.service_scanned.scan.mysql.error_code Number The MySQL error code returned during the scan.
Censys.HostEventHistory.events.resource.service_scanned.scan.mysql.error_id String The MySQL error identifier returned during the scan.
Censys.HostEventHistory.events.resource.service_scanned.scan.mysql.error_message String The MySQL error message returned during the scan.
Censys.HostEventHistory.events.resource.forward_dns_resolved.name String The domain name resolved from the forward DNS lookup.
Censys.HostEventHistory.events.resource.forward_dns_resolved.resolve_time String The timestamp when the forward DNS resolution occurred.
Censys.HostEventHistory.events.resource.jarm_scanned.diff.additionalProp.new String The new value in the JARM scan difference.
Censys.HostEventHistory.events.resource.jarm_scanned.diff.additionalProp.old String The old value in the JARM scan difference.
Censys.HostEventHistory.events.resource.jarm_scanned.scan.cipher_and_version_fingerprint String The cipher and version fingerprint from the JARM scan.
Censys.HostEventHistory.events.resource.jarm_scanned.scan.fingerprint String The JARM fingerprint of the scanned service.
Censys.HostEventHistory.events.resource.jarm_scanned.scan.hostname String The hostname used in the JARM scan.
Censys.HostEventHistory.events.resource.jarm_scanned.scan.ip String The IP address scanned by JARM.
Censys.HostEventHistory.events.resource.jarm_scanned.scan.is_success Boolean Whether the JARM scan was successful or not.
Censys.HostEventHistory.events.resource.jarm_scanned.scan.port Number The port number scanned by JARM.
Censys.HostEventHistory.events.resource.jarm_scanned.scan.scan_time String The timestamp when the JARM scan was performed.
Censys.HostEventHistory.events.resource.jarm_scanned.scan.tls_extensions_sha256 String The SHA-256 hash of the TLS extensions from the JARM scan.
Censys.HostEventHistory.events.resource.jarm_scanned.scan.transport_protocol String The transport protocol used during the JARM scan.
Censys.HostEventHistory.events.resource.location_updated.location.city String The city where the host is located.
Censys.HostEventHistory.events.resource.location_updated.location.continent String The continent where the host is located.
Censys.HostEventHistory.events.resource.location_updated.location.coordinates.latitude Number The latitude coordinate of the host location.
Censys.HostEventHistory.events.resource.location_updated.location.coordinates.longitude Number The longitude coordinate of the host location.
Censys.HostEventHistory.events.resource.location_updated.location.country String The country where the host is located.
Censys.HostEventHistory.events.resource.location_updated.location.country_code String The country code where the host is located.
Censys.HostEventHistory.events.resource.location_updated.location.postal_code String The postal code of the host location.
Censys.HostEventHistory.events.resource.location_updated.location.province String The province or state where the host is located.
Censys.HostEventHistory.events.resource.location_updated.location.registered_country String The registered country of the host.
Censys.HostEventHistory.events.resource.location_updated.location.registered_country_code String The registered country code of the host.
Censys.HostEventHistory.events.resource.location_updated.location.timezone String The timezone of the host location.
Censys.HostEventHistory.events.resource.reverse_dns_resolved.names String The domain names resolved from the reverse DNS lookup.
Censys.HostEventHistory.events.resource.reverse_dns_resolved.resolve_time String The timestamp when the reverse DNS resolution occurred.
Censys.HostEventHistory.events.resource.route_updated.diff.additionalProp.new String The new value in the route update difference.
Censys.HostEventHistory.events.resource.route_updated.diff.additionalProp.old String The old value in the route update difference.
Censys.HostEventHistory.events.resource.route_updated.route.asn Number The Autonomous System Number of the route.
Censys.HostEventHistory.events.resource.route_updated.route.bgp_prefix String The BGP prefix of the route.
Censys.HostEventHistory.events.resource.route_updated.route.country_code String The country code associated with the route.
Censys.HostEventHistory.events.resource.route_updated.route.description String The description of the route.
Censys.HostEventHistory.events.resource.route_updated.route.name String The name of the route.
Censys.HostEventHistory.events.resource.route_updated.route.organization String The organization associated with the route.
Censys.HostEventHistory.events.resource.whois_updated.diff.additionalProp.new String The new value in the WHOIS update difference.
Censys.HostEventHistory.events.resource.whois_updated.diff.additionalProp.old String The old value in the WHOIS update difference.
Censys.HostEventHistory.events.resource.whois_updated.whois.network.allocation_type String The allocation type of the network in WHOIS data.
Censys.HostEventHistory.events.resource.whois_updated.whois.network.cidrs String The CIDR blocks of the network in WHOIS data.
Censys.HostEventHistory.events.resource.whois_updated.whois.network.created String The creation timestamp of the network in WHOIS data.
Censys.HostEventHistory.events.resource.whois_updated.whois.network.handle String The handle identifier of the network in WHOIS data.
Censys.HostEventHistory.events.resource.whois_updated.whois.network.name String The name of the network in WHOIS data.
Censys.HostEventHistory.events.resource.whois_updated.whois.network.updated String The last update timestamp of the network in WHOIS data.
Censys.HostEventHistory.events.resource.whois_updated.whois.organization.abuse_contacts.email String The email address of the abuse contact in WHOIS data.
Censys.HostEventHistory.events.resource.whois_updated.whois.organization.abuse_contacts.handle String The handle identifier of the abuse contact in WHOIS data.
Censys.HostEventHistory.events.resource.whois_updated.whois.organization.abuse_contacts.name String The name of the abuse contact in WHOIS data.
Censys.HostEventHistory.events.resource.whois_updated.whois.organization.address String The address of the organization in WHOIS data.
Censys.HostEventHistory.events.resource.whois_updated.whois.organization.admin_contacts.email String The email address of the admin contact in WHOIS data.
Censys.HostEventHistory.events.resource.whois_updated.whois.organization.admin_contacts.handle String The handle identifier of the admin contact in WHOIS data.
Censys.HostEventHistory.events.resource.whois_updated.whois.organization.admin_contacts.name String The name of the admin contact in WHOIS data.
Censys.HostEventHistory.events.resource.whois_updated.whois.organization.city String The city of the organization in WHOIS data.
Censys.HostEventHistory.events.resource.whois_updated.whois.organization.country String The country of the organization in WHOIS data.
Censys.HostEventHistory.events.resource.whois_updated.whois.organization.handle String The handle identifier of the organization in WHOIS data.
Censys.HostEventHistory.events.resource.whois_updated.whois.organization.name String The name of the organization in WHOIS data.
Censys.HostEventHistory.events.resource.whois_updated.whois.organization.postal_code String The postal code of the organization in WHOIS data.
Censys.HostEventHistory.events.resource.whois_updated.whois.organization.state String The state or province of the organization in WHOIS data.
Censys.HostEventHistory.events.resource.whois_updated.whois.organization.street String The street address of the organization in WHOIS data.
Censys.HostEventHistory.events.resource.whois_updated.whois.organization.tech_contacts.email String The email address of the technical contact in WHOIS data.
Censys.HostEventHistory.events.resource.whois_updated.whois.organization.tech_contacts.handle String The handle identifier of the technical contact in WHOIS data.
Censys.HostEventHistory.events.resource.whois_updated.whois.organization.tech_contacts.name String The name of the technical contact in WHOIS data.
Censys.HostEventHistory.extensions String The extensions associated with the host event history.

Command example

!cen-host-history-list host_id=0.0.0.1 start_time="1 week" end_time="1 day"

Context Example

{
    "Censys": {
        "HostEventHistory": {
            "ip": "0.0.0.1",
            "total_events": 8,
            "partial_data": false,
            "events": [
                {
                    "resource": {
                        "event_time": "2026-03-01T10:00:00.000Z",
                        "service_scanned": {
                            "scan": {
                                "port": 443,
                                "protocol": "https",
                                "transport_protocol": "tcp"
                            }
                        }
                    }
                },
                {
                    "resource": {
                        "event_time": "2026-03-01T09:00:00.000Z",
                        "reverse_dns_resolved": {
                            "names": [
                                "example.com",
                                "www.example.com"
                            ]
                        }
                    }
                },
                {
                    "resource": {
                        "event_time": "2026-03-01T08:00:00.000Z",
                        "endpoint_scanned": {
                            "scan": {
                                "port": 8080,
                                "endpoint_type": "http"
                            }
                        }
                    }
                },
                {
                    "resource": {
                        "event_time": "2026-03-01T07:00:00.000Z",
                        "forward_dns_resolved": {
                            "name": "test.example.com"
                        }
                    }
                },
                {
                    "resource": {
                        "event_time": "2026-03-01T06:00:00.000Z",
                        "jarm_scanned": {
                            "scan": {
                                "port": 443,
                                "fingerprint": "0000000000000000000000000000000000000000000000000000000000001"
                            }
                        }
                    }
                },
                {
                    "resource": {
                        "event_time": "2026-03-01T05:00:00.000Z",
                        "location_updated": {
                            "location": {
                                "city": "San Francisco",
                                "country": "United States"
                            }
                        }
                    }
                },
                {
                    "resource": {
                        "event_time": "2026-03-01T04:00:00.000Z",
                        "route_updated": {
                            "route": {
                                "asn": "15169",
                                "organization": "Google LLC"
                            }
                        }
                    }
                },
                {
                    "resource": {
                        "event_time": "2026-03-01T03:00:00.000Z",
                        "whois_updated": {
                            "whois": {
                                "organization": {
                                    "name": "Example Organization"
                                }
                            }
                        }
                    }
                }
            ]
        }
    }
}

Human Readable Output

Successfully retrieved 8 event(s) for host 0.0.0.1

Host History Events

Event Time Resource Type Resource Details Link to Censys
2026-03-01T10:00:00.000Z service_scanned 443/TCP/https View historical host on Censys platform
2026-03-01T09:00:00.000Z reverse_dns_resolved example.com View historical host on Censys platform
2026-03-01T08:00:00.000Z endpoint_scanned 8080/http View historical host on Censys platform
2026-03-01T07:00:00.000Z forward_dns_resolved test.example.com View historical host on Censys platform
2026-03-01T06:00:00.000Z jarm_scanned 443/0000000000000000000000000000000000000000000000000000000000001 View historical host on Censys platform
2026-03-01T05:00:00.000Z location_updated San Francisco/United States View historical host on Censys platform
2026-03-01T04:00:00.000Z route_updated 15169/Google LLC View historical host on Censys platform
2026-03-01T03:00:00.000Z whois_updated Example Organization View historical host on Censys platform

cen-rescan


Initiate a live rescan for a known host service at a specific IP and port (ip:port) or hostname and port (hostname:port).

Base Command

cen-rescan

Input

Argument Name Description Required
ioc_type Specify the type of IOC. Possible values are: Service, Web Property. Default is Service. Required
ioc_value Specify the value of IOC. Required
port Specify the port number associated with the IOC. Default is 443. Required
protocol Specify the service protocol.

Note: This argument is required only if the IOC type is Service.
Optional
transport_protocol Specify the transport protocol.

Note: This argument is required only if the IOC type is Service. Possible values are: Unknown, TCP, UDP, ICMP, QUIC. Default is Unknown.
Optional

Context Output

Path Type Description
Censys.Rescan.scan_id String The unique identifier for the rescan operation.
Censys.Rescan.status String The status of the rescan (initiated, in_progress, completed, failed).
Censys.Rescan.is_completed Boolean Whether the rescan has completed.
Censys.Rescan.enrichment_data.ip String The IP address of the rescanned host.
Censys.Rescan.enrichment_data.service_count Number The total number of services detected on the host.
Censys.Rescan.enrichment_data.labels String Labels associated with the host.
Censys.Rescan.enrichment_data.location.continent String The continent of the host’s detected location.
Censys.Rescan.enrichment_data.location.country String The name of the country of the host’s detected location.
Censys.Rescan.enrichment_data.location.country_code String The two-letter ISO 3166-1 alpha-2 country code of the host’s detected location.
Censys.Rescan.enrichment_data.location.city String The city of the host’s detected location.
Censys.Rescan.enrichment_data.location.province String The province or state of the host’s detected location.
Censys.Rescan.enrichment_data.location.postal_code String The postal code of the host’s detected location.
Censys.Rescan.enrichment_data.location.timezone String The timezone of the host’s detected location.
Censys.Rescan.enrichment_data.location.coordinates.latitude Number The latitude of the host’s detected location.
Censys.Rescan.enrichment_data.location.coordinates.longitude Number The longitude of the host’s detected location.
Censys.Rescan.enrichment_data.autonomous_system.asn Number The autonomous system number (ASN) that the host is in.
Censys.Rescan.enrichment_data.autonomous_system.description String A brief description of the autonomous system.
Censys.Rescan.enrichment_data.autonomous_system.bgp_prefix String The autonomous system’s CIDR.
Censys.Rescan.enrichment_data.autonomous_system.name String The friendly name of the autonomous system.
Censys.Rescan.enrichment_data.autonomous_system.country_code String The autonomous system’s two-letter, ISO 3166-1 alpha-2 country code.
Censys.Rescan.enrichment_data.whois.network.handle String The WHOIS network handle identifier.
Censys.Rescan.enrichment_data.whois.network.name String The WHOIS network name.
Censys.Rescan.enrichment_data.whois.network.cidrs String The WHOIS network CIDRs.
Censys.Rescan.enrichment_data.whois.network.created Date The creation date of the WHOIS network record.
Censys.Rescan.enrichment_data.whois.network.updated Date The last update date of the WHOIS network record.
Censys.Rescan.enrichment_data.whois.organization.handle String The WHOIS organization handle identifier.
Censys.Rescan.enrichment_data.whois.organization.name String The WHOIS organization name.
Censys.Rescan.enrichment_data.whois.organization.address String The WHOIS organization address.
Censys.Rescan.enrichment_data.whois.organization.abuse_contacts String The WHOIS organization abuse contacts.
Censys.Rescan.enrichment_data.whois.organization.admin_contacts String The WHOIS organization admin contacts.
Censys.Rescan.enrichment_data.services String List of services detected on the host.
Censys.Rescan.enrichment_data.services.port Number The port the service was reached at.
Censys.Rescan.enrichment_data.services.protocol String The name of the service on the port.
Censys.Rescan.enrichment_data.services.transport_protocol String The transport protocol used to contact this service.
Censys.Rescan.enrichment_data.services.software String Software identified on the service.
Censys.Rescan.enrichment_data.services.software.source String The source of the software identification.
Censys.Rescan.enrichment_data.services.software.confidence Number The confidence level of the software identification.
Censys.Rescan.enrichment_data.services.software.part String The part classification of the software in CPE format.
Censys.Rescan.enrichment_data.services.software.vendor String The vendor of the identified software.
Censys.Rescan.enrichment_data.services.software.product String The product name of the identified software.
Censys.Rescan.enrichment_data.services.labels String Labels associated with the service.
Censys.Rescan.enrichment_data.services.labels.value String The value of the service label.
Censys.Rescan.enrichment_data.services.threats String Threats detected on the service.
Censys.Rescan.enrichment_data.services.vulns String Vulnerabilities detected on the service.
Censys.Rescan.enrichment_data.services.ip String The IP address of the service.
Censys.Rescan.enrichment_data.services.scan_time Date The time when the service was scanned.
Censys.Rescan.enrichment_data.services.banner String The banner returned by the service.
Censys.Rescan.enrichment_data.services.banner_hash_sha256 String The SHA-256 hash of the service banner.
Censys.Rescan.enrichment_data.services.banner_hex String The hexadecimal representation of the service banner.
Censys.Rescan.enrichment_data.dns.reverse_dns.resolve_time Date The time when reverse DNS was resolved.
Censys.Rescan.enrichment_data.dns.names String DNS names associated with the host.
Censys.Rescan.enrichment_data.dns.forward_dns.names String Forward DNS names for the host.
Censys.Rescan.enrichment_data.dns.reverse_dns.names String Reverse DNS names for the host.
IP.Address String The IP address.
IP.ASN String The autonomous system name for the IP address, for example: “AS8948”.
IP.Geo.Location String The geolocation where the IP address is located, in the format: latitude:longitude.
IP.Geo.Country String The country in which the IP address is located.
IP.Geo.Description String Additional information about the location.
IP.ASOwner String The autonomous system owner of the IP.
IP.Port String Ports that are associated with the IP.
IP.Malicious.Vendor String The vendor reporting the IP address as malicious.
IP.Malicious.Description String A description explaining why the IP address was reported as malicious.
Domain.Name String The domain name, for example: “google.com”.
Domain.Malicious.Vendor String The vendor reporting the domain as malicious.
Domain.Malicious.Description String A description explaining why the domain was reported as malicious.
DBotScore.Indicator String The indicator that was tested.
DBotScore.Type String The indicator type.
DBotScore.Vendor String The vendor used to calculate the score.
DBotScore.Score Number The actual score.
DBotScore.Reliability String Reliability of the source providing the intelligence data.

Command example

!cen-rescan ioc_type="Service" ioc_value="0.0.0.1" port="443" protocol="HTTPS" transport_protocol="TCP"

Context Example

{
    "Censys": {
        "Rescan": {
            "ioc_value": "0.0.0.1",
            "port": 443,
            "status": "completed",
            "scan_id": "00000000-0000-0000-0000-000000000001",
            "is_completed": true,
            "enrichment_data": {
                "ip": "0.0.0.1",
                "labels": [
                    {
                        "source": "censys",
                        "value": "CLOUD_PROVIDER"
                    },
                    {
                        "source": "censys",
                        "value": "WEB_SERVER"
                    }
                ],
                "location": {
                    "continent": "Asia",
                    "country": "South Korea",
                    "country_code": "KR",
                    "city": "Seoul",
                    "postal_code": "03141",
                    "timezone": "Asia/Seoul",
                    "province": "Seoul",
                    "coordinates": {
                        "latitude": 37.566,
                        "longitude": 126.9784
                    }
                },
                "autonomous_system": {
                    "asn": 12345,
                    "description": "EXAMPLE-AS-AP Example.Co.LTD",
                    "bgp_prefix": "0.0.0.1/24",
                    "name": "EXAMPLE-AS-AP Example.Co.LTD",
                    "country_code": "KR"
                },
                "whois": {
                    "network": {
                        "handle": "HK-EXAMPLE-20190703",
                        "name": "EXAMPLE LIMITED",
                        "cidrs": [
                            "0.0.0.1/24"
                        ],
                        "created": "2024-11-26T00:00:00Z",
                        "updated": "2025-08-18T00:00:00Z"
                    },
                    "organization": {
                        "handle": "ORG-XL117-RIPE",
                        "name": "EXAMPLE LIMITED",
                        "address": "RM 29-33,5/F,EXAMPLE COMMERCIAL CENTRE,87-105 EXAMPLE ROAD\\n000000\\nEXAMPLE CITY\\nEXAMPLE COUNTRY",
                        "abuse_contacts": [
                            {
                                "handle": "EXAMPLE-RIPE",
                                "name": "EXAMPLE-ROLE",
                                "email": "noc@example.com"
                            }
                        ],
                        "admin_contacts": [
                            {
                                "handle": "EXAMPLE-RIPE",
                                "name": "EXAMPLE-ROLE",
                                "email": "noc@example.com"
                            }
                        ]
                    }
                },
                "services": [
                    {
                        "port": 22,
                        "protocol": "SSH",
                        "transport_protocol": "tcp",
                        "software": [
                            {
                                "source": "censys",
                                "confidence": 0.9,
                                "evidence": [
                                    {
                                        "data_path": "protocol",
                                        "found_value": "SSH",
                                        "literal_match": "SSH"
                                    }
                                ],
                                "type": [
                                    "REMOTE_ACCESS"
                                ],
                                "part": "a"
                            }
                        ],
                        "labels": [
                            {
                                "source": "censys",
                                "confidence": 0.9,
                                "evidence": [
                                    {
                                        "data_path": "protocol",
                                        "found_value": "SSH",
                                        "literal_match": "SSH"
                                    }
                                ],
                                "value": "REMOTE_ACCESS"
                            }
                        ],
                        "threats": [
                            {
                                "name": "BRUTE_FORCE_ATTACK",
                                "source": "censys"
                            }
                        ],
                        "vulns": [
                            {
                                "id": "CVE-2023-12345",
                                "cvss": 7.5,
                                "severity": "HIGH"
                            },
                            {
                                "id": "CVE-2023-67890",
                                "cvss": 5.3,
                                "severity": "MEDIUM"
                            }
                        ],
                        "ip": "0.0.0.1",
                        "scan_time": "2026-02-02T00:46:23Z",
                        "banner": "SSH-2.0-OpenSSH_9.2p1 Debian-2+deb12u3",
                        "banner_hash_sha256": "0000000000000000000000000000000000000000000000000000000000000000",
                        "banner_hex": "5353482d322e302d4f70656e5353485f392e3270312044656269616e2d322b64656231327533",
                        "ja4tscan": {
                            "scan_time": "2026-02-01T17:09:57Z",
                            "fingerprint": "65160_2-4-8-1-3_1460_7_1-2-4-8-16"
                        },
                        "ssh": {
                            "endpoint_id": {
                                "raw": "SSH-2.0-OpenSSH_9.2p1 Debian-2+deb12u3",
                                "protocol_version": "2.0",
                                "software_version": "OpenSSH_9.2p1",
                                "comment": "Debian-2+deb12u3"
                            },
                            "kex_init_message": {
                                "kex_algorithms": [
                                    "example@openssh.com",
                                    "curve25519-sha256",
                                    "example@openssh.com"
                                ],
                                "host_key_algorithms": [
                                    "rsa-sha2-512",
                                    "rsa-sha2-256",
                                    "ecdsa-sha2-nistp256",
                                    "ssh-ed25519"
                                ],
                                "client_to_server_ciphers": [
                                    "example@openssh.com",
                                    "aes128-ctr"
                                ],
                                "server_to_client_ciphers": [
                                    "example@openssh.com",
                                    "aes128-ctr"
                                ],
                                "client_to_server_macs": [
                                    "example@openssh.com",
                                    "example@openssh.com"
                                ],
                                "server_to_client_macs": [
                                    "example@openssh.com",
                                    "example@openssh.com"
                                ],
                                "client_to_server_compression": [
                                    "none",
                                    "example@openssh.com"
                                ],
                                "server_to_client_compression": [
                                    "none",
                                    "example@openssh.com"
                                ]
                            },
                            "algorithm_selection": {
                                "kex_algorithm": "example@libssh.org",
                                "host_key_algorithm": "ecdsa-sha2-nistp256",
                                "client_to_server_cipher": "example@openssh.com",
                                "server_to_client_cipher": "example@openssh.com",
                                "client_to_server_mac": "example@openssh.com",
                                "server_to_client_mac": "example@openssh.com",
                                "client_to_server_compression": "none",
                                "server_to_client_compression": "none"
                            },
                            "server_host_key": {
                                "ecdsa_public_key": {
                                    "b": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
                                    "curve": "P256",
                                    "gx": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
                                    "gy": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
                                    "length": 256,
                                    "n": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
                                    "p": "/////wAAAAEAAAAAAAAAAAAAAAD///////////////8=",
                                    "x": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
                                    "y": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="
                                }
                            },
                            "hassh_fingerprint": "00000000000000000000000000000000"
                        }
                    }
                ],
                "service_count": 3,
                "dns": {
                    "names": [
                        "example.com",
                        "www.example.com"
                    ],
                    "forward_dns": {
                        "names": [
                            "example.com",
                            "www.example.com",
                            "mail.example.com"
                        ]
                    },
                    "reverse_dns": {
                        "names": [
                            "host.example.com"
                        ],
                        "resolve_time": "2026-01-30T18:11:14Z"
                    }
                }
            }
        }
    }
}

Human Readable Output

Scan completed successfully for 0.0.0.1:443

Enriched Host Data

IP Labels Service Count Service Ports Service Protocols Service Transport Protocols Service Labels Service Vulns Service Threats Service Scan Times DNS Names Forward DNS Names Reverse DNS Names Network Name CIDRs Autonomous System Name Autonomous System ASN City Province Postal Code Country Country Code Continent Latitude Longitude
0.0.0.1 CLOUD_PROVIDER, WEB_SERVER 3 22 SSH tcp REMOTE_ACCESS CVE-2023-12345, CVE-2023-67890 BRUTE_FORCE_ATTACK 2026-02-02T00:46:23Z example.com, www.example.com example.com, www.example.com, mail.example.com host.example.com EXAMPLE LIMITED 0.0.0.1/24 EXAMPLE-AS-AP Example.Co.LTD 12345 Seoul Seoul 03141 South Korea KR Asia 37.566 126.9784

cen-related-infrastructure-list


Initiate a CensEye (Related Infrastructure) pivot analysis job for a Host, Web Property, or SHA256 Certificate.

Base Command

cen-related-infrastructure-list

Input

Argument Name Description Required
ioc_type Specify the type of IOC. Possible values are: Host, Web Property, Certificate. Default is Host. Required
ioc_value Specify the value of IOC.

Note: For Web Property IOC type, include the port in the format hostname:port (e.g., example.com:443).
Required

Context Output

Path Type Description
Censys.RelatedInfrastructure.job_id String The unique identifier for the related infrastructure job.
Censys.RelatedInfrastructure.pivot_data.count Number The count of related infrastructure entries for this pivot.
Censys.RelatedInfrastructure.pivot_data.field_value_pairs.field String The field name of the pivot.
Censys.RelatedInfrastructure.pivot_data.field_value_pairs.value String The value of the pivot field.
Censys.RelatedInfrastructure.status String The status of the job (initiated, in_progress, completed, failed).
Censys.RelatedInfrastructure.is_completed Boolean Whether the job has completed.
Censys.RelatedInfrastructure.ioc_value String The value of the IOC.

Command example

!cen-related-infrastructure-list ioc_type="Host" ioc_value="0.0.0.1"

Context Example

{
    "Censys": {
        "RelatedInfrastructure": {
            "ioc_value": "0.0.0.1",
            "status": "completed",
            "job_id": "00000000-0000-0000-0000-000000000001",
            "is_completed": true,
            "pivot_data": [
                {
                    "count": 5395,
                    "field_value_pairs": [
                        {
                            "field": "host.services.banner_hash_sha256",
                            "value": "0000000000000000000000000000000000000000000000000000000000000001"
                        }
                    ]
                },
                {
                    "count": 123620,
                    "field_value_pairs": [
                        {
                            "field": "host.services.endpoints.http.headers.key",
                            "value": "Connection"
                        },
                        {
                            "field": "host.services.endpoints.http.headers.value",
                            "value": "close"
                        }
                    ]
                },
                {
                    "count": 5395,
                    "field_value_pairs": [
                        {
                            "field": "host.services.endpoints.banner_hash_sha256",
                            "value": "0000000000000000000000000000000000000000000000000000000000000001"
                        }
                    ]
                },
                {
                    "count": 36216,
                    "field_value_pairs": [
                        {
                            "field": "host.services.endpoints.http.headers.key",
                            "value": "Content-Type"
                        },
                        {
                            "field": "host.services.endpoints.http.headers.value",
                            "value": "text/plain"
                        }
                    ]
                }
            ]
        }
    }
}

Human Readable Output

Job completed successfully for 0.0.0.1

4 Pivots Data

Key Value Count See results in Censys
host.services.banner_hash_sha256 0000000000000000000000000000000000000000000000000000000000000001 5395 View Pivot Information on Censys platform
host.services.endpoints.banner_hash_sha256 0000000000000000000000000000000000000000000000000000000000000001 5395 View Pivot Information on Censys platform
host.services.endpoints.http.headers.key
host.services.endpoints.http.headers.value
Content-Type
text/plain
36216 View Pivot Information on Censys platform
host.services.endpoints.http.headers.key
host.services.endpoints.http.headers.value
Connection
close
123620 View Pivot Information on Censys platform

Configuration parameters

  • server_url — Server URL (required)
  • api_token — (required)
  • organization_id — Organization ID (required)
  • insecure — Trust any certificate (not secure)
  • proxy — Use system proxy settings
  • premium_access — Determine IP score by labels (for paid subscribers)
  • malicious_labels — IP Malicious labels
  • suspicious_labels — IP suspicious labels
  • malicious_labels_threshold — Malicious labels threshold
  • suspicious_labels_threshold — Suspicious labels threshold
  • integration_reliability — Source Reliability

Commands (7)

  • cen-host-history-list

    Retrieve the event history for a host (IP address).

  • cen-related-infrastructure-list

    Initiate a CensEye (Related Infrastructure) pivot analysis job for a Host, Web Property, or SHA256 Certificate.

  • cen-rescan

    Initiate a live rescan for a known host service at a specific IP and port (ip:port) or hostname and port (hostname:port).

  • cen-search

    Return previews of hosts matching a specified search query or a list of certificates that match the given query.

  • cen-view

    Returns detailed information for an IP address or SHA256 within the specified index.

  • domain

    Return all related IPs as relationships.

  • ip

    Runs reputation on IPs.

import json

import pytest
from CensysV2 import (
    CENSYS_API_URL,
    ENDPOINTS,
    ERRORS,
    OUTPUT_PREFIX,
    VALID_RELATED_INFRA_IOC_TYPE,
    VALID_TRANSPORT_PROTOCOL,
    Client,
    ExecutionMetrics,
    censys_host_history_list_command,
    censys_related_infrastructure_list_command,
    censys_rescan_command,
    censys_search_command,
    censys_search_with_pagination,
    censys_view_command,
    domain_command,
    get_dbot_score,
    handle_exceptions,
    ip_command,
    main,
    run_polling_command,
    test_module as censys_test_module,
)
from CommonServerPython import Common, DemistoException


def util_load_json(path):
    with open(f"test_data/{path}", encoding="utf-8") as f:
        return json.loads(f.read())


@pytest.fixture()
def client():
    return Client(base_url="https://api.platform.censys.io", api_token="test_token")


def test_censys_view_command_host(client, requests_mock):
    """
    Given:
        - A query for an IPv4 asset.
    When:
        - Running the cen-view command.
    Then:
        - Ensure the API is called with the correct parameters.
        - Ensure the command results contain the expected outputs and indicator data.
    """
    # Given
    args = {"index": "ipv4", "query": "127.0.0.1"}
    mock_res = util_load_json("view_host_response.json")
    requests_mock.get("https://api.platform.censys.io/v3/global/asset/host/127.0.0.1", json=mock_res)

    # When
    result = censys_view_command(client, args)

    # Then
    assert result.outputs_prefix == "Censys.View"
    assert result.outputs_key_field == "ip"
    assert result.outputs["ip"] == "127.0.0.1"  # type: ignore
    assert result.indicator.ip == "127.0.0.1"  # type: ignore


def test_censys_view_command_host_with_malicious_labels(client, requests_mock, mocker):
    """
    Given:
        - A query for an IPv4 asset with malicious labels.
        - Malicious labels configured in params.
    When:
        - Running the cen-view command.
    Then:
        - Ensure the DBotScore is BAD.
        - Ensure the malicious_description is properly set.
    """
    # Given
    import demistomock as demisto

    args = {"index": "ipv4", "query": "127.0.0.1"}
    params = {
        "integration_reliability": "C - Fairly reliable",
        "malicious_labels": "malicious,bad",
        "malicious_labels_threshold": 1,
    }
    # Mock demisto.params() to return our test params
    mocker.patch.object(demisto, "params", return_value=params)

    mock_res = util_load_json("view_host_response.json")
    # Add malicious labels to the response
    mock_res["result"]["resource"]["labels"] = [{"value": "malicious"}, {"value": "bad"}]
    requests_mock.get("https://api.platform.censys.io/v3/global/asset/host/127.0.0.1", json=mock_res)

    # When
    result = censys_view_command(client, args)

    # Then
    assert result.outputs_prefix == "Censys.View"
    assert result.indicator.ip == "127.0.0.1"  # type: ignore
    assert result.indicator.dbot_score.score == Common.DBotScore.BAD
    assert result.indicator.dbot_score.malicious_description is not None
    assert "Matched malicious labels:" in result.indicator.dbot_score.malicious_description
    assert "bad" in result.indicator.dbot_score.malicious_description
    assert "malicious" in result.indicator.dbot_score.malicious_description


def test_censys_view_command_cert(client, requests_mock):
    """
    Given:
        - A query for a certificate asset.
    When:
        - Running the cen-view command.
    Then:
        - Ensure the API is called with the correct parameters.
        - Ensure the command results contain the expected outputs.
    """
    # Given
    sha256 = "9d3b51a6b80daf76e074730f19dc01e643ca0c3127d8f48be64cf3302f6622cc"
    args = {"index": "certificates", "query": sha256}
    mock_res = util_load_json("view_cert_response.json")
    requests_mock.get(f"https://api.platform.censys.io/v3/global/asset/certificate/{sha256}", json=mock_res)

    # When
    result = censys_view_command(client, args)

    # Then
    assert result.outputs_prefix == "Censys.View"
    assert result.outputs_key_field == "fingerprint_sha256"
    assert result.outputs["fingerprint_sha256"] == sha256  # type: ignore


def test_censys_search_command_host(client, requests_mock):
    """
    Given:
        - A search query for IPv4 assets.
    When:
        - Running the cen-search command.
    Then:
        - Ensure the API is called with the correct parameters.
        - Ensure the command results contain the expected outputs.
    """
    # Given
    args = {"index": "ipv4", "query": "host.services.port:443", "limit": 1}
    mock_res = util_load_json("search_host_response.json")
    requests_mock.post("https://api.platform.censys.io/v3/global/search/query", json=mock_res)

    # When
    result = censys_search_command(client, args)

    # Then
    assert result.outputs_prefix == "Censys.Search"
    assert result.outputs_key_field == "ip"
    assert len(result.outputs) == 1  # type: ignore
    assert result.outputs[0]["ip"] == "127.0.0.1"  # type: ignore


def test_censys_search_command_certs(client, requests_mock):
    """
    Given:
        - A search query for certificate assets.
    When:
        - Running the cen-search command.
    Then:
        - Ensure the API is called with the correct parameters.
        - Ensure the command results contain the expected outputs.
    """
    # Given
    args = {"index": "certificates", "query": "cert.parsed.subject.common_name:google.com", "limit": 1}
    mock_res = util_load_json("search_certs_response.json")
    requests_mock.post("https://api.platform.censys.io/v3/global/search/query", json=mock_res)

    # When
    result = censys_search_command(client, args)

    # Then
    assert result.outputs_prefix == "Censys.Search"
    assert result.outputs_key_field == "fingerprint_sha256"
    assert len(result.outputs) == 1  # type: ignore
    assert result.outputs[0]["fingerprint_sha256"] == (  # type: ignore
        "0003da4aee3b252097bfc7f871ab6fbe3e08eb94c34ff5cea91aaa29248d3c8b"
    )


def test_ip_command(client, requests_mock):
    """
    Given:
        - An IP address to check.
        - Malicious labels and threshold in params.
    When:
        - Running the ip command.
    Then:
        - Ensure the API is called with the correct parameters.
        - Ensure the command results contain the expected indicator and reputation data.
        - Ensure the DBotScore is calculated based on labels.
        - Ensure the malicious_description is properly set.
    """
    # Given
    args = {"ip": "127.0.0.1"}
    params = {
        "integration_reliability": "C - Fairly reliable",
        "malicious_labels": "malicious",
        "malicious_labels_threshold": 1,
    }
    mock_res = util_load_json("ip_command_response.json")
    # Ensure the mock response has the malicious label
    mock_res["result"]["hits"][0]["host_v1"]["resource"]["labels"] = [{"value": "malicious"}]
    requests_mock.post("https://api.platform.censys.io/v3/global/search/query", json=mock_res)

    # When
    results = ip_command(client, args, params)

    # Then
    assert len(results) >= 1
    result = results[0]
    assert result.outputs_prefix == "Censys.IP"
    assert result.indicator.ip == "127.0.0.1"  # type: ignore
    assert result.indicator.dbot_score.score == Common.DBotScore.BAD
    assert result.indicator.dbot_score.malicious_description is not None
    assert "Matched malicious labels:" in result.indicator.dbot_score.malicious_description
    assert "malicious" in result.indicator.dbot_score.malicious_description


def test_domain_command(client, requests_mock):
    """
    Given:
        - A domain to check.
    When:
        - Running the domain command.
    Then:
        - Ensure the API is called with the correct parameters.
        - Ensure the command results contain the expected indicator and relationship data.
    """
    # Given
    args = {"domain": "facebook.com"}
    params = {}
    mock_res = util_load_json("domain_command_response.json")
    requests_mock.post("https://api.platform.censys.io/v3/global/search/query", json=mock_res)

    # When
    results = domain_command(client, args, params)

    # Then
    assert len(results) >= 1
    result = results[0]
    assert result.outputs_prefix == "Censys.Domain"
    assert result.indicator.domain == "facebook.com"  # type: ignore
    assert result.indicator.dbot_score.score == Common.DBotScore.NONE
    assert len(result.relationships) > 0  # type: ignore


def test_domain_command_with_malicious_labels(client, requests_mock):
    """
    Given:
        - A domain to check with malicious labels.
        - Malicious labels configured in params.
    When:
        - Running the domain command.
    Then:
        - Ensure the DBotScore is BAD.
        - Ensure the malicious_description is properly set.
    """
    # Given
    args = {"domain": "malicious.com"}
    params = {
        "integration_reliability": "C - Fairly reliable",
        "malicious_labels": "malicious,phishing",
        "malicious_labels_threshold": 1,
    }
    mock_res = util_load_json("domain_command_response.json")
    # Modify the response to include malicious labels
    mock_res["result"]["hits"][0]["host_v1"]["resource"]["labels"] = [{"value": "malicious"}, {"value": "phishing"}]
    # Update the domain in the response
    mock_res["result"]["hits"][0]["host_v1"]["resource"]["dns"]["names"] = ["malicious.com"]
    mock_res["result"]["hits"][1]["webproperty_v1"]["resource"]["hostname"] = "malicious.com"
    requests_mock.post("https://api.platform.censys.io/v3/global/search/query", json=mock_res)

    # When
    results = domain_command(client, args, params)

    # Then
    assert len(results) >= 1
    result = results[0]
    assert result.outputs_prefix == "Censys.Domain"
    assert result.indicator.domain == "malicious.com"  # type: ignore
    assert result.indicator.dbot_score.score == Common.DBotScore.BAD
    assert result.indicator.dbot_score.malicious_description is not None
    assert "Matched malicious labels:" in result.indicator.dbot_score.malicious_description
    assert (
        "malicious" in result.indicator.dbot_score.malicious_description
        or "phishing" in result.indicator.dbot_score.malicious_description
    )


def test_domain_command_with_suspicious_labels(client, requests_mock):
    """
    Given:
        - A domain to check with suspicious labels.
        - Suspicious labels configured in params.
    When:
        - Running the domain command.
    Then:
        - Ensure the DBotScore is SUSPICIOUS.
        - Ensure the malicious_description is properly set.
    """
    # Given
    args = {"domain": "suspicious.com"}
    params = {
        "integration_reliability": "C - Fairly reliable",
        "suspicious_labels": "suspicious,spam",
        "suspicious_labels_threshold": 1,
    }
    mock_res = util_load_json("domain_command_response.json")
    # Modify the response to include suspicious labels
    mock_res["result"]["hits"][0]["host_v1"]["resource"]["labels"] = [{"value": "suspicious"}]
    # Update the domain in the response
    mock_res["result"]["hits"][0]["host_v1"]["resource"]["dns"]["names"] = ["suspicious.com"]
    mock_res["result"]["hits"][1]["webproperty_v1"]["resource"]["hostname"] = "suspicious.com"
    requests_mock.post("https://api.platform.censys.io/v3/global/search/query", json=mock_res)

    # When
    results = domain_command(client, args, params)

    # Then
    assert len(results) >= 1
    result = results[0]
    assert result.outputs_prefix == "Censys.Domain"
    assert result.indicator.domain == "suspicious.com"  # type: ignore
    assert result.indicator.dbot_score.score == Common.DBotScore.SUSPICIOUS
    assert result.indicator.dbot_score.malicious_description is not None
    assert "Matched suspicious labels:" in result.indicator.dbot_score.malicious_description
    assert "suspicious" in result.indicator.dbot_score.malicious_description


def test_censys_search_with_pagination(client, requests_mock):
    """
    Given:
        - A search query that returns multiple pages.
    When:
        - Running censys_search_with_pagination.
    Then:
        - Ensure all hits are collected across pages.
        - Ensure the page size is adjusted correctly.
    """
    query = "test query"

    # Mock multiple pages
    requests_mock.post(
        "https://api.platform.censys.io/v3/global/search/query",
        [
            {
                "json": {
                    "result": {
                        "hits": [{"host_v1": {"resource": {"ip": "1.1.1.1"}}}],
                        "total_hits": 2,
                        "next_page_token": "token2",
                    }
                }
            },
            {
                "json": {
                    "result": {"hits": [{"host_v1": {"resource": {"ip": "2.2.2.2"}}}], "total_hits": 2, "next_page_token": ""}
                }
            },
        ],
    )

    result = censys_search_with_pagination(client, query, page_size=1, limit=2)

    assert len(result["result"]["hits"]) == 2
    assert result["result"]["hits"][0]["host_v1"]["resource"]["ip"] == "1.1.1.1"
    assert result["result"]["hits"][1]["host_v1"]["resource"]["ip"] == "2.2.2.2"


def test_censys_search_with_pagination_remaining(client, requests_mock):
    """
    Given:
        - A search query with a limit that requires adjusting page_size.
    When:
        - Running censys_search_with_pagination.
    Then:
        - Ensure page_size is adjusted for the last page.
    """
    query = "test query"
    # First page returns 1 hit, limit is 2, so remaining is 1.
    requests_mock.post(
        "https://api.platform.censys.io/v3/global/search/query",
        [
            {
                "json": {
                    "result": {
                        "hits": [{"host_v1": {"resource": {"ip": "1.1.1.1"}}}],
                        "total_hits": 2,
                        "next_page_token": "token2",
                    }
                }
            },
            {
                "json": {
                    "result": {"hits": [{"host_v1": {"resource": {"ip": "8.8.8.8"}}}], "total_hits": 2, "next_page_token": ""}
                }
            },
        ],
    )

    result = censys_search_with_pagination(client, query, page_size=10, limit=2)
    assert len(result["result"]["hits"]) == 2


def test_censys_search_with_pagination_limit_trim(client, requests_mock):
    """
    Given:
        - A search query with a limit.
        - API returns more hits than the limit.
    When:
        - Running censys_search_with_pagination.
    Then:
        - Ensure hits are trimmed to the limit.
    """
    query = "test query"
    requests_mock.post(
        "https://api.platform.censys.io/v3/global/search/query",
        json={
            "result": {
                "hits": [{"host_v1": {"resource": {"ip": "1.1.1.1"}}}, {"host_v1": {"resource": {"ip": "2.2.2.2"}}}],
                "total_hits": 2,
                "next_page_token": "",
            }
        },
    )

    result = censys_search_with_pagination(client, query, limit=1)
    assert len(result["result"]["hits"]) == 1


def test_get_dbot_score():
    """
    Given:
        - Different sets of labels and thresholds.
    When:
        - Running get_dbot_score.
    Then:
        - Ensure the correct DBot score and description are returned.
    """
    params = {
        "malicious_labels": "malicious,bad",
        "suspicious_labels": "suspicious,warn",
        "malicious_labels_threshold": 1,
        "suspicious_labels_threshold": 1,
    }

    # Test BAD - single malicious label
    score, description = get_dbot_score(params, ["malicious"])
    assert score == Common.DBotScore.BAD
    assert description == "Matched malicious labels: malicious"

    # Test BAD - multiple malicious labels (should be sorted alphabetically)
    score, description = get_dbot_score(params, ["malicious", "bad"])
    assert score == Common.DBotScore.BAD
    assert description == "Matched malicious labels: bad, malicious"

    # Test SUSPICIOUS - single suspicious label
    score, description = get_dbot_score(params, ["suspicious"])
    assert score == Common.DBotScore.SUSPICIOUS
    assert description == "Matched suspicious labels: suspicious"

    # Test SUSPICIOUS - multiple suspicious labels (should be sorted alphabetically)
    score, description = get_dbot_score(params, ["warn", "suspicious"])
    assert score == Common.DBotScore.SUSPICIOUS
    assert description == "Matched suspicious labels: suspicious, warn"

    # Test NONE - clean label
    score, description = get_dbot_score(params, ["clean"])
    assert score == Common.DBotScore.NONE
    assert description is None

    # Test threshold - malicious threshold not met
    params["malicious_labels_threshold"] = 2
    score, description = get_dbot_score(params, ["malicious"])
    assert score == Common.DBotScore.NONE
    assert description is None

    # Test threshold - malicious threshold met
    score, description = get_dbot_score(params, ["malicious", "bad"])
    assert score == Common.DBotScore.BAD
    assert description == "Matched malicious labels: bad, malicious"

    # Test threshold - suspicious threshold
    params["suspicious_labels_threshold"] = 2
    score, description = get_dbot_score(params, ["suspicious"])
    assert score == Common.DBotScore.NONE
    assert description is None

    # Test threshold - suspicious threshold met
    score, description = get_dbot_score(params, ["suspicious", "warn"])
    assert score == Common.DBotScore.SUSPICIOUS
    assert description == "Matched suspicious labels: suspicious, warn"


def test_handle_exceptions():
    """
    Given:
        - Different types of exceptions.
    When:
        - Running handle_exceptions.
    Then:
        - Ensure exceptions are handled correctly and metrics are updated.
    """
    import requests

    # Given
    results = []
    execution_metrics = ExecutionMetrics()

    # When / Then - Test quota error (403 with "quota")
    mock_res = requests.Response()
    mock_res.status_code = 403
    e = DemistoException("quota exceeded", res=mock_res)
    assert handle_exceptions(e, results, execution_metrics, "item1") is True
    assert execution_metrics.quota_error == 1
    assert "Quota exceeded" in results[0].readable_output

    # When / Then - Test rate limit error (429)
    mock_res.status_code = 429
    e = DemistoException("too many requests", res=mock_res)
    handle_exceptions(e, results, execution_metrics, "item2")
    assert execution_metrics.general_error == 1
    assert "Too many requests" in results[1].readable_output

    # When / Then - Test non-premium access error (403 with "specific fields")
    mock_res.status_code = 403
    e = DemistoException("specific fields", res=mock_res)
    with pytest.raises(DemistoException, match="Your user does not have permission for premium features"):
        handle_exceptions(e, results, execution_metrics, "item3")

    # When / Then - Test general error
    e = Exception("general error")
    assert handle_exceptions(e, results, execution_metrics, "item4") is False
    assert execution_metrics.general_error == 2
    assert "An error occurred" in results[2].readable_output

    # When / Then - Test unauthorized error (401)
    mock_res = requests.Response()
    mock_res.status_code = 401
    e = DemistoException("unauthorized", res=mock_res)
    with pytest.raises(DemistoException):
        handle_exceptions(e, results, execution_metrics, "item5")


def test_test_module_success(client, requests_mock):
    """
    Given:
        - Valid parameters.
    When:
        - Running test-module.
    Then:
        - Ensure "ok" is returned.
    """
    params = {"api_token": {"password": "test_token"}}
    requests_mock.post("https://api.platform.censys.io/v3/global/search/query", json={"result": {"hits": []}})
    assert censys_test_module(client, params) == "ok"


def test_test_module_premium_error(client):
    """
    Given:
        - Premium labels selected without premium access.
    When:
        - Running test-module.
    Then:
        - Ensure DemistoException is raised.
    """
    params = {"premium_access": False, "malicious_labels": "bad"}
    with pytest.raises(
        DemistoException, match="The 'Determine IP score by label' feature only works for Censys paid subscribers"
    ):
        censys_test_module(client, params)


def test_test_module_general_demisto_error(client, mocker):
    """
    Given:
        - A general DemistoException during test-module.
    When:
        - Running test-module.
    Then:
        - Ensure the exception is re-raised.
    """
    # Given
    params = {"premium_access": False}
    mocker.patch("CensysV2.censys_search_with_pagination", side_effect=DemistoException("general error"))

    # When / Then
    with pytest.raises(DemistoException, match="general error"):
        censys_test_module(client, params)


def test_test_module_premium_permission_error(client, requests_mock):
    """
    Given:
        - A 403 error with "specific fields" during test-module.
    When:
        - Running test-module.
    Then:
        - Ensure a descriptive DemistoException is raised.
    """
    params = {"premium_access": True}
    requests_mock.post(
        "https://api.platform.censys.io/v3/global/search/query",
        status_code=403,
        json={"error": "Your query contains specific fields that require premium access"},
    )
    with pytest.raises(DemistoException, match="Your user does not have permission for premium features"):
        censys_test_module(client, params)


def test_test_module_unauthorized_error(client, requests_mock):
    """
    Given:
        - A 401 error during test-module.
    When:
        - Running test-module.
    Then:
        - Ensure a descriptive DemistoException is raised.
    """
    params = {"premium_access": False}
    requests_mock.post(
        "https://api.platform.censys.io/v3/global/search/query",
        status_code=401,
        json={"error": {"code": 401, "status": "Unauthorized", "message": "Access credentials are invalid"}},
    )
    with pytest.raises(DemistoException, match="401 Unauthorized: Access credentials are invalid"):
        censys_test_module(client, params)


def test_test_module_forbidden_error(client, requests_mock):
    """
    Given:
        - A 403 error (not premium) during test-module.
    When:
        - Running test-module.
    Then:
        - Ensure a descriptive DemistoException is raised.
    """
    params = {"premium_access": False}
    requests_mock.post(
        "https://api.platform.censys.io/v3/global/search/query",
        status_code=403,
        json={"error": "Forbidden"},
    )
    with pytest.raises(DemistoException, match="403 Forbidden: The provided Organization ID is incorrect"):
        censys_test_module(client, params)


def test_test_module_unprocessable_entity_error(client, requests_mock):
    """
    Given:
        - A 422 error during test-module.
    When:
        - Running test-module.
    Then:
        - Ensure a descriptive DemistoException is raised.
    """
    params = {"premium_access": False}
    requests_mock.post(
        "https://api.platform.censys.io/v3/global/search/query",
        status_code=422,
        json={"error": "Unprocessable Entity"},
    )
    with pytest.raises(DemistoException, match="422 Unprocessable Entity: The provided Organization ID is malformed"):
        censys_test_module(client, params)


def test_ip_command_no_hits(client, requests_mock):
    """
    Given:
        - An IP that returns no hits (missing 'hits' field).
    When:
        - Running ip_command.
    Then:
        - Ensure an error message is returned in results.
    """
    args = {"ip": "1.1.1.1"}
    params = {}
    requests_mock.post("https://api.platform.censys.io/v3/global/search/query", json={"result": {}})
    results = ip_command(client, args, params)
    # When hits field is missing (None), it triggers an error that gets caught and handled
    # The exception handler reports it as an error
    assert (
        "Unexpected response: 'hits' path not found" in results[0].readable_output
        or "No results found for IP: 1.1.1.1" in results[0].readable_output
    )


def test_domain_command_no_results(client, requests_mock):
    """
    Given:
        - A domain that returns no results (hits is empty list).
    When:
        - Running domain_command.
    Then:
        - Ensure "No results found" message is returned.
    """
    args = {"domain": "nonexistent.com"}
    params = {}
    requests_mock.post("https://api.platform.censys.io/v3/global/search/query", json={"result": {"hits": []}})
    results = domain_command(client, args, params)
    # When hits is an empty list, it should return "No results found"
    assert "No results found for domain: nonexistent.com" in results[0].readable_output


def test_domain_command_single_domain(client, requests_mock):
    """
    Given:
        - A single domain (not a list).
    When:
        - Running domain_command.
    Then:
        - Ensure the query is built correctly.
    """
    args = {"domain": "facebook.com"}
    params = {}
    mock_res = util_load_json("domain_command_response.json")
    requests_mock.post("https://api.platform.censys.io/v3/global/search/query", json=mock_res)

    results = domain_command(client, args, params)
    assert results[0].indicator.domain == "facebook.com"


def test_domain_command_no_match(client, requests_mock):
    """
    Given:
        - A domain that has hits but none match the requested domain.
    When:
        - Running domain_command.
    Then:
        - Ensure "No results found" is in the output.
    """
    args = {"domain": "nonexistent.com"}
    params = {}
    # Return a hit for a different domain
    requests_mock.post(
        "https://api.platform.censys.io/v3/global/search/query",
        json={"result": {"hits": [{"host_v1": {"resource": {"dns": {"names": ["other.com"]}, "ip": "1.1.1.1"}}}]}},
    )
    results = domain_command(client, args, params)
    assert "No results found for domain: nonexistent.com" in results[0].readable_output


def test_ip_command_not_found(client, requests_mock):
    """
    Given:
        - An IP address that is not found in search results.
    When:
        - Running ip_command.
    Then:
        - Ensure "No results found for IP" message is returned.
    """
    # Given
    args = {"ip": "192.168.1.1"}
    params = {}
    # Return empty hits
    requests_mock.post("https://api.platform.censys.io/v3/global/search/query", json={"result": {"hits": []}})

    # When
    results = ip_command(client, args, params)

    # Then
    assert len(results) >= 1
    assert "No results found for IP: 192.168.1.1" in results[0].readable_output


def test_ip_command_multiple_ips_partial_found(client, requests_mock):
    """
    Given:
        - Multiple IP addresses where only some are found in search results.
    When:
        - Running ip_command.
    Then:
        - Ensure results are returned for found IPs.
        - Ensure "No results found" messages are returned for IPs not found.
    """
    # Given
    args = {"ip": ["127.0.0.1", "192.168.1.1", "10.0.0.1"]}
    params = {"integration_reliability": "C - Fairly reliable"}
    # Return hits only for 127.0.0.1
    mock_res = util_load_json("ip_command_response.json")
    requests_mock.post("https://api.platform.censys.io/v3/global/search/query", json=mock_res)

    # When
    results = ip_command(client, args, params)

    # Then
    # Should have: 1 result for found IP + 2 "not found" messages
    assert len(results) >= 3

    # Check that we have a result for the found IP
    found_result = None
    not_found_results = []
    for result in results:
        if hasattr(result, "outputs_prefix") and result.outputs_prefix == "Censys.IP":
            found_result = result
        elif (
            hasattr(result, "readable_output") and result.readable_output and "No results found for IP:" in result.readable_output
        ):
            not_found_results.append(result)

    assert found_result is not None
    assert found_result.indicator.ip == "127.0.0.1"
    assert len(not_found_results) == 2
    assert any("192.168.1.1" in r.readable_output for r in not_found_results)
    assert any("10.0.0.1" in r.readable_output for r in not_found_results)


def test_ip_command_multiple_ips_all_found(client, requests_mock):
    """
    Given:
        - Multiple IP addresses that are all found in search results.
    When:
        - Running ip_command.
    Then:
        - Ensure results are returned for all IPs.
        - Ensure no "not found" messages are returned.
    """
    # Given
    args = {"ip": ["127.0.0.1", "8.8.8.8"]}
    params = {"integration_reliability": "C - Fairly reliable"}
    # Return hits for both IPs
    requests_mock.post(
        "https://api.platform.censys.io/v3/global/search/query",
        json={
            "result": {
                "hits": [
                    {"host_v1": {"resource": {"ip": "127.0.0.1", "labels": [], "services": []}}},
                    {"host_v1": {"resource": {"ip": "8.8.8.8", "labels": [], "services": []}}},
                ]
            }
        },
    )

    # When
    results = ip_command(client, args, params)

    # Then
    # Should have results for both IPs, no "not found" messages
    ip_results = [r for r in results if hasattr(r, "outputs_prefix") and r.outputs_prefix == "Censys.IP"]
    not_found_results = [
        r
        for r in results
        if hasattr(r, "readable_output") and r.readable_output and "No results found for IP:" in r.readable_output
    ]

    assert len(ip_results) == 2
    assert len(not_found_results) == 0
    assert any(r.indicator.ip == "127.0.0.1" for r in ip_results)
    assert any(r.indicator.ip == "8.8.8.8" for r in ip_results)


def test_domain_command_multiple_domains_partial_found(client, requests_mock):
    """
    Given:
        - Multiple domains where only some are found in search results.
    When:
        - Running domain_command.
    Then:
        - Ensure results are returned for found domains.
        - Ensure "No results found" messages are returned for domains not found.
    """
    # Given
    args = {"domain": ["facebook.com", "nonexistent1.com", "nonexistent2.com"]}
    params = {"integration_reliability": "C - Fairly reliable"}
    # Return hits only for facebook.com
    mock_res = util_load_json("domain_command_response.json")
    requests_mock.post("https://api.platform.censys.io/v3/global/search/query", json=mock_res)

    # When
    results = domain_command(client, args, params)

    # Then
    # Should have: 1 result for found domain + 2 "not found" messages
    assert len(results) >= 3

    # Check that we have a result for the found domain
    found_result = None
    not_found_results = []
    for result in results:
        if hasattr(result, "outputs_prefix") and result.outputs_prefix == "Censys.Domain":
            found_result = result
        elif (
            hasattr(result, "readable_output")
            and result.readable_output
            and "No results found for domain:" in result.readable_output
        ):
            not_found_results.append(result)

    assert found_result is not None
    assert found_result.indicator.domain == "facebook.com"
    assert len(not_found_results) == 2
    assert any("nonexistent1" in r.readable_output for r in not_found_results)
    assert any("nonexistent2" in r.readable_output for r in not_found_results)


def test_domain_command_multiple_domains_all_found(client, requests_mock):
    """
    Given:
        - Multiple domains that are all found in search results.
    When:
        - Running domain_command.
    Then:
        - Ensure results are returned for all domains.
        - Ensure no "not found" messages are returned.
    """
    # Given
    args = {"domain": ["facebook.com", "google.com"]}
    params = {"integration_reliability": "C - Fairly reliable"}
    # Return hits for both domains
    requests_mock.post(
        "https://api.platform.censys.io/v3/global/search/query",
        json={
            "result": {
                "hits": [
                    {"host_v1": {"resource": {"dns": {"names": ["facebook.com"]}, "ip": "1.1.1.1", "labels": []}}},
                    {"host_v1": {"resource": {"dns": {"names": ["google.com"]}, "ip": "2.2.2.2", "labels": []}}},
                ]
            }
        },
    )

    # When
    results = domain_command(client, args, params)

    # Then
    # Should have results for both domains, no "not found" messages
    domain_results = [r for r in results if hasattr(r, "outputs_prefix") and r.outputs_prefix == "Censys.Domain"]
    not_found_results = [
        r
        for r in results
        if hasattr(r, "readable_output") and r.readable_output and "No results found for domain:" in r.readable_output
    ]

    assert len(domain_results) == 2
    assert len(not_found_results) == 0
    assert any(r.indicator.domain == "facebook.com" for r in domain_results)
    assert any(r.indicator.domain == "google.com" for r in domain_results)


def test_domain_command_multiple_domains_none_found(client, requests_mock):
    """
    Given:
        - Multiple domains where none are found in search results.
    When:
        - Running domain_command.
    Then:
        - Ensure "No results found" messages are returned for all domains.
    """
    # Given
    args = {"domain": ["nonexistent1.com", "nonexistent2.com"]}
    params = {}
    # Return empty hits
    requests_mock.post("https://api.platform.censys.io/v3/global/search/query", json={"result": {"hits": []}})

    # When
    results = domain_command(client, args, params)

    # Then
    # Should have "not found" messages for both domains
    not_found_results = [
        r
        for r in results
        if hasattr(r, "readable_output") and r.readable_output and "No results found for domain:" in r.readable_output
    ]
    assert len(not_found_results) == 2
    assert any("nonexistent1" in r.readable_output for r in not_found_results)
    assert any("nonexistent2" in r.readable_output for r in not_found_results)


def test_ip_command_multiple_ips_none_found(client, requests_mock):
    """
    Given:
        - Multiple IP addresses where none are found in search results.
    When:
        - Running ip_command.
    Then:
        - Ensure "No results found" messages are returned for all IPs.
    """
    # Given
    args = {"ip": ["192.168.1.1", "10.0.0.1"]}
    params = {}
    # Return empty hits
    requests_mock.post("https://api.platform.censys.io/v3/global/search/query", json={"result": {"hits": []}})

    # When
    results = ip_command(client, args, params)

    # Then
    # Should have "not found" messages for both IPs
    not_found_results = [
        r
        for r in results
        if hasattr(r, "readable_output") and r.readable_output and "No results found for IP:" in r.readable_output
    ]
    assert len(not_found_results) == 2
    assert any("192.168.1.1" in r.readable_output for r in not_found_results)
    assert any("10.0.0.1" in r.readable_output for r in not_found_results)


def test_main_test_module(mocker):
    """
    Given:
        - The test-module command.
    When:
        - Running main.
    Then:
        - Ensure test_module is called and results are returned.
    """
    # Given
    import demistomock as demisto

    mocker.patch.object(demisto, "command", return_value="test-module")
    mocker.patch.object(demisto, "params", return_value={"api_token": {"password": "token"}})
    mocker.patch.object(demisto, "results")
    mocker.patch("CensysV2.test_module", return_value="ok")

    # When
    main()

    # Then
    demisto.results.assert_called_with("ok")


def test_main_cen_view(mocker):
    """
    Given:
        - The cen-view command.
    When:
        - Running main.
    Then:
        - Ensure censys_view_command is called and results are returned.
    """
    # Given
    import demistomock as demisto

    mocker.patch.object(demisto, "command", return_value="cen-view")
    mocker.patch.object(demisto, "args", return_value={"index": "ipv4", "query": "8.8.8.8"})
    mocker.patch.object(demisto, "params", return_value={"api_token": {"password": "token"}})
    mocker.patch.object(demisto, "results")
    mocker.patch("CensysV2.censys_view_command", return_value="view_results")

    # When
    main()

    # Then
    demisto.results.assert_called_with("view_results")


def test_main_cen_search(mocker):
    """
    Given:
        - The cen-search command.
    When:
        - Running main.
    Then:
        - Ensure censys_search_command is called and results are returned.
    """
    # Given
    import demistomock as demisto

    mocker.patch.object(demisto, "command", return_value="cen-search")
    mocker.patch.object(demisto, "args", return_value={"index": "ipv4", "query": "test"})
    mocker.patch.object(demisto, "params", return_value={"api_token": {"password": "token"}})
    mocker.patch.object(demisto, "results")
    mocker.patch("CensysV2.censys_search_command", return_value="search_results")

    # When
    main()

    # Then
    demisto.results.assert_called_with("search_results")


def test_main_ip(mocker):
    """
    Given:
        - The ip command.
    When:
        - Running main.
    Then:
        - Ensure ip_command is called and results are returned.
    """
    # Given
    import demistomock as demisto

    mocker.patch.object(demisto, "command", return_value="ip")
    mocker.patch.object(demisto, "args", return_value={"ip": "8.8.8.8"})
    mocker.patch.object(demisto, "params", return_value={"api_token": {"password": "token"}})
    mocker.patch.object(demisto, "results")
    mocker.patch("CensysV2.ip_command", return_value="ip_results")

    # When
    main()

    # Then
    demisto.results.assert_called_with("ip_results")


def test_main_domain(mocker):
    """
    Given:
        - The domain command.
    When:
        - Running main.
    Then:
        - Ensure domain_command is called and results are returned.
    """
    # Given
    import demistomock as demisto

    mocker.patch.object(demisto, "command", return_value="domain")
    mocker.patch.object(demisto, "args", return_value={"domain": "google.com"})
    mocker.patch.object(demisto, "params", return_value={"api_token": {"password": "token"}})
    mocker.patch.object(demisto, "results")
    mocker.patch("CensysV2.domain_command", return_value="domain_results")

    # When
    main()

    # Then
    demisto.results.assert_called_with("domain_results")


def test_main_error(mocker):
    """
    Given:
        - A command that raises an exception.
    When:
        - Running main.
    Then:
        - Ensure return_error is called.
    """
    # Given
    import demistomock as demisto

    mocker.patch.object(demisto, "command", return_value="ip")
    mocker.patch.object(demisto, "params", return_value={"api_token": {"password": "token"}})
    mocker.patch.object(demisto, "results")
    # Mock return_error in CensysV2 namespace to avoid SystemExit
    mock_return_error = mocker.patch("CensysV2.return_error")
    mocker.patch("CensysV2.ip_command", side_effect=Exception("unexpected error"))

    # When
    main()

    # Then
    mock_return_error.assert_called()


def test_search_certs_command_with_fields(client, requests_mock):
    """
    Given:
        - A search query for certificates with extra fields.
    When:
        - Running search_certs_command (via censys_search_command).
    Then:
        - Ensure the API is called and results are processed.
    """
    args = {"index": "certificates", "query": "test", "fields": "cert.parsed.issuer.common_name", "limit": 1}
    mock_res = util_load_json("search_certs_response.json")
    requests_mock.post("https://api.platform.censys.io/v3/global/search/query", json=mock_res)

    result = censys_search_command(client, args)
    assert result.outputs_prefix == "Censys.Search"


def test_search_certs_command_error(client, requests_mock):
    """
    Given:
        - A search query for certificates that returns an unexpected response.
    When:
        - Running search_certs_command.
    Then:
        - Ensure ValueError is raised.
    """
    from CensysV2 import search_certs_command

    args = {"fields": ""}
    requests_mock.post("https://api.platform.censys.io/v3/global/search/query", json={"result": {}})
    with pytest.raises(ValueError, match="Unexpected response: 'hits' path not found"):
        search_certs_command(client, args, "query", 1)


def test_censys_host_history_list_command_success_with_pagination(client, requests_mock, mocker):
    """
    Test Case 1: Success scenario with 3 API calls and MAX_NUMBER_OF_RECORDS=8

    Given:
        - Valid host_id, start_time, and end_time arguments
        - MAX_NUMBER_OF_RECORDS mocked to 8
        - API returns 2 events per page for 2 pages (total 4 events)
    When:
        - Running censys_host_history_list_command command
    Then:
        - Ensure 3 API calls are made (2 with data, 1 stops at max records)
        - Ensure exactly 4 events are returned
        - Ensure partial_data is False
        - Ensure HR output contains correct headers and data
        - Ensure context output matches expected structure
    """
    mocker.patch("CensysV2.MAX_NUMBER_OF_RECORDS", 8)

    # Load test data
    api_responses = util_load_json("host_history_api_response.json")
    context_data = util_load_json("host_history_context_output.json")
    with open("test_data/host_history_sucess_hr.md") as f:
        hr_output = f.read()

    # Setup args and params
    args = {"host_id": "0.0.0.1", "start_time": "2026-02-20T00:00:00.000Z", "end_time": "2026-03-01T12:00:00.000Z"}

    requests_mock.get(
        f"{CENSYS_API_URL}/{ENDPOINTS['HOST_EVENT_HISTORY'].format('0.0.0.1')}",
        [
            {"json": api_responses["page1_response"]},
            {"json": api_responses["page2_response"]},
            {"json": api_responses["page3_response"]},
            {"json": api_responses["page4_response"]},
        ],
    )

    # Execute command
    result = censys_host_history_list_command(client, args)

    # Assertions
    assert result.outputs_prefix == OUTPUT_PREFIX["HOST_EVENT_HISTORY"]
    assert result.outputs_key_field == "ip"
    assert result.outputs == context_data["success_context"]
    assert result.readable_output == hr_output


def test_censys_host_history_list_command_pagination_no_scanned_to(client, requests_mock, mocker):
    """
    Test Case 1b: Success scenario with pagination stopping when scanned_to is None

    Given:
        - Valid host_id, start_time, and end_time arguments
        - MAX_NUMBER_OF_RECORDS mocked to 8
        - API returns 2 events on page1, then page2 has no scanned_to cursor
    When:
        - Running censys_host_history_list_command command
    Then:
        - Ensure pagination stops when scanned_to is None (covers lines 1055-1056)
        - Ensure exactly 4 events are returned
        - Ensure partial_data is False
        - Ensure HR output contains correct headers and data
    """
    # Load test data
    api_responses = util_load_json("host_history_api_response.json")
    context_data = util_load_json("host_history_context_output.json")
    with open("test_data/host_history_no_scanned_to_hr.md") as f:
        hr_output = f.read()

    # Setup args and params
    args = {"host_id": "0.0.0.1", "start_time": "2026-02-20T00:00:00.000Z", "end_time": "2026-03-01T12:00:00.000Z"}

    requests_mock.get(
        f"{CENSYS_API_URL}/{ENDPOINTS['HOST_EVENT_HISTORY'].format('0.0.0.1')}",
        [
            {"json": api_responses["page1_response"]},  # 2 events, scanned_to="2026-03-01T08:00:00.000Z"
            {"json": api_responses["page5_response"]},  # 2 events, no scanned_to
        ],
    )

    # Execute command
    result = censys_host_history_list_command(client, args)

    # Assertions
    assert result.outputs_prefix == OUTPUT_PREFIX["HOST_EVENT_HISTORY"]
    assert result.outputs_key_field == "ip"
    assert result.outputs == context_data["pagination_no_scanned_to_context"]
    assert result.readable_output == hr_output


def test_censys_host_history_list_command_pagination_scanned_to_boundary(client, requests_mock, mocker):
    """
    Test Case Success scenario with pagination stopping when scanned_to <= start_time

    Given:
        - Valid host_id, start_time, and end_time arguments
        - MAX_NUMBER_OF_RECORDS mocked to 10
        - API returns events until scanned_to="0001-01-01T00:00:00Z" which is <= start_time
    When:
        - Running censys_host_history_list_command command
    Then:
        - Ensure pagination stops when scanned_to <= start_time (covers lines 1060-1063)
        - Ensure exactly 8 events are returned
        - Ensure partial_data is False
        - Ensure HR output contains correct headers and data
    """
    mocker.patch("CensysV2.MAX_NUMBER_OF_RECORDS", 10)

    # Load test data
    api_responses = util_load_json("host_history_api_response.json")
    context_data = util_load_json("host_history_context_output.json")

    # Setup args and params
    args = {"host_id": "0.0.0.1", "start_time": "2026-02-20T00:00:00.000Z", "end_time": "2026-03-01T12:00:00.000Z"}

    requests_mock.get(
        f"{CENSYS_API_URL}/{ENDPOINTS['HOST_EVENT_HISTORY'].format('0.0.0.1')}",
        [
            {"json": api_responses["page1_response"]},
            {"json": api_responses["page2_response"]},
            {"json": api_responses["page3_response"]},
            {"json": api_responses["page4_response"]},
        ],
    )

    # Execute command
    result = censys_host_history_list_command(client, args)

    # Assertions
    assert result.outputs_prefix == OUTPUT_PREFIX["HOST_EVENT_HISTORY"]
    assert result.outputs_key_field == "ip"
    assert result.outputs == context_data["success_context"]


def test_censys_host_history_list_command_partial_data_api_error(client, requests_mock, mocker):
    """
    Test Case 2: Partial data scenario with 2 API calls where 2nd call fails

    Given:
        - Valid host_id, start_time, and end_time arguments
        - First API call succeeds with 2 events
        - Second API call fails with DemistoException
    When:
        - Running censys_host_history_list_command command
    Then:
        - Ensure warning message is returned
        - Ensure partial_data is True
        - Ensure 2 events from first call are returned
        - Ensure warning message contains error details
    """
    # Load test data
    api_responses = util_load_json("host_history_api_response.json")
    context_data = util_load_json("host_history_context_output.json")
    with open("test_data/host_history_partial_data_hr.md") as f:
        hr_output = f.read()

    # Setup args and params
    args = {"host_id": "0.0.0.1", "start_time": "2026-02-20T00:00:00.000Z", "end_time": "2026-03-01T12:00:00.000Z"}

    # Mock return_warning to capture warning messages
    warning_messages = []
    mocker.patch("CensysV2.return_warning", side_effect=lambda msg: warning_messages.append(msg))

    # Mock API calls - first succeeds, second fails
    requests_mock.get(
        f"{CENSYS_API_URL}/{ENDPOINTS['HOST_EVENT_HISTORY'].format('0.0.0.1')}",
        [
            {"json": api_responses["page1_response"]},  # Returns 2 events
            {"status_code": 500, "json": {"error": "Internal Server Error"}},  # Fails
        ],
    )

    # Execute command
    result = censys_host_history_list_command(client, args)

    # Assertions
    assert result.outputs_prefix == OUTPUT_PREFIX["HOST_EVENT_HISTORY"]
    assert result.outputs_key_field == "ip"
    assert result.outputs == context_data["partial_data_scenario_context"]
    assert result.readable_output == hr_output

    # Verify warning was called
    assert len(warning_messages) == 1
    assert "WARNING: Partial data collected (2 event(s))" in warning_messages[0]
    assert "Pagination stopped at page 2" in warning_messages[0]


def test_censys_host_history_list_command_timeout_scenario(client, requests_mock, mocker):
    """
    Test Case 3: Timeout scenario after 2 API calls

    Given:
        - Valid host_id, start_time, and end_time arguments
        - has_passed_time_threshold returns True after 2 successful API calls
    When:
        - Running censys_host_history_list_command command
    Then:
        - Ensure warning message about timeout is returned
        - Ensure partial_data is True
        - Ensure events from first 2 calls are returned
        - Ensure warning message contains timeout information and platform link
    """
    # Load test data
    api_responses = util_load_json("host_history_api_response.json")
    context_data = util_load_json("host_history_context_output.json")
    with open("test_data/host_history_timeout_hr.md") as f:
        hr_output = f.read()

    # Setup args and params
    args = {"host_id": "0.0.0.1", "start_time": "2026-02-20T00:00:00.000Z", "end_time": "2026-03-01T12:00:00.000Z"}

    # Mock return_warning to capture warning messages
    warning_messages = []
    mocker.patch("CensysV2.return_warning", side_effect=lambda msg: warning_messages.append(msg))

    # Mock has_passed_time_threshold to return False first 2 times, then True
    call_count = {"count": 0}

    def mock_has_passed_time_threshold(start_time, threshold):
        call_count["count"] += 1
        return call_count["count"] > 2  # Return True after 2 calls

    mocker.patch("CensysV2.has_passed_time_threshold", side_effect=mock_has_passed_time_threshold)

    # Mock API calls - both succeed
    requests_mock.get(
        f"{CENSYS_API_URL}/{ENDPOINTS['HOST_EVENT_HISTORY'].format('0.0.0.1')}",
        [
            {"json": api_responses["page1_response"]},  # Returns 2 events
            {"json": api_responses["page2_response"]},  # Returns 2 events
        ],
    )

    # Execute command
    result = censys_host_history_list_command(client, args)

    # Assertions
    assert result.outputs_prefix == OUTPUT_PREFIX["HOST_EVENT_HISTORY"]
    assert result.outputs_key_field == "ip"
    assert result.outputs == context_data["timeout_scenario_context"]
    assert result.readable_output == hr_output

    # Verify warning was called with timeout message
    assert len(warning_messages) == 1
    assert "Results limited due to command execution time constraint (4 minutes)" in warning_messages[0]
    assert "https://platform.censys.io/hosts/0.0.0.1/events" in warning_messages[0]


def test_censys_host_history_list_command_no_events_found(client, requests_mock):
    """
    Test Case 5: No events found scenario

    Given:
        - Valid host_id, start_time, and end_time arguments
        - API returns empty events list
    When:
        - Running censys_host_history_list_command command
    Then:
        - Ensure appropriate message is returned
        - Ensure no context data is created
    """
    # Load test data
    api_responses = util_load_json("host_history_api_response.json")

    # Setup args and params
    args = {"host_id": "0.0.0.1", "start_time": "2026-02-20T00:00:00.000Z", "end_time": "2026-03-01T12:00:00.000Z"}

    # Mock API call with empty response
    requests_mock.get(
        f"{CENSYS_API_URL}/{ENDPOINTS['HOST_EVENT_HISTORY'].format('0.0.0.1')}", json=api_responses["empty_response"]
    )

    # Execute command
    result = censys_host_history_list_command(client, args)

    # Assertions
    assert "No historical data found for host 0.0.0.1" in result.readable_output
    assert result.outputs is None


def test_censys_host_history_list_command_error_in_first_call(client, requests_mock):
    """
    Test Case 6: Error in first API call scenario

    Given:
        - Valid host_id, start_time, and end_time arguments
        - API returns error in first call (500 Internal Server Error)
    When:
        - Running censys_host_history_list_command command
    Then:
        - Ensure exception is raised
        - Ensure no partial data warning is issued since no events were collected
    """

    # Setup args and params
    args = {"host_id": "0.0.0.1", "start_time": "2026-02-20T00:00:00.000Z", "end_time": "2026-03-01T12:00:00.000Z"}

    # Mock API call with error response
    requests_mock.get(
        f"{CENSYS_API_URL}/{ENDPOINTS['HOST_EVENT_HISTORY'].format('0.0.0.1')}",
        status_code=500,
        json={"error": "Internal Server Error"},
    )

    # Execute command and expect DemistoException to be raised
    with pytest.raises(DemistoException) as exc_info:
        censys_host_history_list_command(client, args)

    # Verify the exception contains error information
    assert "500" in str(exc_info.value) or "Internal Server Error" in str(exc_info.value)


@pytest.mark.parametrize(
    "args,expected_error",
    [
        # Missing host_id
        (
            {"start_time": "2026-02-20T00:00:00.000Z", "end_time": "2026-03-01T12:00:00.000Z"},
            ERRORS["REQUIRED_ARGUMENT"].format("host_id"),
        ),
        # Missing start_time
        (
            {"host_id": "0.0.0.1", "end_time": "2026-03-01T12:00:00.000Z"},
            ERRORS["REQUIRED_ARGUMENT"].format("start_time"),
        ),
        # Missing end_time
        (
            {"host_id": "0.0.0.1", "start_time": "2026-02-20T00:00:00.000Z"},
            ERRORS["REQUIRED_ARGUMENT"].format("end_time"),
        ),
        # Invalid IP address
        (
            {"host_id": "invalid_ip", "start_time": "2026-02-20T00:00:00.000Z", "end_time": "2026-03-01T12:00:00.000Z"},
            ERRORS["INVALID_IP"].format("invalid_ip"),
        ),
        # Invalid time range (start_time after end_time)
        (
            {"host_id": "0.0.0.1", "start_time": "2026-03-01T12:00:00.000Z", "end_time": "2026-02-20T00:00:00.000Z"},
            ERRORS["INVALID_TIME_RANGE"].format("start_time", "2026-03-01T12:00:00.000Z", "end_time", "2026-02-20T00:00:00.000Z"),
        ),
    ],
)
def test_censys_host_history_list_command_invalid_arguments(client, args, expected_error):
    """
    Test Case 4: Invalid arguments scenarios

    Given:
        - Various invalid argument combinations
    When:
        - Running censys_host_history_list_command command
    Then:
        - Ensure ValueError is raised with appropriate error message
    """

    with pytest.raises(ValueError) as err:
        censys_host_history_list_command(client, args)

    assert expected_error in str(err.value)


def test_censys_rescan_command_initiate(client, requests_mock):
    """
    Test Case 1: Initiate the rescan

    Given:
        - Valid arguments for initiating a rescan (Service type)
        - polling=False (initial request)
    When:
        - Running censys_rescan_command
    """
    args = {
        "ioc_type": "Service",
        "ioc_value": "0.0.0.1",
        "port": "443",
        "protocol": "HTTP",
        "transport_protocol": "tcp",
        "polling": False,
    }
    api_responses = util_load_json("rescan_api_response.json")
    context_data = util_load_json("rescan_context_output.json")
    with open("test_data/rescan_initiate_hr.md") as f:
        hr_output = f.read()

    requests_mock.post(f"{CENSYS_API_URL}/{ENDPOINTS['INITIATE_RESCAN']}", json=api_responses["rescan_initiate"])

    result = censys_rescan_command(client, args)

    assert result.outputs_prefix == OUTPUT_PREFIX["INITIATE_RESCAN"]
    assert result.outputs == context_data["rescan_initiate"]
    assert result.readable_output == hr_output


def test_censys_rescan_command_initiate_no_scan_id_returned(client, requests_mock):
    """
    Test Case 1b: Initiate the rescan - No scan ID returned

    Given:
        - Valid arguments for initiating a rescan (Service type)
        - polling=False (initial request)
        - API returns response without scan_id
    When:
        - Running censys_rescan_command
    Then:
        - Ensure the command handles the missing scan_id gracefully
        - Ensure status is set to 'failed' and is_completed is True
    """
    args = {
        "ioc_type": "Service",
        "ioc_value": "0.0.0.1",
        "port": "443",
        "protocol": "HTTP",
        "transport_protocol": "tcp",
        "polling": False,
    }
    api_responses = util_load_json("rescan_api_response.json")
    context_data = util_load_json("rescan_context_output.json")

    requests_mock.post(f"{CENSYS_API_URL}/{ENDPOINTS['INITIATE_RESCAN']}", json=api_responses["rescan_initiate_no_scan_id"])

    result = censys_rescan_command(client, args)

    assert result.outputs_prefix == OUTPUT_PREFIX["INITIATE_RESCAN"]
    assert result.outputs == context_data["rescan_initiate_no_scan_id"]


def test_censys_rescan_command_status_in_progress(client, requests_mock):
    """
    Test Case 2: Check the rescan status - In progress

    Given:
        - A scan_id from a previously initiated rescan
        - polling=True
        - Scan status is 'scanning' (in progress)
    When:
        - Running censys_rescan_command with polling
    """
    scan_id = "00000000-0000-0000-0000-000000000001"
    args = {
        "ioc_type": "Service",
        "ioc_value": "0.0.0.1",
        "port": "443",
        "protocol": "HTTP",
        "scan_id": scan_id,
        "polling": True,
    }
    api_responses = util_load_json("rescan_api_response.json")
    context_data = util_load_json("rescan_context_output.json")
    with open("test_data/rescan_status_in_progress_hr.md") as f:
        hr_output = f.read()

    requests_mock.get(
        f"{CENSYS_API_URL}/{ENDPOINTS['RESCAN_STATUS'].format(scan_id)}", json=api_responses["scan_status_in_progress"]
    )

    result = censys_rescan_command(client, args)

    assert result.outputs_prefix == OUTPUT_PREFIX["INITIATE_RESCAN"]
    assert result.outputs == context_data["scan_status_in_progress"]
    assert result.readable_output == hr_output


def test_censys_rescan_command_status_failed(client, requests_mock):
    """
    Test Case 3: Check the rescan status - Failed

    Given:
        - A scan_id from a previously initiated rescan
        - polling=True
        - Scan status is 'failed'
    When:
        - Running censys_rescan_command with polling
    """
    scan_id = "00000000-0000-0000-0000-000000000001"
    args = {
        "ioc_type": "Service",
        "ioc_value": "0.0.0.1",
        "port": "443",
        "protocol": "HTTP",
        "scan_id": scan_id,
        "polling": True,
    }
    api_responses = util_load_json("rescan_api_response.json")
    context_data = util_load_json("rescan_context_output.json")
    with open("test_data/rescan_status_failed_hr.md") as f:
        hr_output = f.read()

    requests_mock.get(f"{CENSYS_API_URL}/{ENDPOINTS['RESCAN_STATUS'].format(scan_id)}", json=api_responses["scan_status_failed"])

    result = censys_rescan_command(client, args)

    assert result.outputs_prefix == OUTPUT_PREFIX["INITIATE_RESCAN"]
    assert result.outputs == context_data["scan_status_failed"]
    assert result.readable_output == hr_output


def test_censys_rescan_command_complete_service_type(client, requests_mock):
    """
    Test Case 4: Rescan status complete for Service (IP)

    Given:
        - A scan_id from a previously initiated rescan
        - polling=True
        - Scan status is 'completed'
        - ioc_type='Service'
    When:
        - Running censys_rescan_command with polling
    """
    scan_id = "00000000-0000-0000-0000-000000000001"
    args = {
        "ioc_type": "Service",
        "ioc_value": "0.0.0.1",
        "port": "443",
        "protocol": "HTTP",
        "scan_id": scan_id,
        "polling": True,
    }
    api_responses = util_load_json("rescan_api_response.json")
    context_data = util_load_json("rescan_context_output.json")
    with open("test_data/rescan_status_completed_service_hr.md") as f:
        hr_output = f.read()

    requests_mock.get(
        f"{CENSYS_API_URL}/{ENDPOINTS['RESCAN_STATUS'].format(scan_id)}", json=api_responses["scan_status_completed"]
    )
    requests_mock.get(f"{CENSYS_API_URL}/v3/global/asset/host/0.0.0.1", json=api_responses["ip_enrichment_data"])

    result = censys_rescan_command(client, args)

    assert result.outputs_prefix == OUTPUT_PREFIX["INITIATE_RESCAN"]
    assert result.outputs == context_data["scan_status_completed_service"]
    assert result.readable_output == hr_output


def test_censys_rescan_command_complete_web_property_type(client, requests_mock):
    """
    Test Case 5: Rescan status complete for Web Property

    Given:
        - A scan_id from a previously initiated rescan
        - polling=True
        - Scan status is 'completed'
        - ioc_type='Web Property'
    When:
        - Running censys_rescan_command with polling
    """
    scan_id = "00000000-0000-0000-0000-000000000001"
    args = {
        "ioc_type": "Web Property",
        "ioc_value": "example.com",
        "port": "443",
        "scan_id": scan_id,
        "polling": True,
    }
    api_responses = util_load_json("rescan_api_response.json")
    context_data = util_load_json("rescan_context_output.json")
    with open("test_data/rescan_status_completed_web_property_hr.md") as f:
        hr_output = f.read()

    requests_mock.get(
        f"{CENSYS_API_URL}/{ENDPOINTS['RESCAN_STATUS'].format(scan_id)}", json=api_responses["scan_status_completed"]
    )
    requests_mock.get(
        f"{CENSYS_API_URL}/v3/global/asset/webproperty/example.com:443", json=api_responses["web_property_enrichment_data"]
    )

    result = censys_rescan_command(client, args)

    assert result.outputs_prefix == OUTPUT_PREFIX["INITIATE_RESCAN"]
    assert result.outputs == context_data["scan_status_completed_web_property"]
    assert result.readable_output == hr_output


@pytest.mark.parametrize(
    "args,expected_error",
    [
        (
            {"ioc_type": " ", "port": "443", "protocol": "HTTP"},
            ERRORS["REQUIRED_ARGUMENT"].format("ioc_type"),
        ),
        (
            {"ioc_type": "Service", "port": "443", "protocol": "HTTP"},
            ERRORS["REQUIRED_ARGUMENT"].format("ioc_value"),
        ),
        (
            {"ioc_type": "Service", "ioc_value": "0.0.0.1", "port": "", "protocol": "HTTP"},
            ERRORS["REQUIRED_ARGUMENT"].format("port"),
        ),
        (
            {"ioc_type": "Service", "ioc_value": "0.0.0.1", "port": "443"},
            "Protocol is required when IOC Type is Service.",
        ),
        (
            {"ioc_type": "InvalidType", "ioc_value": "0.0.0.1", "port": "443", "protocol": "HTTP"},
            ERRORS["INVALID_SELECT"].format("InvalidType", "ioc_type", "Service, Web Property"),
        ),
        (
            {"ioc_type": "Service", "ioc_value": "invalid_ip", "port": "443", "protocol": "HTTP"},
            ERRORS["INVALID_IP"].format("invalid_ip"),
        ),
        (
            {"ioc_type": "Service", "ioc_value": "0.0.0.1", "port": "70000", "protocol": "HTTP"},
            ERRORS["INVALID_PORT"].format(70000, 1, 65535),
        ),
        (
            {"ioc_type": "Service", "ioc_value": "0.0.0.1", "port": "-1", "protocol": "HTTP"},
            ERRORS["INVALID_PORT"].format(-1, 1, 65535),
        ),
        (
            {"ioc_type": "Service", "ioc_value": "0.0.0.1", "transport_protocol": "invalid_protocol", "protocol": "HTTP"},
            ERRORS["INVALID_SELECT"].format(
                "invalid_protocol", "transport_protocol", ", ".join(VALID_TRANSPORT_PROTOCOL.values())
            ),
        ),
    ],
)
def test_censys_rescan_invalid_arguments(client, args, expected_error):
    """
    Test Case 6: Invalid arguments

    Given:
        - Various invalid argument combinations
    When:
        - Running censys_rescan_command
    Then:
        - Ensure ValueError is raised with appropriate error message
    """
    with pytest.raises(ValueError) as err:
        censys_rescan_command(client, args)

    assert expected_error in str(err.value)


def test_run_polling_command_completed_scan(client, requests_mock):
    """
    Test run_polling_command when scan is completed

    Given:
        - A completed scan result from censys_rescan_command
    When:
        - Running run_polling_command
    Then:
        - Ensure it returns the result directly without scheduling
    """
    args = {
        "ioc_type": "Service",
        "ioc_value": "0.0.0.1",
        "port": "443",
        "protocol": "HTTP",
        "scan_id": "00000000-0000-0000-0000-000000000001",
        "polling": True,
    }
    api_responses = util_load_json("rescan_api_response.json")

    # Mock the status check and enrichment endpoints
    scan_id = "00000000-0000-0000-0000-000000000001"
    requests_mock.get(
        f"{CENSYS_API_URL}/{ENDPOINTS['RESCAN_STATUS'].format(scan_id)}", json=api_responses["scan_status_completed"]
    )
    requests_mock.get(f"{CENSYS_API_URL}/v3/global/asset/host/0.0.0.1", json=api_responses["ip_enrichment_data"])

    result = run_polling_command(client, args, "cen-rescan", censys_rescan_command)

    # Should return single CommandResults, not a list
    assert not isinstance(result, list)
    assert result.outputs.get("is_completed") is True
    assert result.outputs.get("status") == "completed"


def test_run_polling_command_initiate_scan(client, requests_mock):
    """
    Test run_polling_command when initiating a new scan

    Given:
        - Arguments to initiate a new scan (polling=False)
    When:
        - Running run_polling_command
    Then:
        - Ensure it returns a list with result and ScheduledCommand for polling
    """
    args = {
        "ioc_type": "Service",
        "ioc_value": "0.0.0.1",
        "port": "443",
        "protocol": "HTTP",
        "transport_protocol": "tcp",
        "polling": False,
    }
    api_responses = util_load_json("rescan_api_response.json")

    # Mock the initiate rescan endpoint
    requests_mock.post(f"{CENSYS_API_URL}/{ENDPOINTS['INITIATE_RESCAN']}", json=api_responses["rescan_initiate"])

    result = run_polling_command(client, args, "cen-rescan", censys_rescan_command)

    # Should return list with result and scheduled command
    assert isinstance(result, list)
    assert len(result) == 2
    assert result[0].outputs.get("is_completed") is False
    assert result[0].outputs.get("status") == "initiated"
    assert result[0].outputs.get("scan_id") == "00000000-0000-0000-0000-000000000001"
    assert result[1].scheduled_command is not None


def test_censys_related_infra_command_initiate_host(client, requests_mock):
    """
    Test Case : Initiate a related infrastructure job for Host type

    Given:
        - Valid arguments for initiating a job (Host type)
    When:
        - Running censys_related_infrastructure_list_command
    Then:
        - Ensure the command returns the correct outputs and HR
    """
    args = {"ioc_type": "Host", "ioc_value": "0.0.0.1"}
    api_responses = util_load_json("related_infra_api_response.json")
    context_data = util_load_json("related_infra_context_output.json")
    with open("test_data/related_infra_initiate_host_hr.md") as f:
        hr_output = f.read()

    requests_mock.post(f"{CENSYS_API_URL}/{ENDPOINTS['INITIATE_JOB']}", json=api_responses["host_initiate"])

    result = censys_related_infrastructure_list_command(client, args)

    assert result.outputs_prefix == OUTPUT_PREFIX["RELATED_INFRASTRUCTURE"]
    assert result.outputs == context_data["host_initiate"]
    assert result.readable_output == hr_output


def test_censys_related_infra_command_initiate_web_property(client, requests_mock):
    """
    Test Case : Initiate a related infrastructure job for Web Property type

    Given:
        - Valid arguments for initiating a job (Web Property type)
    When:
        - Running censys_related_infrastructure_list_command
    Then:
        - Ensure the command returns the correct outputs and HR
    """
    args = {"ioc_type": "Web Property", "ioc_value": "example.com:443"}
    api_responses = util_load_json("related_infra_api_response.json")
    context_data = util_load_json("related_infra_context_output.json")
    with open("test_data/related_infra_initiate_web_property_hr.md") as f:
        hr_output = f.read()

    requests_mock.post(f"{CENSYS_API_URL}/{ENDPOINTS['INITIATE_JOB']}", json=api_responses["web_property_initiate"])

    result = censys_related_infrastructure_list_command(client, args)

    assert result.outputs_prefix == OUTPUT_PREFIX["RELATED_INFRASTRUCTURE"]
    assert result.outputs == context_data["web_property_initiate"]
    assert result.readable_output == hr_output


def test_censys_related_infra_command_initiate_certificate(client, requests_mock):
    """
    Test Case : Initiate a related infrastructure job for Certificate type

    Given:
        - Valid arguments for initiating a job (Certificate type)
    When:
        - Running censys_related_infrastructure_list_command
    Then:
        - Ensure the command returns the correct outputs and HR
    """
    args = {"ioc_type": "Certificate", "ioc_value": "0000000000000000000000000000000000000000000000000000000000000001"}
    api_responses = util_load_json("related_infra_api_response.json")
    context_data = util_load_json("related_infra_context_output.json")
    with open("test_data/related_infra_initiate_certificate_hr.md") as f:
        hr_output = f.read()

    requests_mock.post(f"{CENSYS_API_URL}/{ENDPOINTS['INITIATE_JOB']}", json=api_responses["certificate_initiate"])

    result = censys_related_infrastructure_list_command(client, args)

    assert result.outputs_prefix == OUTPUT_PREFIX["RELATED_INFRASTRUCTURE"]
    assert result.outputs == context_data["certificate_initiate"]
    assert result.readable_output == hr_output


def test_censys_related_infra_command_initiate_no_job_id_returned(client, requests_mock):
    """
    Test Case : Initiate a related infrastructure job - No job ID returned

    Given:
        - Valid arguments for initiating a job (Host type)
        - API returns response without job_id
    When:
        - Running censys_related_infrastructure_list_command
    Then:
        - Ensure the command handles the missing job_id gracefully
        - Ensure status is set to 'failed' and is_completed is True
    """
    args = {"ioc_type": "Host", "ioc_value": "0.0.0.1"}
    api_responses = util_load_json("related_infra_api_response.json")
    context_data = util_load_json("related_infra_context_output.json")

    requests_mock.post(f"{CENSYS_API_URL}/{ENDPOINTS['INITIATE_JOB']}", json=api_responses["host_initiate_no_job_id"])

    result = censys_related_infrastructure_list_command(client, args)

    assert result.outputs_prefix == OUTPUT_PREFIX["RELATED_INFRASTRUCTURE"]
    assert result.outputs == context_data["host_initiate_no_job_id"]


def test_censys_related_infra_command_status_in_progress(client, requests_mock):
    """
    Test Case : Check the job status - In progress

    Given:
        - A job_id from a previously initiated job
        - polling=True
        - Job state is 'started' (in progress)
    When:
        - Running censys_related_infrastructure_list_command with polling
    Then:
        - Ensure the command returns in_progress status
    """
    job_id = "00000000-0000-0000-0000-000000000001"
    args = {"ioc_type": "Host", "ioc_value": "0.0.0.1", "job_id": job_id, "polling": True}
    api_responses = util_load_json("related_infra_api_response.json")
    context_data = util_load_json("related_infra_context_output.json")
    with open("test_data/related_infra_status_in_progress_hr.md") as f:
        hr_output = f.read()

    requests_mock.get(f"{CENSYS_API_URL}/{ENDPOINTS['JOB_STATUS'].format(job_id)}", json=api_responses["job_status_in_progress"])

    result = censys_related_infrastructure_list_command(client, args)

    assert result.outputs_prefix == OUTPUT_PREFIX["RELATED_INFRASTRUCTURE"]
    assert result.outputs == context_data["job_status_in_progress"]
    assert result.readable_output == hr_output


def test_censys_related_infra_command_status_failed(client, requests_mock):
    """
    Test Case: Check the job status - Failed

    Given:
        - A job_id from a previously initiated job
        - polling=True
        - Job state is 'failed' (in progress)
    When:
        - Running censys_related_infrastructure_list_command with polling
    Then:
        - Ensure the command returns in_progress status
    """
    job_id = "00000000-0000-0000-0000-000000000001"
    args = {"ioc_type": "Host", "ioc_value": "0.0.0.1", "job_id": job_id, "polling": True}
    api_responses = util_load_json("related_infra_api_response.json")
    context_data = util_load_json("related_infra_context_output.json")
    with open("test_data/related_infra_status_failed_hr.md") as f:
        hr_output = f.read()

    requests_mock.get(f"{CENSYS_API_URL}/{ENDPOINTS['JOB_STATUS'].format(job_id)}", json=api_responses["job_status_failed"])

    result = censys_related_infrastructure_list_command(client, args)

    assert result.outputs_prefix == OUTPUT_PREFIX["RELATED_INFRASTRUCTURE"]
    assert result.outputs == context_data["job_status_failed"]
    assert result.readable_output == hr_output


def test_censys_related_infra_command_completed_host(client, requests_mock):
    """
    Test Case : Job completed for Host type

    Given:
        - A job_id from a previously initiated job
        - polling=True
        - Job state is 'completed'
    When:
        - Running censys_related_infrastructure_list_command with polling
    Then:
        - Ensure the command returns completed status with pivot data
    """
    job_id = "00000000-0000-0000-0000-000000000001"
    args = {"ioc_type": "Host", "ioc_value": "0.0.0.1", "job_id": job_id, "polling": True}
    api_responses = util_load_json("related_infra_api_response.json")
    context_data = util_load_json("related_infra_context_output.json")
    with open("test_data/related_infra_completed_host_hr.md") as f:
        hr_output = f.read()

    requests_mock.get(f"{CENSYS_API_URL}/{ENDPOINTS['JOB_STATUS'].format(job_id)}", json=api_responses["job_status_completed"])
    requests_mock.get(f"{CENSYS_API_URL}/{ENDPOINTS['JOB_RESULTS'].format(job_id)}", json=api_responses["host_job_results"])

    result = censys_related_infrastructure_list_command(client, args)

    assert result.outputs_prefix == OUTPUT_PREFIX["RELATED_INFRASTRUCTURE"]
    assert result.outputs == context_data["host_job_completed"]
    assert result.readable_output == hr_output


def test_censys_related_infra_command_completed_no_pivot_data(client, requests_mock):
    """
    Test Case : Job completed but no pivot data found

    Given:
        - A job_id from a previously initiated job
        - polling=True
        - Job state is 'completed'
        - Job results contain empty pivot data
    When:
        - Running censys_related_infrastructure_list_command with polling
    Then:
        - Ensure the command returns completed status with empty pivot_data
        - Ensure HR contains "No pivot data found" message
    """
    job_id = "00000000-0000-0000-0000-000000000001"
    args = {
        "ioc_type": "Host",
        "ioc_value": "0.0.0.1",
        "job_id": job_id,
        "polling": True,
    }
    api_responses = util_load_json("related_infra_api_response.json")
    context_data = util_load_json("related_infra_context_output.json")
    with open("test_data/related_infra_completed_no_pivot_data_hr.md") as f:
        hr_output = f.read()

    requests_mock.get(f"{CENSYS_API_URL}/{ENDPOINTS['JOB_STATUS'].format(job_id)}", json=api_responses["job_status_completed"])
    requests_mock.get(f"{CENSYS_API_URL}/{ENDPOINTS['JOB_RESULTS'].format(job_id)}", json=api_responses["host_job_results_empty"])

    result = censys_related_infrastructure_list_command(client, args)

    assert result.outputs_prefix == OUTPUT_PREFIX["RELATED_INFRASTRUCTURE"]
    assert result.outputs == context_data["host_job_completed_no_pivot_data"]
    assert result.readable_output == hr_output
    assert "No pivot data found" in result.readable_output


@pytest.mark.parametrize(
    "args,expected_error",
    [
        (
            {"ioc_type": " ", "ioc_value": "0.0.0.1"},
            ERRORS["REQUIRED_ARGUMENT"].format("ioc_type"),
        ),
        (
            {"ioc_type": "Host"},
            ERRORS["REQUIRED_ARGUMENT"].format("ioc_value"),
        ),
        (
            {"ioc_type": "InvalidType", "ioc_value": "0.0.0.1"},
            ERRORS["INVALID_SELECT"].format("InvalidType", "ioc_type", ", ".join(VALID_RELATED_INFRA_IOC_TYPE.values())),
        ),
        (
            {"ioc_type": "Host", "ioc_value": "invalid_ip"},
            ERRORS["INVALID_IP"].format("invalid_ip"),
        ),
        (
            {"ioc_type": "Web Property", "ioc_value": "example.com"},
            "For Web Property IOC type, ioc_value must include port in the format hostname:port",
        ),
        (
            {"ioc_type": "Web Property", "ioc_value": "example.com:70000"},
            ERRORS["INVALID_PORT"].format(70000, 1, 65535),
        ),
        (
            {"ioc_type": "Web Property", "ioc_value": "example.com:-1"},
            ERRORS["INVALID_PORT"].format(-1, 1, 65535),
        ),
    ],
)
def test_censys_related_infra_invalid_arguments(client, args, expected_error):
    """
    Test Case : Invalid arguments

    Given:
        - Various invalid argument combinations
    When:
        - Running censys_related_infrastructure_list_command
    Then:
        - Ensure ValueError is raised with appropriate error message
    """
    with pytest.raises(ValueError) as err:
        censys_related_infrastructure_list_command(client, args)

    assert expected_error in str(err.value)


def test_run_polling_command_completed_related_infra_job(client, requests_mock):
    """
    Test run_polling_command when related infrastructure job is completed

    Given:
        - A completed job result from censys_related_infrastructure_list_command
    When:
        - Running run_polling_command
    Then:
        - Ensure it returns the result directly without scheduling
    """
    job_id = "00000000-0000-0000-0000-000000000001"
    args = {"ioc_type": "Host", "ioc_value": "0.0.0.1", "job_id": job_id, "polling": True}
    api_responses = util_load_json("related_infra_api_response.json")

    requests_mock.get(f"{CENSYS_API_URL}/{ENDPOINTS['JOB_STATUS'].format(job_id)}", json=api_responses["job_status_completed"])
    requests_mock.get(f"{CENSYS_API_URL}/{ENDPOINTS['JOB_RESULTS'].format(job_id)}", json=api_responses["host_job_results"])

    result = run_polling_command(client, args, "cen-related-infrastructure-list", censys_related_infrastructure_list_command)

    # Should return single CommandResults, not a list
    assert not isinstance(result, list)
    assert result.outputs.get("is_completed") is True
    assert result.outputs.get("status") == "completed"


def test_run_polling_command_initiate_related_infra_job(client, requests_mock):
    """
    Test run_polling_command when initiating a new related infrastructure job

    Given:
        - Arguments to initiate a new job (polling=False)
    When:
        - Running run_polling_command
    Then:
        - Ensure it returns a list with result and ScheduledCommand for polling
    """
    args = {"ioc_type": "Host", "ioc_value": "0.0.0.1", "polling": False}
    api_responses = util_load_json("related_infra_api_response.json")

    requests_mock.post(f"{CENSYS_API_URL}/{ENDPOINTS['INITIATE_JOB']}", json=api_responses["host_initiate"])

    result = run_polling_command(client, args, "cen-related-infrastructure-list", censys_related_infrastructure_list_command)

    # Should return list with result and scheduled command
    assert isinstance(result, list)
    assert len(result) == 2
    assert result[0].outputs.get("is_completed") is False
    assert result[0].outputs.get("status") == "initiated"
    assert result[0].outputs.get("job_id") == "00000000-0000-0000-0000-000000000001"
    assert result[1].scheduled_command is not None