MISP/misp-guard

misp-guard is a mitmproxy addon that inspects and blocks outgoing events to external MISP instances via sync mechanisms (pull/push/feed fetch) based on a set of customizable block rules.

23

stars

94

commits

Python

primary language

Sep 1, 2026

updated

www.misp-project.org/2022/09/13/misp-guard.html/
air-gapped
misp
misp-api
misp-guard

README

misp-guard is a mitmproxy addon designed to apply configurable filters that prevent the unintentional leakage of sensitive threat intelligence data while facilitating controlled information sharing.

misp-guard functions as a proxy specifically designed to interact with and understand the MISP synchronization protocol. It monitors communications between MISP instances, allowing for real-time inspection and enforcement of security policies. MISP Guard effectively blocks incoming or outgoing data that matches configured filtering rules, ensuring sensitive or restricted information is not unintentionally shared.

NOTE: By default this addon will block all outgoing HTTP requests that are not required during a MISP server sync. However, individual URLs or domains can be allowed if necessary.

Objectives

To prevent data leakage in high-security environments such as military networks or critical infrastructure systems, misp-guard plays a crucial role by acting as a configurable enforcement layer during MISP instance synchronization. Its fine-grained filtering capabilities allow organizations to maintain strict control over what information is shared, ensuring compliance with compartmentalization policies and mitigating the risk of accidental data exposure.

Supported block rules:

  • compartments_rules: Compartments can be interpreted as a VLAN where one or more MISP are living, each compartment defines to which other compartments allows to sync.
  • taxonomies_rules:
    • required_taxonomies: Taxonomies that have to be present in a event, otherwise it will be blocked.
    • allowed_tags: For each of the required_taxonomies a subset of allowed tags can be specified.
    • blocked_tags: Tags that cannot be present in any of the event entities.
  • blocked_distribution_levels: Blocks if the event/objects/attributes matches one of the blocked distribution levels.
    • "0": Organisation Only
    • "1": Community Only
    • "2": Connected Communities
    • "3": All Communities
    • "4": Sharing Group
    • "5": Inherit Event
  • blocked_sharing_groups_uuids: Blocks if the event/objects/attributes matches one of the blocked sharing groups uuids.
  • blocked_attribute_types: Blocks if the event contains an attribute matching one of this types.
  • blocked_attribute_categories: Blocks if the event contains an attribute matching one of this categories.
  • blocked_object_types: Blocks if the event contains an object matching one of this types.

Allowlist

  • To allow individual URLs or domains, simply add them as a JSON array under the allowlist element.
    • urls The entire URL is checked and only exact calls are allowed.
    • domains In contrast, only the domain is checked and any website behind the domain can be queried. Should only be used if adding exact URLs is not possible.

Feeds

  • Remote feeds can be configured under the top level feeds element, see the Feeds section below.

Instance settings

  • allow_sync_auth_key_refresh: If set to true, [POST]/users/resetauthkey/me requests to this instance are allowed, so the sync user authentication key can be refreshed. Defaults to false, meaning these requests are blocked as any other non sync related endpoint. Note that this setting is evaluated on the destination instance, the one owning the authentication key being refreshed.

See sample config here.

Evaluation

misp-guard has been evaluated at Evaluation Assurance Level 2 (EAL 2) under the Common Criteria framework, covering its filtering capabilities, logging mechanisms, configuration options and integration with MISP instances.

The report documents the target of evaluation, the security target, the functional specification of every supported filtering rule, the high level design, the test plan and results, and the vulnerability assessment conducted on the addon.

PUSH

