CTIXDeleteFlaggedIndicators

Deletes indicators ingested from Cyware Intel Exchange (CTIX v3) that are flagged as deprecated, revoked, false positive, reviewed, or whitelisted. All delete flags are disabled by default; the script does nothing until at least one flag is enabled.

python · Cyware Intel Exchange

Details

IDCTIXDeleteFlaggedIndicators
Languagepython
From Version6.10.0
Docker Imagedemisto/python3:3.12.13.10404775

README

Deletes indicators ingested from Cyware Intel Exchange (CTIX v3) that are flagged as deprecated, revoked, false positive, reviewed, or whitelisted.

The script builds a Threat Intel query scoped to indicators from the CTIX v3 integration (sourceBrands:"CTIX v3") with any of the enabled flag fields set, and runs the built-in deleteIndicators command on the matches. All delete flags are disabled by default — the script does nothing until at least one flag is explicitly enabled, so it can never issue an unscoped delete.

It is intended to be run on a schedule via the bundled CTIX - Delete Flagged Indicators job (which triggers the playbook of the same name), but can also be run manually from the War Room or Playground.

Note: this script only deletes indicators whose flag fields are already up to date in the Threat Intel Module — run the CTIX feed fetch first so it can update those fields, then run this script (or the bundled job/playbook) to pick up the changes.

Script Data


Name Description
Script Type python3
Cortex XSOAR Version 6.10.0

Inputs


Argument Name Description
delete_deprecated Whether to delete indicators marked as deprecated in Cyware Intel Exchange (CTIX). Default is false.
delete_revoked Whether to delete indicators revoked by their source in Cyware Intel Exchange (CTIX). Default is false.
delete_false_positive Whether to delete indicators marked as false positive in Cyware Intel Exchange (CTIX). Default is false.
delete_whitelisted Whether to delete indicators allow-listed in Cyware Intel Exchange (CTIX). Default is false.
delete_reviewed Whether to delete indicators that have been reviewed in Cyware Intel Exchange (CTIX). Default is false.
exclude Whether to also add the deleted indicators to the Exclusion List. When false (default), indicators are purely deleted and can be re-created if they reappear un-flagged.
reason The reason recorded for the deletion (and exclusion, if enabled).

Command Example

!CTIXDeleteFlaggedIndicators delete_false_positive=true exclude=true reason="Not malicious and used internally"

Human Readable Output

done

Outputs


There are no outputs for this script.

import demistomock as demisto
import pytest

from CTIXDeleteFlaggedIndicators import build_query, main

SUCCESS_ENTRY = [{"Type": 1, "Contents": "3 indicators deleted", "ContentsFormat": "text", "HumanReadable": None}]
ERROR_ENTRY = [{"Type": 4, "Contents": "deletion failed", "ContentsFormat": "text"}]


class TestBuildQuery:
    def test_no_flags_returns_empty(self):
        assert build_query({}) == ""
        assert build_query({"delete_deprecated": "false", "delete_revoked": "false"}) == ""

    def test_single_flag(self):
        query = build_query({"delete_deprecated": "true"})
        assert query == 'sourceBrands:"CTIX v3" and (ctixisdeprecated:T)'

    def test_multiple_flags_or_combined(self):
        query = build_query(
            {"delete_deprecated": "true", "delete_revoked": "true", "delete_whitelisted": "true", "delete_reviewed": "true"}
        )
        assert query.startswith('sourceBrands:"CTIX v3" and (')
        assert "ctixisdeprecated:T" in query
        assert "ctixisrevoked:T" in query
        assert "ctixiswhitelisted:T" in query
        assert "ctixisreviewed:T" in query
        assert "ctixisfalsepositive" not in query
        assert query.count(" or ") == 3

    def test_all_flags(self):
        query = build_query(
            {
                "delete_deprecated": "true",
                "delete_revoked": "true",
                "delete_false_positive": "true",
                "delete_whitelisted": "true",
                "delete_reviewed": "true",
            }
        )
        for field in ("ctixisdeprecated", "ctixisrevoked", "ctixisfalsepositive", "ctixiswhitelisted", "ctixisreviewed"):
            assert f"{field}:T" in query


class TestMain:
    def test_no_flags_enabled_does_not_delete(self, mocker):
        """With every flag disabled, deleteIndicators must never be called."""
        mocker.patch.object(demisto, "args", return_value={"delete_deprecated": "false"})
        execute_mock = mocker.patch.object(demisto, "executeCommand", return_value=SUCCESS_ENTRY)
        results_mock = mocker.patch.object(demisto, "results")

        main()

        execute_mock.assert_not_called()
        assert "No delete flags enabled" in str(results_mock.call_args[0][0])

    def test_delete_called_with_do_not_whitelist_true_by_default(self, mocker):
        """exclude defaults to false -> pure delete (doNotWhitelist=True)."""
        mocker.patch.object(demisto, "args", return_value={"delete_deprecated": "true"})
        execute_mock = mocker.patch.object(demisto, "executeCommand", return_value=SUCCESS_ENTRY)
        mocker.patch.object(demisto, "results")

        main()

        command, command_args = execute_mock.call_args[0][0], execute_mock.call_args[0][1]
        assert command == "deleteIndicators"
        assert command_args["query"] == 'sourceBrands:"CTIX v3" and (ctixisdeprecated:T)'
        assert command_args["doNotWhitelist"] is True
        assert command_args["reason"] == "Deleted by CTIXDeleteFlaggedIndicators job"

    def test_exclude_true_sets_do_not_whitelist_false(self, mocker):
        mocker.patch.object(
            demisto, "args", return_value={"delete_revoked": "true", "exclude": "true", "reason": "revoked by source"}
        )
        execute_mock = mocker.patch.object(demisto, "executeCommand", return_value=SUCCESS_ENTRY)
        mocker.patch.object(demisto, "results")

        main()

        command_args = execute_mock.call_args[0][1]
        assert command_args["doNotWhitelist"] is False
        assert command_args["reason"] == "revoked by source"

    def test_error_from_delete_calls_return_error(self, mocker):
        mocker.patch.object(demisto, "args", return_value={"delete_deprecated": "true"})
        mocker.patch.object(demisto, "executeCommand", return_value=ERROR_ENTRY)
        mocker.patch.object(demisto, "error")
        error_mock = mocker.patch.object(demisto, "results")

        with pytest.raises(SystemExit):
            main()

        entry = error_mock.call_args[0][0]
        assert entry["Type"] == 4  # entryTypes['error']
        assert "Failed to execute CTIXDeleteFlaggedIndicators" in entry["Contents"]