RelayShield

RelayShield real-time identity-compromise and agent-security threat intelligence. Implements the generic `domain`/`ip`/`email` reputation commands (auto-invoked by existing enrichment playbooks) plus RelayShield-specific commands for MCP server registry risk, certificate expiry, and supply-chain vendor risk. "No known finding" from any command means nothing was flagged in the sources RelayShield actually queried. It is deliberately never mapped to a "Good" DBotScore, since that would claim more certainty than the data supports. See the README's DBotScore section for the exact mapping.

Data Enrichment & Threat Intelligence · RelayShield

Details

IDRelayShield
ProviderRelayShield
CategoryData Enrichment & Threat Intelligence
From Version6.8.0
Docker Imagedemisto/python3:3.12.14.12343672

README

RelayShield real-time identity-compromise and agent-security threat intelligence.

This integration implements the generic domain, ip, and email reputation commands,
which are automatically invoked by any existing enrichment playbook that calls generic
reputation commands, with no playbook changes needed. It adds three RelayShield-specific
commands for MCP server registry risk, certificate expiry, and supply-chain vendor risk.

This integration was integrated and tested with version 1.0 of the RelayShield API.

Configure RelayShield in Cortex

Parameter Description Required
Server URL The RelayShield API base URL. True
API Key The RelayShield API key, sent as the X-RS-API-KEY header. True
Trust any certificate (not secure) Whether to trust any TLS certificate. False
Use system proxy settings Whether to route requests through the system proxy. False
Source Reliability Reliability of the source providing the intelligence data. False

DBotScore mapping

A clean result (“no known finding”) maps to DBotScore Unknown (0), never Good (1).
“No known finding” means nothing was flagged in the sources RelayShield actually queried,
which is not a verified-safe guarantee.

RelayShield verdict DBotScore
CRITICAL 3 (Bad)
HIGH 3 (Bad)
MEDIUM 2 (Suspicious)
LOW 2 (Suspicious)
No known finding 0 (Unknown)

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.

domain


Check a domain for phishing-lookalike/typosquat risk, presence in RelayShield’s criminal IOC corpus, and set a DBotScore.

Base Command

domain

Input

Argument Name Description Required
domain A comma-separated list of domains to check. Required

Context Output

Path Type Description
RelayShield.Domain.queried String The domain queried.
RelayShield.Domain.verdict String The RelayShield verdict (CRITICAL/HIGH/MEDIUM/LOW), absent if no known finding.
RelayShield.Domain.findings Unknown The list of findings, if any.
Domain.Name String The domain name.
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 The reliability of the source providing the intelligence data.

ip


Check an IP address for reputation, malicious/suspicious votes, and set a DBotScore.

Base Command

ip

Input

Argument Name Description Required
ip A comma-separated list of IP addresses to check. Required

Context Output

Path Type Description
RelayShield.IP.queried String The IP address queried.
RelayShield.IP.reputation Number The community reputation score.
RelayShield.IP.malicious_votes Number The malicious vote count.
IP.Address String The IP address.
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 The reliability of the source providing the intelligence data.

email


Check an email address for breach exposure and active stolen-session risk, and set a DBotScore.

Base Command

email

Input

Argument Name Description Required
email A comma-separated list of email addresses to check. Required

Context Output

Path Type Description
RelayShield.Email.queried String The email address queried.
RelayShield.Email.breach_found Boolean Whether the email address appears in a known breach.
RelayShield.Email.breach_sources Unknown The list of breach sources the email address was found in.
RelayShield.Email.session_risk_found Boolean Whether an active stolen session was found.
RelayShield.Email.sessions Unknown The list of stolen sessions found, if any.
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 The reliability of the source providing the intelligence data.

relayshield-mcp-registry-risk


Assess an MCP server URL or package name for typosquat/supply-chain/registry risk before an agent connects to it.

Base Command

relayshield-mcp-registry-risk

Input