sequenceDiagram
    participant MISP A 
    participant MISP Guard
    participant MISP B

    rect rgb(191, 223, 255)
    note right of MISP A: PUSH Events 

    MISP B->>MISP Guard: [GET]/servers/getVersion
    MISP Guard->>MISP A: [GET]/servers/getVersion
    MISP A->>MISP Guard: [GET]/servers/getVersion
    MISP Guard->>MISP B: [GET]/servers/getVersion
    
    MISP B->>MISP Guard: [HEAD]/events/view/[UUID]
    note right of MISP Guard: Only `minimal` search requests to /events/index are allowed
    MISP Guard->>MISP A: [HEAD]/events/view/[UUID]
    MISP A->>MISP Guard: [HEAD]/events/view/[UUID]
    MISP Guard->>MISP B: [HEAD]/events/view/[UUID]
    
    rect rgb(191, 223, 255)
    note left of MISP Guard: 404: If the event does not exists in MISP A
    MISP B->>+MISP Guard: [POST]/events/add
    note right of MISP Guard: Outgoing Event is inspected and rejected with 403 if any block rule matches
    MISP Guard->>-MISP A: [POST]/events/add
    MISP A->>MISP Guard: [POST]/events/add
    MISP Guard->>MISP B: [POST]/events/add
    end

    rect rgb(191, 223, 255)
    note left of MISP Guard: 200: If the event already exists in MISP A
    MISP B->>+MISP Guard: [POST]/events/edit/[UUID]
    note right of MISP Guard: Outgoing Event is inspected and rejected with 403 if any block rule matches
    MISP Guard->>-MISP A: [POST]/events/edit/[UUID]
    MISP A->>MISP Guard: [POST]/events/edit/[UUID]
    MISP Guard->>MISP B: [POST]/events/edit/[UUID]
    end
    end 

    rect rgb(191, 223, 255)
    note right of MISP A: PUSH GalaxyClusters
    MISP B->>+MISP Guard: [POST]/galaxies/pushCluster
    note right of MISP Guard: Outgoing Galaxy Cluster is inspected and rejected with 403 if any block rule matches
    MISP Guard->>-MISP A: [POST]/galaxies/pushCluster
    MISP A->>MISP Guard: [POST]/galaxies/pushCluster
    MISP Guard->>MISP B: [POST]/galaxies/pushCluster
    end

    rect rgb(191, 223, 255)
    note right of MISP A: PUSH Sightings
    MISP B->>+MISP Guard: [POST]/sightings/bulkSaveSightings/[UUID]
    note right of MISP Guard: Outgoing Sightings are inspected and rejected with 403 if any block rule matches
    MISP Guard->>-MISP A: [POST]/sightings/bulkSaveSightings/[UUID]
    MISP A->>MISP Guard: [POST]/sightings/bulkSaveSightings/[UUID]
    MISP Guard->>MISP B: [POST]/sightings/bulkSaveSightings/[UUID]
    end
    
    rect rgb(191, 223, 255)
    note right of MISP A: PUSH AnalystData
    MISP B->>+MISP Guard: [POST]/analyst_data/filterAnalystDataForPush
    MISP A->>MISP Guard: [POST]/analyst_data/filterAnalystDataForPush
    MISP Guard->>MISP B: [POST]/analyst_data/filterAnalystDataForPush

    MISP B->>+MISP Guard: [POST]/analyst_data/pushAnalystData
    note right of MISP Guard: Outgoing Analyst Data is inspected and rejected with 403 if any block rule matches
    MISP Guard->>-MISP A: [POST]/analyst_data/pushAnalystData
    MISP A->>MISP Guard: [POST]/analyst_data/pushAnalystData
    MISP Guard->>MISP B: [POST]/analyst_data/pushAnalystData
    end

PULL

