If you believe you have found a security vulnerability in OpenGraphDB, please report it privately. Do not open a public GitHub issue.
Private channels:
- Preferred: open a GitHub Security Advisory. This gives a private workspace to coordinate a fix + disclosure. The repo's Private vulnerability reporting setting must be enabled on github.com for this URL to render the report form — verify the link returns a 200 (not a 404) before relying on it. The release runbook checks this.
- Fallback: email
security@opengraphdb.dev(or, until that alias is provisioned, the maintainer atashesh.goplani96@gmail.com) with the subject prefix[opengraphdb-security]. The fallback address goes to one human's inbox, so response time may be longer than the GHSA path; if you have a critical or actively-exploited issue, please use both channels.
- A description of the vulnerability + the impact.
- Steps to reproduce (a minimal
.cypherquery, sample input, or test case). - The OpenGraphDB version (
ogdb --version) and platform. - Whether you believe the issue is exploitable remotely or requires local access.
- Acknowledgement within 72 hours.
- Triage within 7 days — we will tell you whether we accept the report and the severity we assign.
- Fix timeline depends on severity:
- Critical (remote code exec, data corruption): patch within 14 days.
- High (auth bypass, integrity loss): patch within 30 days.
- Medium / Low: patch in the next minor release.
- Disclosure: coordinated. We will credit you in the release notes unless you prefer to remain anonymous.
We patch security issues in the latest minor release only. Users on older versions should upgrade.
| Version | Supported |
|---|---|
| 0.6.x | ✅ |
| < 0.6.0 | ❌ |
- Vulnerabilities in dependencies that have already been patched upstream and where we are tracking the upgrade.
- Issues that require physical access to the server.
- Self-XSS in user-supplied query results that the user themselves rendered with
dangerouslySetInnerHTMLafter copying out of the playground.
OpenGraphDB ships as an embedded, single-process database (the SQLite model): by default the trust boundary is "whoever can reach the loopback socket / open the file," i.e. the OS user. For that use case the defaults are safe. The guidance below is for the networked / shared / multi-user deployment, where you must turn auth on and put the process behind TLS.
There is no in-process TLS today (see the roadmap note below). HTTP, Bolt, and gRPC
are cleartext sockets. The supported way to get transport encryption is to bind the
server to 127.0.0.1 (the default for every protocol) and terminate TLS at a reverse
proxy on the same host.
- All protocols default to
127.0.0.1. Exposing a server on all interfaces is an explicit opt-in (--bind 0.0.0.0:<port>), and OpenGraphDB prints a loud warning when you do, because that puts a cleartext, potentially unauthenticated graph DB on the LAN. - Keep
ogdbon loopback and let the proxy be the only thing listening externally.
nginx (/etc/nginx/conf.d/ogdb.conf):
server {
listen 443 ssl;
server_name ogdb.example.com;
ssl_certificate /etc/letsencrypt/live/ogdb.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/ogdb.example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
location / {
proxy_pass http://127.0.0.1:8080; # ogdb serve --http (loopback)
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# SSE: /query/trace streams — disable response buffering so events flush.
proxy_buffering off;
proxy_read_timeout 1h;
}
}Caddy (Caddyfile) — automatic Let's Encrypt certificates:
ogdb.example.com {
reverse_proxy 127.0.0.1:8080 {
flush_interval -1 # stream Server-Sent Events (/query/trace) without buffering
}
}Traefik (dynamic config, file provider) — automatic ACME certs configured in your
static config (certificatesResolvers.le):
# /etc/traefik/dynamic/ogdb.yml
http:
routers:
ogdb:
rule: "Host(`ogdb.example.com`)"
entryPoints: [websecure]
service: ogdb
tls:
certResolver: le
services:
ogdb:
loadBalancer:
# Traefik streams SSE (/query/trace) without buffering by default.
servers:
- url: "http://127.0.0.1:8080" # ogdb serve --http (loopback)Start the backend on loopback:
ogdb serve --http --bind 127.0.0.1:8080 --require-auth /path/to/graph.ogdbBolt over TLS (
bolt+s://): terminate with an L4 TLS proxy (nginxstream {}, HAProxy, or stunnel) in front ofogdb serve --bolt --bind 127.0.0.1:7687. The Bolt wire protocol is not HTTP, so use a TCP/streamproxy, not an HTTPlocationblock.
The token + role engine is dormant until the first user exists. Bootstrap it, then serve fail-closed:
# Create the first user with a bearer token and an admin role.
ogdb user add admin --token "$(openssl rand -hex 32)" --role admin --db /path/to/graph.ogdb
ogdb user list --db /path/to/graph.ogdb # never prints token values
# Serve fail-closed: every data route (reads + writes) needs a valid bearer, and the
# server refuses to start until a user exists. Also honored via OGDB_REQUIRE_AUTH=1.
ogdb serve --http --bind 127.0.0.1:8080 --require-auth /path/to/graph.ogdb--require-auth(envOGDB_REQUIRE_AUTH=1): fail closed. Anonymous requests get401;/healthstays open for liveness probes.--require-auth-reads(envOGDB_REQUIRE_AUTH_READS=1): keep writes/exports gated as usual but also require a bearer for reads (/query,/schema,/metrics) once users exist. Use this when you want the open browser playground gone but don't need the full fail-closed posture.- Clients authenticate with
Authorization: Bearer <token>.
Roles: admin, read_write, read_only (default for a new user). Grant/revoke with
ogdb user grant <name> <role> / ogdb user revoke <name> <role>.
In-process TLS (rustls) is not implemented and is intentionally deferred. The HTTP,
Bolt, and MCP servers each manage raw TcpStreams with hand-rolled framing (including an
SSE streaming path), so adding TLS cleanly means threading a rustls config, PEM cert
loading/reload UX, SNI/ALPN, and handshake-error handling through three transports plus a
new test surface — a cross-cutting feature, not a small patch. Terminating TLS at a
reverse proxy (above) gives the same transport security today with zero code risk, so
that is the supported path. Native TLS will be revisited when there is a concrete
requirement a proxy cannot satisfy.