Argument Name Description Required
server_url The full URL of the MCP server to check. Provide this or package_name. Optional
package_name The package name of the MCP server if no server_url is available. Optional

Context Output

Path Type Description
RelayShield.MCPRegistryRisk.queried String The server URL or package name queried.
RelayShield.MCPRegistryRisk.verdict String The RelayShield verdict, absent if no known finding.
RelayShield.MCPRegistryRisk.findings Unknown The list of findings, if any.

relayshield-cert-expiry


Check a domain’s TLS certificate expiry risk.

Base Command

relayshield-cert-expiry

Input

Argument Name Description Required
domain The domain to check. Required

Context Output

Path Type Description
RelayShield.CertExpiry.domain String The domain checked.
RelayShield.CertExpiry.days_remaining Number The days until certificate expiry.
RelayShield.CertExpiry.risk_level String The risk level (CRITICAL/HIGH/MEDIUM/LOW).

relayshield-supply-chain


Check up to 10 vendor domains (or emails) for combined breach/infostealer risk.

Base Command

relayshield-supply-chain

Input

Argument Name Description Required
vendor_domains A comma-separated list of up to 10 vendor domains to check. Provide this or vendor_emails. Optional
vendor_emails A comma-separated list of vendor email addresses. The domain portion is extracted automatically. Optional

Context Output

Path Type Description
RelayShield.SupplyChain.domains_checked Number The number of vendor domains checked.
RelayShield.SupplyChain.highest_risk String The highest risk level found across all vendors checked.
RelayShield.SupplyChain.critical_vendors Unknown The list of vendors flagged as critical risk.

Configuration parameters

  • url — Server URL (required)
  • credentials — API Key (required)
  • insecure — Trust any certificate (not secure)
  • proxy — Use system proxy settings
  • integrationReliability — Source Reliability

Commands (6)

  • domain

    Check a domain for phishing-lookalike/typosquat risk, presence in RelayShield's criminal IOC corpus, and set a DBotScore.

  • email

    Check an email address for breach exposure and active stolen-session risk, and set a DBotScore.

  • ip

    Check an IP address for reputation, malicious/suspicious votes, and set a DBotScore.

  • relayshield-cert-expiry

    Check a domain's TLS certificate expiry risk.

  • relayshield-mcp-registry-risk

    Assess an MCP server URL or package name for typosquat/supply-chain/registry risk before an agent connects to it.

  • relayshield-supply-chain

    Check up to 10 vendor domains (or emails) for combined breach/infostealer risk.

from unittest.mock import patch

import pytest

import RelayShield


RELIABILITY = "B - Usually reliable"


def _client():
    return RelayShield.Client(base_url="https://api.relayshield.net", api_key="rs_live_testkey", verify=True, proxy=False)


def test_domain_command_finding():
    client = _client()
    with patch.object(
        client,
        "call",
        return_value={
            "queried": "evil.com",
            "verdict": "CRITICAL",
            "findings": [{"type": "typosquat_suspected"}],
            "checked_at": "2026-07-22T00:00:00Z",
        },
    ):
        results = RelayShield.domain_command(client, {"domain": "evil.com"}, RELIABILITY)
    assert len(results) == 1
    r = results[0]
    assert r.indicator.dbot_score.score == 3
    assert r.indicator.dbot_score.reliability == RELIABILITY
    assert r.indicator.domain == "evil.com"


def test_domain_command_clean_maps_to_unknown_not_good():
    """A clean result must map to DBotScore Unknown (0), never Good (1) --
    "no known finding" is not the same claim as "verified safe"."""
    client = _client()
    with patch.object(client, "call", return_value={"queried": "clean.com", "verdict": None, "findings": []}):
        results = RelayShield.domain_command(client, {"domain": "clean.com"}, RELIABILITY)
    assert results[0].indicator.dbot_score.score == 0