sequenceDiagram
    participant MISP A
    participant MISP Guard
    participant MISP B

    rect rgb(191, 223, 255)
    note right of MISP A: PULL Events 
    MISP A->>MISP Guard: [GET]/servers/getVersion
    MISP Guard->>MISP B: [GET]/servers/getVersion
    MISP B->>MISP Guard: [GET]/servers/getVersion
    MISP Guard->>MISP A: [GET]/servers/getVersion

    MISP A->>+MISP Guard: [POST]/events/index
    note right of MISP Guard: Only `minimal` search requests to /events/index are allowed
    MISP Guard->>-MISP B: [POST]/events/index
    MISP B->>MISP Guard: [POST]/events/index
    MISP Guard->>MISP A: [POST]/events/index

    MISP A->>MISP Guard: [GET]/events/view/[UUID]
    MISP Guard->>MISP B: [GET]/events/view/[UUID]
    MISP B->>+MISP Guard: [GET]/events/view/[UUID]
    note right of MISP Guard: Incoming Event is inspected and rejected with 403 if any block rule matches
    MISP Guard->>-MISP A: [GET]/events/view/[UUID]

    MISP A->>MISP Guard: [GET]/users/view/me.json
    MISP Guard->>MISP B: [GET]/users/view/me.json
    MISP B->>MISP Guard: [GET]/users/view/me.json
    MISP Guard->>MISP A: [GET]/users/view/me.json
    end

    rect rgb(191, 223, 255)
    note right of MISP A: PULL ShadowAttributes 
    MISP A->>MISP Guard: [GET]/shadow_attributes/index
    MISP Guard->>MISP B: [GET]/shadow_attributes/index
    MISP B->>+MISP Guard: [GET]/shadow_attributes/index
    note right of MISP Guard: Incoming Shadow Attributes are inspected and rejected with 403 if any block rule matches
    MISP Guard->>-MISP A: [GET]/shadow_attributes/index
    end

    rect rgb(191, 223, 255)
    note right of MISP A: GalaxyClusters 
    MISP A->>+MISP Guard: [POST]/galaxy_clusters/restSearch
    note right of MISP Guard: Only `minimal` search requests to /galaxy_clusters/restSearch are allowed
    MISP Guard->>-MISP B: [POST]/galaxy_clusters/restSearch
    MISP B->>MISP Guard: [POST]/galaxy_clusters/restSearch
    MISP Guard->>MISP A: [POST]/galaxy_clusters/restSearch

    MISP A->>MISP Guard: [GET]/galaxy_clusters/view/[UUID]
    MISP Guard->>MISP B: [GET]/galaxy_clusters/view/[UUID]
    MISP B->>+MISP Guard: [GET]/galaxy_clusters/view/[UUID]
    note right of MISP Guard: Incoming Galaxy Cluster is inspected and rejected with 403 if any block rule matches
    MISP Guard->>-MISP A: [GET]/galaxy_clusters/view/[UUID]

    MISP A->>MISP Guard: [GET]/users/view/me.json
    MISP Guard->>MISP B: [GET]/users/view/me.json
    MISP B->>MISP Guard: [GET]/users/view/me.json
    MISP Guard->>MISP A: [GET]/users/view/me.json
    end

    rect rgb(191, 223, 255)
    note right of MISP A: PULL Sightings 
    MISP A->>MISP Guard: [POST]/sightings/restSearch/event
    MISP Guard->>MISP B: [POST]/sightings/restSearch/event
    MISP B->>+MISP Guard: [POST]/sightings/restSearch/event
    note right of MISP Guard: Incoming Sightings are inspected and rejected with 403 if any block rule matches
    MISP Guard->>-MISP A: [POST]/sightings/restSearch/event
    end
    
    rect rgb(191, 223, 255)
    note right of MISP A: PULL AnalystData 
    MISP A->>MISP Guard: [POST]/analyst_data/indexMinimal
    MISP Guard->>MISP B: [POST]/analyst_data/indexMinimal
    MISP B->>+MISP Guard: [POST]/analyst_data/indexMinimal
    MISP Guard->>-MISP A: [POST]/analyst_data/indexMinimal

    MISP A->>MISP Guard: [GET]/analyst_data/index/[Note|Opinion|Relationship]/uuid:[UUID].json
    MISP Guard->>MISP B: [GET]/analyst_data/index/[Note|Opinion|Relationship]/uuid:[UUID].json
    MISP B->>+MISP Guard: [GET]/analyst_data/index/[Note|Opinion|Relationship]/uuid:[UUID].json
    note right of MISP Guard: Incoming Analyst Data is inspected and rejected with 403 if any block rule matches
    MISP Guard->>-MISP A: [GET]/analyst_data/index/[Note|Opinion|Relationship]/uuid:[UUID].json

    MISP A->>MISP Guard: [GET]/users/view/me.json
    MISP Guard->>MISP B: [GET]/users/view/me.json
    MISP B->>MISP Guard: [GET]/users/view/me.json
    MISP Guard->>MISP A: [GET]/users/view/me.json
    end

NOTE: The MISP A server needs to have the misp-guard hostname configured as the server hostname you are going to pull from, not the MISP B hostname.

Feeds

Remote feeds are configured under the top level feeds element, each feed defines its own set of block rules, using the same rules as the instances:

"feeds": {
    "feed_osint": {
        "type": "misp",
        "url": "https://www.circl.lu/doc/misp/feed-osint",
        "allow_caching": false,
        "taxonomies_rules": {
            "required_taxonomies": [],
            "allowed_tags": {},
            "blocked_tags": [
                "tlp:red"
            ]
        },
        "blocked_distribution_levels": [],
        "blocked_sharing_groups_uuids": [],
        "blocked_attribute_types": [],
        "blocked_attribute_categories": [],
        "blocked_object_types": []
    }
}
  • type: Feed format, only misp format feeds are supported for now.
  • url: Base url of the feed, the directory holding the manifest.json file.
  • allow_caching: If set to true, [GET]<FEED_URL>/hashes.csv requests are allowed, so MISP can fill its feed cache used for the feed correlation lookups. Defaults to false.

Only the [GET]<FEED_URL>/manifest.json, [GET]<FEED_URL>/[UUID].json and [GET]<FEED_URL>/[UUID].asc endpoints of a configured feed are allowed, plus [GET]<FEED_URL>/hashes.csv if allow_caching is enabled. Any other request to the feed host is rejected as any other non sync related request. Only the configured instances can fetch a feed.

The [UUID].asc signature of a protected event is passed through, it holds no event data and the event it signs is either passed through untouched or rejected as a whole, so the signature validation done by MISP is not affected.

