Catch the security bugs that live between your microservices.
Snyk scans one repo. Semgrep scans one file. CrossGraph builds one call graph across every service you own, propagates taint across HTTP / gRPC / shared-DB boundaries, and uses your OpenTelemetry traces to keep false positives below 5 %.
Seven things happen on every pull request.
CrossGraph is the GitHub App that does one job — it catches a finding that would have only shown up in production, and it does it before the PR merges.
Walk the repos.
Every package.json or pyproject.toml becomes a service. Every openapi.yaml, .proto, and source file maps to an edge candidate.
Find the taint.
Tree-sitter extractors on TypeScript + Python surface sources (req.body, env vars,request.form) and sinks (SQL interpolation, exec, egress, file writes, logs).
Build the call graph.
OpenAPI endpoints + .proto methods + inferred client calls become directed edges between services. Shared Postgres tables become FK + shared-state edges.
Pair it with reality.
Edges with 0 production calls in 24 h drop to 20 % confidence. Cold edges (1-9) to 70 %. Hot edges at full. This is the patent-distinguishing element — and why the PR check doesn't spam.
Propagate across services.
BFS from every labeled source, across every edge, until it hits a sink. Cross-service paths only — intra-service work belongs in Semgrep.
Report only net-new.
Base-branch findings don't spam the PR. Findings the PR removed get celebrated. The check reports only what this change introduced.
What the developer sees.
One Check Run summary + one inline PR comment per net-new finding, anchored to the sink line. Path shown, runtime evidence attached, suggested fix specific.
🔴 CrossGraph — 1 new cross-service vulnerability (blocking) CG-001 — cross-service SQL injection (critical) checkout-api/src/routes/checkout.ts:47 passes req.body.coupon_code (user-input, unsanitized) via HTTP POST /orders to orders-writer. The receiving handler in orders-writer/app/orders.py:112 interpolates it directly into a SQL query. Cross-service path (3 hops): 1. checkout-api src/routes/checkout.ts:47 → source: user-input 2. orders-writer HTTP POST /orders → edge 3. orders-writer app/orders.py:112 → sink: SQL Runtime evidence: 1,247 production calls in the last 24h. Confidence: 92 %. Suggested fix: parameterized query at orders-writer/app/orders.py:112.
Built for teams that already moved past single-repo scanners.
| Cross-service vulnerability | Single-repo scanner? | CrossGraph? |
|---|---|---|
| SQL injection across an internal HTTP hop | ✗ | ✓ CG-001 |
| Command execution from a shared queue payload | ✗ | ✓ CG-002 |
| SSRF via an internal proxy service | ✗ | ✓ CG-003 |
| PII logged on a downstream service | ✗ | ✓ CG-004 |
| Secret exfiltrated through an outbound egress | ✗ | ✓ CG-005 |
| Shadow API edges (in runtime but not in OpenAPI) | ✗ | ✓ CG-050 |
Get early access.
We're onboarding 3-5 design partners in Q2 2026. Series B-D startups running Node and Python microservices at 20-150 service count, already paying Snyk or Semgrep — but still shipping cross-service bugs to production.