Skip to content

OpenGraph Plugins

danti1988 edited this page May 15, 2026 · 4 revisions

Working with OpenGraph Plugins

OpenGraph checks usually need two pieces:

  1. A datasource gate in datasources/<name>.py.
  2. One or more checks that declare requires=["<name>"].

The gate keeps ordinary AD audits quiet when the plugin data is not present.

Datasource Gate

from checks.core import DataSource, datasource


@datasource("example_platform")
class ExamplePlatformAvailability(DataSource):

    def available(self):
        rows = self.query(
            "MATCH (n:Example_PluginNode) RETURN count(n) AS c",
            name="example_platform_availability",
        )
        return rows[0]["c"] > 0 if rows else False

Check Using the Gate

from checks.core import Check, check


@check(
    risk="Medium",
    category="Example Platform Exposure",
    entity="computer",
    data=[],
    requires=["example_platform"],
)
class ExamplePlatformExposureCheck(Check):

    def execute(self):
        rows = self.query("""
            MATCH (c:Computer)-[:Example_PluginEdge]->(target)
            RETURN c.objectid AS sid, target.name AS target
        """, name="example_platform_exposure")

        return {
            row["sid"]: self.finding(f"Plugin edge to {row['target']}")
            for row in rows
            if row.get("sid")
        }

Importer Behaviour

ADPathfinder has specific importer handling for MSSQLHound and ConfigManBearPig:

  • Seed data is uploaded before plugin relationship data.
  • ConfigManBearPig SCCM seed data is injected when it is missing.
  • SharpHound-owned AD properties are preserved.
  • Duplicate OpenGraph AD principal stubs are merged back onto the real AD User, Computer, or Group nodes.
  • Older MSSQLHound server nodes are linked back to their host computers when possible.

New OpenGraph plugins are not fully automatic. Include any required seed or type-registration data before relationship data, keep AD principal objectid values SID-based where possible, and avoid overwriting SharpHound AD properties.

If the plugin emits duplicate AD principal nodes, add importer handling or model relationships so traversal starts from the existing AD nodes. Without that, checks may query the right edge type but still miss the path because the collector data sits on a separate stub node.

Clone this wiki locally