NOTE: The feed cache (hashes.csv) only holds the md5 hashes of the attribute values and the uuid of the event they belong to, there are no tags, types, categories or distribution levels to match the block rules against, so its content is passed through as is. An event that the block rules would reject can still contribute its value hashes to the cache, which is why fetching it has to be explicitly enabled per feed.

sequenceDiagram
    participant MISP A
    participant MISP Guard
    participant Feed

    rect rgb(191, 223, 255)
    note right of MISP A: FETCH Feed

    MISP A->>MISP Guard: [GET]/manifest.json
    MISP Guard->>Feed: [GET]/manifest.json
    Feed->>+MISP Guard: [GET]/manifest.json
    note right of MISP Guard: The event metadata of the manifest is inspected and the events matching a block rule are removed from it
    MISP Guard->>-MISP A: [GET]/manifest.json

    MISP A->>MISP Guard: [GET]/[UUID].json
    MISP Guard->>Feed: [GET]/[UUID].json
    Feed->>+MISP Guard: [GET]/[UUID].json
    note right of MISP Guard: The incoming event is inspected and rejected with 403 if any block rule matches
    MISP Guard->>-MISP A: [GET]/[UUID].json

    rect rgb(191, 223, 255)
    note left of MISP Guard: Only for protected events
    MISP A->>MISP Guard: [GET]/[UUID].asc
    MISP Guard->>Feed: [GET]/[UUID].asc
    Feed->>MISP Guard: [GET]/[UUID].asc
    MISP Guard->>MISP A: [GET]/[UUID].asc
    end
    end

    rect rgb(191, 223, 255)
    note right of MISP A: CACHE Feed

    MISP A->>+MISP Guard: [GET]/hashes.csv
    note right of MISP Guard: Rejected with 403 unless the feed has `allow_caching` enabled, the feed cache content can not be filtered
    MISP Guard->>-Feed: [GET]/hashes.csv
    Feed->>MISP Guard: [GET]/hashes.csv
    MISP Guard->>MISP A: [GET]/hashes.csv
    end

The rules are checked in two stages:

  1. Manifest: the manifest.json document holds the metadata (tags, ...) of every event of the feed, the events matching a block rule are removed from the manifest so they are never fetched. The manifest metadata only carries the event tags, so in practice only the taxonomies_rules apply at this stage.
  2. Event: each [UUID].json event is inspected with the full set of block rules, the same way as an event pulled from another instance, and is rejected with a 403 if any rule matches.

NOTE: Feed events do not carry a distribution level nor a sharing group, those rules only apply to the entities of the event that do define them.

Instructions

Requirements

  • Python 3.12 or newer.
  • venv (recommended).

Installation

$ git clone https://github.com/MISP/misp-guard.git
$ cd src/
$ apt install python3.12-venv
$ python3.12 -m venv .venv
$ source .venv/bin/activate
$ pip3 install -r requirements.txt

Setup

  1. Define your block rules in the config.json file.

  2. Start mitmproxy with the mispguard addon:

    $ mitmdump -s mispguard.py -p 8888 --certs *=cert.pem --set config=config.json
    Loading script mispguard.py
    MispGuard initialized
    Proxy server listening at *:8888
    

    Add -k to accept self-signed certificates.

  3. Configure the proxy in your MISP instance, set the following MISP Proxy.host and Proxy.port settings accordingly.

Done, outgoing MISP sync requests will be inspected and dropped according to the specified block rules.

NOTE: add -v to mitmdump to increase verbosity and display debug logs.

Testing

$ pip install pytest pytest-asyncio
$ src src/
$ pytest

Docker

You can also run misp-guard using the misp-docker/misp-guard.

You need to mount a valid config.json, use the misp-docker sample config.json file as the misp-guard container relies on the a hardcoded instance named misp_container to replace the IP provided.

Example:

docker run --name misp-guard \
  -e MISP_IP=172.19.0.7 \
  -e GUARD_PORT=8888 \
  -e GUARD_ARGS="--ssl-insecure -v" \
  -p 8888:8888 \
  -v /home/user/misp-guard/src/config.json:/config.json:ro \
  ghcr.io/misp/misp-docker/misp-guard:latest

Environment variables:

  • MISP_IP: The IP address of MISP instance that will be placed behind the misp-guard proxy.
  • GUARD_PORT: Port mitmproxy will be running, has to match Proxy.port MISP Setting.
  • GUARD_ARGS: Additional arguments to be sent to the mitmproxy utility.

Contributors

righel

90 commits

sva-mk

3 commits

Wachizungu

1 commits

MISP/misp-guard

