Skip to content

Security: ShoaibsProjects/GenID

Security

SECURITY.md

Security Policy

Reporting a Vulnerability

Do not open a public GitHub issue for security vulnerabilities.

Email security reports to the project maintainers. You should receive a response within 48 hours. Confirmed issues receive a patch as soon as possible, coordinated with CVE publication if warranted.

Supported Versions

Version Supported
main branch ✅ Active development / nightly
Tagged releases ✅ Once released

Security Architecture Baseline

GenID implements defense-in-depth across 7 layers. The table below summarizes the audited state of each control (last audit: 2026-07-29).

Layer 1: Authentication & Sessions

Control Status Location
RS256 JWT validation against JWKS endpoint ✅ PASS backend/internal/middleware/jwt_auth.go:89-110
JWT exp claim enforcement (access: 5m, refresh: 30d) ✅ PASS backend/internal/oidc/provider.go:79,149
Refresh token rotation (old revoked before new issued) ✅ PASS backend/internal/oidc/handlers.go:241
Refresh tokens stored as SHA-256 hash (not raw) ✅ PASS backend/internal/oidc/provider.go:303
OAuth2 token revocation endpoint (RFC 7009) ✅ PASS backend/internal/oidc/handlers.go:440-483
Access token jti-based replay detection ⚠️ GAP backend/internal/middleware/jwt_auth.go — jti exists but not checked
Access token revocation blocklist ⚠️ GAP backend/internal/oidc/handlers.go:480 — documented as deferred
DEV_LOGIN_ENABLED defaults to true in dev mode ⚠️ RISK backend/cmd/identity-service/main.go:249

Layer 2: Authorization & Policy

Control Status Location
WorkflowGuard — 12 sensitive operations require master permission ✅ PASS backend/internal/middleware/workflow_permission.go:75-116
X-Master-Key header validation against configured key ✅ PASS backend/internal/middleware/workflow_permission.go:101-103
JWT role-based master check (master/admin/owner roles) ✅ PASS backend/internal/middleware/workflow_permission.go:106-113
Cedar policy engine — forbid always wins over permit ✅ PASS backend/internal/cedar/engine.go
Multi-tenant Row Level Security — 28 tables, app.current_tenant ✅ PASS infrastructure/postgres/init.sql:723-789
API key authentication with runtime key rotation ✅ PASS backend/internal/middleware/auth.go:22-77

Layer 3: Cryptography & Key Management

Control Status Location
AES-256-GCM for vault secrets (crypto/rand nonces) ✅ PASS backend/internal/vault/vault.go:161-198
Vault master key minimum length enforcement (32 chars) ✅ PASS backend/internal/vault/vault.go:44-49
Vault file permissions 0600 ✅ PASS backend/internal/vault/vault.go:80
No hardcoded IVs, seeds, or deterministic nonces ✅ PASS Entire crypto surface
No deprecated algorithms (MD5, SHA1, DES) ✅ PASS Garable audit
JWT signing key regenerated on every restart ⚠️ GAP backend/internal/oidc/provider.go:37 — no key persistence
HMAC secret for CAEP webhooks defaults to genid-dev-secret ⚠️ GAP backend/internal/activities/activities.go:832
JSON output encryption via json.Marshal ✅ PASS backend/internal/vault/vault.go:207-211

Layer 4: Input Validation & Output Safety

Control Status Location
Request body size limits (10 MB default) ✅ PASS backend/internal/middleware/validate.go:9
Content-Type enforcement on POST/PUT/PATCH ✅ PASS backend/internal/middleware/validate.go:39-67
Security headers: X-Content-Type-Options, X-Frame-Options, Referrer-Policy ✅ PASS backend/cmd/identity-service/main.go:885-897
CORS origin validation — exact match, never wildcard ✅ PASS backend/cmd/identity-service/main.go:900-921
Connector config credential sanitizer ✅ PASS backend/internal/service/identity_service.go:1715-1732
No dangerouslySetInnerHTML in frontend ✅ PASS frontend/src/
User input injected into HTML without escaping ⚠️ GAP backend/internal/oidc/handlers.go:77,354

Layer 5: Rate Limiting & DoS Protection

Control Status Location
Per-IP token bucket rate limiter ✅ PASS backend/internal/middleware/rate_limit.go:11-17,72-87
X-Forwarded-For support for proxied deployments ✅ PASS backend/internal/middleware/rate_limit.go:75-77
Cleanup goroutine for stale IPs (10 min interval) ✅ PASS backend/internal/middleware/rate_limit.go:53-70
Retry-After header on 429 responses ✅ PASS backend/internal/middleware/rate_limit.go:80
No panic recovery HTTP middleware ⚠️ GAP backend/cmd/identity-service/main.go

Layer 6: Audit & Integrity

Control Status Location
SHA-256 hash chain (prev_hash → hash) ✅ PASS backend/internal/audit/chain.go:69-82
Genesis hash constant (000...000) ✅ PASS backend/internal/audit/chain.go:18
Mutex serialization prevents chain forks ✅ PASS backend/internal/audit/chain.go:44-45
Verify() endpoint — replays and recomputes entire chain ✅ PASS backend/internal/audit/chain.go:154-207
Backfill for copies rows ✅ PASS backend/internal/audit/chain.go:211-271
Error response bodies captured in audit message (potential token leak) ⚠️ GAP backend/internal/audit/audit.go:203

