-
Notifications
You must be signed in to change notification settings - Fork 1
OpenGraph Plugins
danti1988 edited this page May 15, 2026
·
4 revisions
OpenGraph checks usually need two pieces:
- A datasource gate in
datasources/<name>.py. - One or more checks that declare
requires=["<name>"].
The gate keeps ordinary AD audits quiet when the plugin data is not present.
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 Falsefrom 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")
}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, orGroupnodes. - 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.