misp-guard is a mitmproxy addon that inspects and blocks outgoing events to external MISP instances via sync mechanisms (pull/push/feed fetch) based on a set of customizable block rules.

23

stars

94

commits

Python

primary language

Sep 1, 2026

updated

www.misp-project.org/2022/09/13/misp-guard.html/
air-gapped
misp
misp-api
misp-guard

README

misp-guard is a mitmproxy addon designed to apply configurable filters that prevent the unintentional leakage of sensitive threat intelligence data while facilitating controlled information sharing.

misp-guard functions as a proxy specifically designed to interact with and understand the MISP synchronization protocol. It monitors communications between MISP instances, allowing for real-time inspection and enforcement of security policies. MISP Guard effectively blocks incoming or outgoing data that matches configured filtering rules, ensuring sensitive or restricted information is not unintentionally shared.

NOTE: By default this addon will block all outgoing HTTP requests that are not required during a MISP server sync. However, individual URLs or domains can be allowed if necessary.

Objectives

To prevent data leakage in high-security environments such as military networks or critical infrastructure systems, misp-guard plays a crucial role by acting as a configurable enforcement layer during MISP instance synchronization. Its fine-grained filtering capabilities allow organizations to maintain strict control over what information is shared, ensuring compliance with compartmentalization policies and mitigating the risk of accidental data exposure.

Supported block rules:

  • compartments_rules: Compartments can be interpreted as a VLAN where one or more MISP are living, each compartment defines to which other compartments allows to sync.
  • taxonomies_rules:
    • required_taxonomies: Taxonomies that have to be present in a event, otherwise it will be blocked.
    • allowed_tags: For each of the required_taxonomies a subset of allowed tags can be specified.
    • blocked_tags: Tags that cannot be present in any of the event entities.
  • blocked_distribution_levels: Blocks if the event/objects/attributes matches one of the blocked distribution levels.
    • "0": Organisation Only
    • "1": Community Only
    • "2": Connected Communities
    • "3": All Communities
    • "4": Sharing Group
    • "5": Inherit Event
  • blocked_sharing_groups_uuids: Blocks if the event/objects/attributes matches one of the blocked sharing groups uuids.
  • blocked_attribute_types: Blocks if the event contains an attribute matching one of this types.
  • blocked_attribute_categories: Blocks if the event contains an attribute matching one of this categories.
  • blocked_object_types: Blocks if the event contains an object matching one of this types.

Allowlist

  • To allow individual URLs or domains, simply add them as a JSON array under the allowlist element.
    • urls The entire URL is checked and only exact calls are allowed.
    • domains In contrast, only the domain is checked and any website behind the domain can be queried. Should only be used if adding exact URLs is not possible.

Feeds

  • Remote feeds can be configured under the top level feeds element, see the Feeds section below.

Instance settings

  • allow_sync_auth_key_refresh: If set to true, [POST]/users/resetauthkey/me requests to this instance are allowed, so the sync user authentication key can be refreshed. Defaults to false, meaning these requests are blocked as any other non sync related endpoint. Note that this setting is evaluated on the destination instance, the one owning the authentication key being refreshed.

See sample config here.

Evaluation

misp-guard has been evaluated at Evaluation Assurance Level 2 (EAL 2) under the Common Criteria framework, covering its filtering capabilities, logging mechanisms, configuration options and integration with MISP instances.

The report documents the target of evaluation, the security target, the functional specification of every supported filtering rule, the high level design, the test plan and results, and the vulnerability assessment conducted on the addon.

PUSH