Layer 8: Dependency Supply Chain

Control Status Location
Go module verification via go.sum ✅ PASS backend/go.sum
npm audit / package-lock.json ✅ PASS frontend/package-lock.json
Pre-commit gitleaks hook ✅ PASS .githooks/pre-commit
Pinned Docker image tags ✅ PASS docker/ Dockerfiles
NATS client 7 versions behind latest ⚠️ RISK backend/go.modnats-io/nats.go v1.52.0
golang.org/x/crypto contains known CVE ⚠️ RISK backend/go.sum — requires update

Layer 9: Infrastructure Hardening

Control Status Location
Identity service runs as non-root user (UID 1001) ✅ PASS docker/identity-service.Dockerfile:30-31
Frontend Dockerfile lacks explicit USER nginx ⚠️ GAP docker/frontend.Dockerfile
Redis exposed without password ⚠️ GAP infrastructure/docker-compose.ymlREDIS_PASSWORD= empty
Internal services bound to 0.0.0.0 in docker-compose ⚠️ GAP infrastructure/docker-compose.yml — many ports: directives
QA deployments enabled by default in compose ⚠️ GAP infrastructure/docker-compose.yml:243

Layer 10: Error Handling & Timing Resistance

Control Status Location
Authentication timing oracle — different messages for different failures ⚠️ GAP backend/internal/oidc/provider.go:453-459
Error messages leak internal detail to clients ⚠️ GAP backend/internal/middleware/jwt_auth.go:101
No panic() in business logic or handlers ✅ PASS All handler files

Layer 11: Redirect URI & OAuth Security

Control Status Location
Redirect URI validation exists ✅ PASS backend/internal/oidc/handlers.go:541
Redirect URI validated via strings.HasPrefix (open redirect risk) ⚠️ HIGH backend/internal/oidc/handlers.go:544
PKCE (S256) enforced for authcode flow ✅ PASS backend/internal/oidc/provider.go:278-299
State parameter present in auth request ✅ PASS backend/internal/oidc/handlers.go:79

Layer 12: IDP & TLS

Control Status Location
LDAP TLS enforcement, InsecureSkipVerify: false ✅ PASS backend/internal/connector/ldap.go:57-58
OTel exporter uses insecure.NewCredentials() always ⚠️ GAP backend/cmd/backend_service/main.go:993-994
HTTP client timeout via http.DefaultClient for JWKS fetch ✅ PASS backend/internal/middleware/jwt_auth.go:231

Immediate Hardening Priority Queue

CRITICAL — Fix Today

  1. Rotate credentials — Remove POSTGRES_PASSWORD, NEO4J_AUTH, API_KEYS, MASTER_KEY from infrastructure/docker-compose.yml. Move to .env.
  2. Fix redirect URI validation — Replace strings.HasPrefix with exact URL component match in backend/internal/oidc/handlers.go:544
  3. Escape user input in HTML — Use html.EscapeString() or html/template in backend/internal/oidc/handlers.go:77,354

HIGH — Fix This Week

  1. Implement JWT jti replay protection — Check jti against Redis blocklist in backend/internal/middleware/jwt_auth.go:132
  2. Persist JWT signing key — Write key to file on first start, load on subsequent starts backend/internal/oidc/provider.go:37
  3. Remove HMAC default secret — Return error if CAEP_HMAC_SECRET is not set backend/internal/activities/activities.go:832
  4. Add production gate — Exit with fatal on startup if MASTER_KEY/VAULT_MASTER_KEY matches known default

MEDIUM — Fix This Sprint

  1. Redis authentication — Set REDIS_PASSWORD in .env and configure Redis container with requirepass
  2. Binding internal services to localhost — In docker-compose.yml, change ports: to "127.0.0.1:P:H" for all internal services
  3. Audit log response body sanitizer — Strip tokens from error response bodies before capture backend/internal/audit/audit.go:203
  4. Add panic recovery HTTP middleware — Top-level recovery wrapper in backend/cmd/identity-service/main.go

Security Best Practices for Deployers

  1. Set VAULT_MASTER_KEY — 32+ character hex key generated with openssl rand -hex 32. The service does NOT start without it.
  2. Set MASTER_KEY — enables WorkflowGuard for 12 sensitive mutation endpoints.
  3. Set API_KEYS — comma-separated name:key values. Without these, auth is disabled entirely.
  4. Disable DEV_LOGIN_ENABLED — set to false in production. This is a developer-test-only endpoint.
  5. Set CORS_ORIGIN — your frontend domain. Never use *.
  6. Set PRODUCTION=true — enables additional startup checks (key strength, disabled dev endpoints).
  7. Rotate MASTER_KEY every 90 days — use the SetKeys() hot-reload over API.
  8. Enable TLS — set TLS_CERT_FILE and TLS_KEY_FILE.
  9. Bind database ports to 127.0.0.1 — do not expose PostgreSQL, Redis, or Neo4j to the network.

Dependency Security

Check dependencies before every deploy:

# Go
go mod verify
go mod tidy

# Frontend
npm audit fix

# Secrets scan
gitleaks detect --verbose

# Go vulnerability check
govulncheck ./...

This project follows the principle of least privilege, defense in depth, and assume breach architecture.

There aren't any published security advisories