def test_ip_command():
    client = _client()
    with patch.object(
        client,
        "call",
        return_value={
            "queried": "1.2.3.4",
            "reputation": 50,
            "malicious_votes": 2,
            "as_owner": "Evil Corp",
            "country": "US",
        },
    ):
        results = RelayShield.ip_command(client, {"ip": "1.2.3.4"}, RELIABILITY)
    assert results[0].indicator.dbot_score.score == 3
    assert results[0].indicator.asn == "Evil Corp"


def test_email_command_combines_breach_and_session():
    client = _client()
    with patch.object(
        client,
        "call",
        side_effect=[
            {"found": True, "sources": ["breach1"]},
            {"found": True, "sessions": [{"severity": "CRITICAL", "service_category": "email"}]},
        ],
    ):
        results = RelayShield.email_command(client, {"email": "victim@example.com"}, RELIABILITY)
    r = results[0]
    assert r.indicator.dbot_score.score == 3
    assert r.outputs["breach_found"] is True
    assert r.outputs["session_risk_found"] is True


def test_mcp_registry_risk_command_requires_input():
    client = _client()
    try:
        RelayShield.mcp_registry_risk_command(client, {})
        pytest.fail("should have raised")
    except ValueError:
        pass


def test_mcp_registry_risk_command():
    client = _client()
    with patch.object(
        client,
        "call",
        return_value={
            "queried": "https://evil-mcp.test",
            "verdict": "HIGH",
            "findings": [{"type": "typosquat_suspected"}],
        },
    ):
        result = RelayShield.mcp_registry_risk_command(client, {"server_url": "https://evil-mcp.test"})
    # Assert on the structured outputs with an equality check rather than a
    # substring search over the rendered markdown. A `"..." in <url string>`
    # test is what CodeQL flags as incomplete URL substring sanitization, and
    # the exact-match form is a stricter assertion anyway.
    assert result.outputs["queried"] == "https://evil-mcp.test"
    assert result.outputs["verdict"] == "HIGH"


def test_cert_expiry_command():
    client = _client()
    with patch.object(client, "call", return_value={"days_remaining": 3, "risk_level": "CRITICAL"}):
        result = RelayShield.cert_expiry_command(client, {"domain": "example.com"})
    assert result.outputs["days_remaining"] == 3


def test_supply_chain_command_requires_input():
    client = _client()
    try:
        RelayShield.supply_chain_command(client, {})
        pytest.fail("should have raised")
    except ValueError:
        pass


def test_supply_chain_command():
    client = _client()
    with patch.object(
        client,
        "call",
        return_value={
            "domains_checked": 2,
            "highest_risk": "HIGH",
            "critical_vendors": [],
        },
    ):
        result = RelayShield.supply_chain_command(client, {"vendor_domains": ["a.com", "b.com"]})
    assert result.outputs["domains_checked"] == 2


def test_client_call_raises_on_error_envelope():
    client = _client()
    with patch.object(RelayShield.BaseClient, "_http_request", return_value={"ok": False, "error": "bad request"}):
        try:
            client.call("/v1/metered/domain", {"domain": "x.com"})
            pytest.fail("should have raised")
        except RelayShield.DemistoException as e:
            assert "bad request" in str(e)


@pytest.mark.parametrize(
    "params",
    [
        {"credentials": None, "api_key": None},
        {"credentials": {}, "api_key": None},
        {},
    ],
)
def test_main_missing_api_key_does_not_raise_attributeerror(mocker, params):
    """XSOAR stores an unset encrypted parameter as an explicit None, so
    params.get("api_key", {}) returns None rather than the default and chaining
    .get() on it used to raise AttributeError. main() must surface a readable
    configuration error instead."""
    mocker.patch.object(RelayShield.demisto, "params", return_value=params)
    mocker.patch.object(RelayShield.demisto, "args", return_value={})
    mocker.patch.object(RelayShield.demisto, "command", return_value="test-module")
    return_error = mocker.patch.object(RelayShield, "return_error")

    RelayShield.main()

    message = return_error.call_args[0][0]
    assert "AttributeError" not in message
    assert "API Key is required" in message