sequenceDiagram
    participant MISP A 
    participant MISP Guard
    participant MISP B

    rect rgb(191, 223, 255)
    note right of MISP A: PUSH Events 

    MISP B->>MISP Guard: [GET]/servers/getVersion
    MISP Guard->>MISP A: [GET]/servers/getVersion
    MISP A->>MISP Guard: [GET]/servers/getVersion
    MISP Guard->>MISP B: [GET]/servers/getVersion
    
    MISP B->>MISP Guard: [HEAD]/events/view/[UUID]
    note right of MISP Guard: Only `minimal` search requests to /events/index are allowed
    MISP Guard->>MISP A: [HEAD]/events/view/[UUID]
    MISP A->>MISP Guard: [HEAD]/events/view/[UUID]
    MISP Guard->>MISP B: [HEAD]/events/view/[UUID]
    
    rect rgb(191, 223, 255)
    note left of MISP Guard: 404: If the event does not exists in MISP A
    MISP B->>+MISP Guard: [POST]/events/add
    note right of MISP Guard: Outgoing Event is inspected and rejected with 403 if any block rule matches
    MISP Guard->>-MISP A: [POST]/events/add
    MISP A->>MISP Guard: [POST]/events/add
    MISP Guard->>MISP B: [POST]/events/add
    end

    rect rgb(191, 223, 255)
    note left of MISP Guard: 200: If the event already exists in MISP A
    MISP B->>+MISP Guard: [POST]/events/edit/[UUID]
    note right of MISP Guard: Outgoing Event is inspected and rejected with 403 if any block rule matches
    MISP Guard->>-MISP A: [POST]/events/edit/[UUID]
    MISP A->>MISP Guard: [POST]/events/edit/[UUID]
    MISP Guard->>MISP B: [POST]/events/edit/[UUID]
    end
    end 

    rect rgb(191, 223, 255)
    note right of MISP A: PUSH GalaxyClusters
    MISP B->>+MISP Guard: [POST]/galaxies/pushCluster
    note right of MISP Guard: Outgoing Galaxy Cluster is inspected and rejected with 403 if any block rule matches
    MISP Guard->>-MISP A: [POST]/galaxies/pushCluster
    MISP A->>MISP Guard: [POST]/galaxies/pushCluster
    MISP Guard->>MISP B: [POST]/galaxies/pushCluster
    end

    rect rgb(191, 223, 255)
    note right of MISP A: PUSH Sightings
    MISP B->>+MISP Guard: [POST]/sightings/bulkSaveSightings/[UUID]
    note right of MISP Guard: Outgoing Sightings are inspected and rejected with 403 if any block rule matches
    MISP Guard->>-MISP A: [POST]/sightings/bulkSaveSightings/[UUID]
    MISP A->>MISP Guard: [POST]/sightings/bulkSaveSightings/[UUID]
    MISP Guard->>MISP B: [POST]/sightings/bulkSaveSightings/[UUID]
    end
    
    rect rgb(191, 223, 255)
    note right of MISP A: PUSH AnalystData
    MISP B->>+MISP Guard: [POST]/analyst_data/filterAnalystDataForPush
    MISP A->>MISP Guard: [POST]/analyst_data/filterAnalystDataForPush
    MISP Guard->>MISP B: [POST]/analyst_data/filterAnalystDataForPush

    MISP B->>+MISP Guard: [POST]/analyst_data/pushAnalystData
    note right of MISP Guard: Outgoing Analyst Data is inspected and rejected with 403 if any block rule matches
    MISP Guard->>-MISP A: [POST]/analyst_data/pushAnalystData
    MISP A->>MISP Guard: [POST]/analyst_data/pushAnalystData
    MISP Guard->>MISP B: [POST]/analyst_data/pushAnalystData
    end

PULL

sequenceDiagram
    participant MISP A
    participant MISP Guard
    participant MISP B

    rect rgb(191, 223, 255)
    note right of MISP A: PULL Events 
    MISP A->>MISP Guard: [GET]/servers/getVersion
    MISP Guard->>MISP B: [GET]/servers/getVersion
    MISP B->>MISP Guard: [GET]/servers/getVersion
    MISP Guard->>MISP A: [GET]/servers/getVersion

    MISP A->>+MISP Guard: [POST]/events/index
    note right of MISP Guard: Only `minimal` search requests to /events/index are allowed
    MISP Guard->>-MISP B: [POST]/events/index
    MISP B->>MISP Guard: [POST]/events/index
    MISP Guard->>MISP A: [POST]/events/index

    MISP A->>MISP Guard: [GET]/events/view/[UUID]
    MISP Guard->>MISP B: [GET]/events/view/[UUID]
    MISP B->>+MISP Guard: [GET]/events/view/[UUID]
    note right of MISP Guard: Incoming Event is inspected and rejected with 403 if any block rule matches
    MISP Guard->>-MISP A: [GET]/events/view/[UUID]

    MISP A->>MISP Guard: [GET]/users/view/me.json
    MISP Guard->>MISP B: [GET]/users/view/me.json
    MISP B->>MISP Guard: [GET]/users/view/me.json
    MISP Guard->>MISP A: [GET]/users/view/me.json
    end

    rect rgb(191, 223, 255)
    note right of MISP A: PULL ShadowAttributes 
    MISP A->>MISP Guard: [GET]/shadow_attributes/index
    MISP Guard->>MISP B: [GET]/shadow_attributes/index
    MISP B->>+MISP Guard: [GET]/shadow_attributes/index
    note right of MISP Guard: Incoming Shadow Attributes are inspected and rejected with 403 if any block rule matches
    MISP Guard->>-MISP A: [GET]/shadow_attributes/index
    end

    rect rgb(191, 223, 255)
    note right of MISP A: GalaxyClusters 
    MISP A->>+MISP Guard: [POST]/galaxy_clusters/restSearch
    note right of MISP Guard: Only `minimal` search requests to /galaxy_clusters/restSearch are allowed
    MISP Guard->>-MISP B: [POST]/galaxy_clusters/restSearch
    MISP B->>MISP Guard: [POST]/galaxy_clusters/restSearch
    MISP Guard->>MISP A: [POST]/galaxy_clusters/restSearch

    MISP A->>MISP Guard: [GET]/galaxy_clusters/view/[UUID]
    MISP Guard->>MISP B: [GET]/galaxy_clusters/view/[UUID]
    MISP B->>+MISP Guard: [GET]/galaxy_clusters/view/[UUID]
    note right of MISP Guard: Incoming Galaxy Cluster is inspected and rejected with 403 if any block rule matches
    MISP Guard->>-MISP A: [GET]/galaxy_clusters/view/[UUID]

    MISP A->>MISP Guard: [GET]/users/view/me.json
    MISP Guard->>MISP B: [GET]/users/view/me.json
    MISP B->>MISP Guard: [GET]/users/view/me.json
    MISP Guard->>MISP A: [GET]/users/view/me.json
    end

    rect rgb(191, 223, 255)
    note right of MISP A: PULL Sightings 
    MISP A->>MISP Guard: [POST]/sightings/restSearch/event
    MISP Guard->>MISP B: [POST]/sightings/restSearch/event
    MISP B->>+MISP Guard: [POST]/sightings/restSearch/event
    note right of MISP Guard: Incoming Sightings are inspected and rejected with 403 if any block rule matches
    MISP Guard->>-MISP A: [POST]/sightings/restSearch/event
    end
    
    rect rgb(191, 223, 255)
    note right of MISP A: PULL AnalystData 
    MISP A->>MISP Guard: [POST]/analyst_data/indexMinimal
    MISP Guard->>MISP B: [POST]/analyst_data/indexMinimal
    MISP B->>+MISP Guard: [POST]/analyst_data/indexMinimal
    MISP Guard->>-MISP A: [POST]/analyst_data/indexMinimal

    MISP A->>MISP Guard: [GET]/analyst_data/index/[Note|Opinion|Relationship]/uuid:[UUID].json
    MISP Guard->>MISP B: [GET]/analyst_data/index/[Note|Opinion|Relationship]/uuid:[UUID].json
    MISP B->>+MISP Guard: [GET]/analyst_data/index/[Note|Opinion|Relationship]/uuid:[UUID].json
    note right of MISP Guard: Incoming Analyst Data is inspected and rejected with 403 if any block rule matches
    MISP Guard->>-MISP A: [GET]/analyst_data/index/[Note|Opinion|Relationship]/uuid:[UUID].json

    MISP A->>MISP Guard: [GET]/users/view/me.json
    MISP Guard->>MISP B: [GET]/users/view/me.json
    MISP B->>MISP Guard: [GET]/users/view/me.json
    MISP Guard->>MISP A: [GET]/users/view/me.json
    end

NOTE: The MISP A server needs to have the misp-guard hostname configured as the server hostname you are going to pull from, not the MISP B hostname.

Feeds

Remote feeds are configured under the top level feeds element, each feed defines its own set of block rules, using the same rules as the instances:

"feeds": {
    "feed_osint": {
        "type": "misp",
        "url": "https://www.circl.lu/doc/misp/feed-osint",
        "allow_caching": false,
        "taxonomies_rules": {
            "required_taxonomies": [],
            "allowed_tags": {},
            "blocked_tags": [
                "tlp:red"
            ]
        },
        "blocked_distribution_levels": [],
        "blocked_sharing_groups_uuids": [],
        "blocked_attribute_types": [],
        "blocked_attribute_categories": [],
        "blocked_object_types": []
    }
}
  • type: Feed format, only misp format feeds are supported for now.
  • url: Base url of the feed, the directory holding the manifest.json file.
  • allow_caching: If set to true, [GET]<FEED_URL>/hashes.csv requests are allowed, so MISP can fill its feed cache used for the feed correlation lookups. Defaults to false.

Only the [GET]<FEED_URL>/manifest.json, [GET]<FEED_URL>/[UUID].json and [GET]<FEED_URL>/[UUID].asc endpoints of a configured feed are allowed, plus [GET]<FEED_URL>/hashes.csv if allow_caching is enabled. Any other request to the feed host is rejected as any other non sync related request. Only the configured instances can fetch a feed.

The [UUID].asc signature of a protected event is passed through, it holds no event data and the event it signs is either passed through untouched or rejected as a whole, so the signature validation done by MISP is not affected.

NOTE: The feed cache (hashes.csv) only holds the md5 hashes of the attribute values and the uuid of the event they belong to, there are no tags, types, categories or distribution levels to match the block rules against, so its content is passed through as is. An event that the block rules would reject can still contribute its value hashes to the cache, which is why fetching it has to be explicitly enabled per feed.

sequenceDiagram
    participant MISP A
    participant MISP Guard
    participant Feed

    rect rgb(191, 223, 255)
    note right of MISP A: FETCH Feed

    MISP A->>MISP Guard: [GET]/manifest.json
    MISP Guard->>Feed: [GET]/manifest.json
    Feed->>+MISP Guard: [GET]/manifest.json
    note right of MISP Guard: The event metadata of the manifest is inspected and the events matching a block rule are removed from it
    MISP Guard->>-MISP A: [GET]/manifest.json

    MISP A->>MISP Guard: [GET]/[UUID].json
    MISP Guard->>Feed: [GET]/[UUID].json
    Feed->>+MISP Guard: [GET]/[UUID].json
    note right of MISP Guard: The incoming event is inspected and rejected with 403 if any block rule matches
    MISP Guard->>-MISP A: [GET]/[UUID].json

    rect rgb(191, 223, 255)
    note left of MISP Guard: Only for protected events
    MISP A->>MISP Guard: [GET]/[UUID].asc
    MISP Guard->>Feed: [GET]/[UUID].asc
    Feed->>MISP Guard: [GET]/[UUID].asc
    MISP Guard->>MISP A: [GET]/[UUID].asc
    end
    end

    rect rgb(191, 223, 255)
    note right of MISP A: CACHE Feed

    MISP A->>+MISP Guard: [GET]/hashes.csv
    note right of MISP Guard: Rejected with 403 unless the feed has `allow_caching` enabled, the feed cache content can not be filtered
    MISP Guard->>-Feed: [GET]/hashes.csv
    Feed->>MISP Guard: [GET]/hashes.csv
    MISP Guard->>MISP A: [GET]/hashes.csv
    end

The rules are checked in two stages:

  1. Manifest: the manifest.json document holds the metadata (tags, ...) of every event of the feed, the events matching a block rule are removed from the manifest so they are never fetched. The manifest metadata only carries the event tags, so in practice only the taxonomies_rules apply at this stage.
  2. Event: each [UUID].json event is inspected with the full set of block rules, the same way as an event pulled from another instance, and is rejected with a 403 if any rule matches.

NOTE: Feed events do not carry a distribution level nor a sharing group, those rules only apply to the entities of the event that do define them.

Instructions

Requirements

  • Python 3.12 or newer.
  • venv (recommended).

Installation

$ git clone https://github.com/MISP/misp-guard.git
$ cd src/
$ apt install python3.12-venv
$ python3.12 -m venv .venv
$ source .venv/bin/activate
$ pip3 install -r requirements.txt

Setup

  1. Define your block rules in the config.json file.

  2. Start mitmproxy with the mispguard addon:

    $ mitmdump -s mispguard.py -p 8888 --certs *=cert.pem --set config=config.json
    Loading script mispguard.py
    MispGuard initialized
    Proxy server listening at *:8888
    

    Add -k to accept self-signed certificates.

  3. Configure the proxy in your MISP instance, set the following MISP Proxy.host and Proxy.port settings accordingly.

Done, outgoing MISP sync requests will be inspected and dropped according to the specified block rules.

NOTE: add -v to mitmdump to increase verbosity and display debug logs.

Testing

$ pip install pytest pytest-asyncio
$ src src/
$ pytest

Docker

You can also run misp-guard using the misp-docker/misp-guard.

You need to mount a valid config.json, use the misp-docker sample config.json file as the misp-guard container relies on the a hardcoded instance named misp_container to replace the IP provided.

Example:

docker run --name misp-guard \
  -e MISP_IP=172.19.0.7 \
  -e GUARD_PORT=8888 \
  -e GUARD_ARGS="--ssl-insecure -v" \
  -p 8888:8888 \
  -v /home/user/misp-guard/src/config.json:/config.json:ro \
  ghcr.io/misp/misp-docker/misp-guard:latest

Environment variables:

  • MISP_IP: The IP address of MISP instance that will be placed behind the misp-guard proxy.
  • GUARD_PORT: Port mitmproxy will be running, has to match Proxy.port MISP Setting.
  • GUARD_ARGS: Additional arguments to be sent to the mitmproxy utility.

Contributors

righel

90 commits

sva-mk

3 commits

Wachizungu

1 commits

Languages

Python

100.0%