HouseGRC: a self-hosted, multi-tenant GRC platform, built solo
A solo-built, owner-controlled GRC platform that runs a whole security and compliance programme from one encrypted, multi-tenant app, from frameworks, risk and audits through access reviews, incident response, privacy, AI governance and the external attack surface, with central fail-closed tenant scoping.
What it is
HouseGRC is a self-hosted, multi-tenant governance, risk, and compliance platform that I built solo and run myself. The sensitive part of GRC, meaning your open risks, your control gaps, your incident playbooks, is what you least want sitting in a SaaS you don’t control. HouseGRC keeps that record in a single owner-controlled deployment, encrypted at rest: one app that consolidates an organization’s compliance frameworks, risk register, controls and evidence, policies, audits, third-party/vendor risk, software and asset inventory, BIA/BCP/DR and incident-response planning, and executive reporting. You hold the keys and the data stays inside your boundary.
It is the inward half of a two-part idea. DeepReview, my outward-facing, authorized-use-only vendor-risk and reconnaissance project, is the inverse. Where HouseGRC manages your own posture, DeepReview profiles the third parties you depend on. The two started as one app and now run as separate deployments, each standing on its own.
Domain breadth
The hard part of GRC is the breadth of the domain and the relationships between its parts, not the UI. HouseGRC ships with a broad seeded catalog spanning the major standards: the ISO 27000 family plus the privacy and AI extensions (27701, 42001), SOC 2, the NIST family (CSF, 800-53, 800-171, RMF, AI RMF), PCI DSS, HIPAA, HITRUST, CIS, CMMC, FedRAMP, CSA CCM, and a wide set of privacy and sector regimes (GDPR, CCPA/CPRA, PIPEDA, LGPD, POPIA, DORA, NIS2, the EU AI Act, OWASP LLM, and more). The controls library underneath those standards matters more than the count of them. A single control cross-maps across many standards, so satisfying one requirement credits every framework that depends on it instead of forcing you to re-document the same control N times.
On top of that catalog sit the working surfaces:
- Risk register: inherent vs. residual scoring, heat-maps, and the ability to promote a finding straight into a tracked risk.
- Evidence: scheduled connectors (cloud, source-control, and identity-provider integrations) that pull evidence on a cron rather than relying on someone remembering to screenshot a console, with automatic mapping of collected evidence to the overlapping controls it satisfies.
- Policies: a library of policy templates with a submit / approve / reject workflow.
- Audit toolkit: control sampling, finding workpapers, and exportable audit-project bundles you can hand to an external auditor.
- Third-party / vendor risk: vendor profiles, automated risk tiering whose reasoning is shown rather than hidden behind a single opaque number, a normalized trust score fed by the vendor’s profile and assessment signals, and tokenized public security questionnaires a vendor can fill without an account.
- Software & asset inventory: paired with a vulnerability register fed by a CVE feed, scored with CVSS, and worked through a triage flow.
- Resilience planning: BIA, BCP, DR, and incident-response plans with phased, role-tagged steps so each phase records who does what.
- Incident management: with a regulatory-reporting rule engine that evaluates a breach’s data class and jurisdiction (PII / PHI / payment data, by region) against thresholds and maps the combination to the specific reporting obligations and clocks it triggers, so an obligation in the wrong jurisdiction surfaces instead of slipping.
- Architecture risk assessments: document upload with AI extraction, plus automated security-control-assessment scoring with a graded result and a per-domain breakdown.
- Executive dashboards: Risk, Security, IT, and a predictive view.
- The long tail of GRC hygiene: exceptions, access reviews, a regulations register with change tracking, privacy DSAR handling and right-to-be-forgotten redaction, and retention.
It also exposes a REST API and supports enterprise SSO and multi-org operation, so a larger installation can integrate it with existing identity and provision multiple business units under one deployment.
Running the programme, not just recording it
A register tells you what you have. The newer half of HouseGRC is about the work a security leader does every week, so each area produces owned, dated actions that land in a personal My Work queue and on a shared calendar, and is backed by evidence an auditor can follow.
- Governance and risk: business objectives with a coverage rollup, per-category risk appetite bands with over-appetite badges and two-approver acceptance, a key-risk-indicator library with stored history and breach alerts, a single register of open risks, audit findings and exceptions on one severity scale, and a board pack carrying the organization’s own branding.
- Assurance: a criticality-weighted audit-readiness score per framework with its blockers and a daily trend, continuous control checks that assert against collected evidence and open (and close) findings on their own, evidence-freshness chasing, and a governance calendar of ceremonies, audit windows, certifications and reviews.
- Identity and access: separation of duties with self-approval blocked on every approval gate and toxic permission combinations reported, time-limited group membership with just-in-time requests and break-glass sessions, and per-user access reviews where a “revoke” decision actually removes the access.
- Vulnerabilities and exposure: remediation SLAs ranked by known exploitation (CISA KEV) and exploit probability (EPSS), import of common scanner export formats matched to the software inventory, an asset-exposure ranking, and external attack-surface discovery from Certificate Transparency for verified domains, with a TLS expiry watch.
- Third parties: vendor criticality derived from business impact and the recovery objectives of the processes that depend on each vendor, a concentration and single-point-of-failure view, contract renewal tracking that warns before an auto-renewal locks in, and an offboarding checklist built from everything the vendor touches.
- Incidents: corrective actions and a structured post-incident review, a live countdown to each regulatory notification deadline with escalation, an on-call rota that assigns new incidents, and links between incidents and the risks they realised.
- Privacy: data classification on systems, a record of processing activities with lawful-basis rules and transfer safeguards, DPIA screening and sign-off, and a map of where restricted data flows.
- AI governance: a register of AI systems and agents with EU AI Act risk classification, the obligations each one triggers (serious-incident reporting included), impact assessments, scheduled kill-switch tests and evaluations, and detection of AI in use that nobody registered.
- People and architecture: recurring security-awareness and AI-literacy training with completion evidence, phishing-simulation records with automatic refreshers, a privacy-respecting human-risk score, and per-assessment STRIDE threat models traced to controls behind a design-review sign-off.
Architecture
HouseGRC is a Python full-stack application built on Reflex, which compiles a Python UI to React. State is server-authoritative: the browser holds a thin client, and user actions round-trip as events to event handlers on the server, which mutate state objects and stream back the minimal delta over a WebSocket. The upside is that one language and one type system span the whole app. There’s no separate JavaScript codebase, and the back-end model objects the UI binds to are the same objects the services layer mutates. The cost is that the app is stateful and connection-oriented rather than a stateless request/response front end, which shapes how sessions and long-running work are handled.
Because some integrations genuinely want a conventional request/response surface (the REST API, SCIM, SAML), a FastAPI sub-app is mounted alongside the Reflex ASGI app and serves those endpoints directly, rather than trying to model webhook callbacks and machine-to-machine calls as UI events. Persistence is SQLAlchemy 2.0 with Alembic migrations. The default datastore is a SQLCipher-encrypted SQLite database, which keeps the whole deployment to a single owner-controlled, fully-encrypted-at-rest file; migrations and seeding run at boot against that encrypted database (the SQLCipher key is supplied at connect time, so Alembic operates on the decrypted handle like any other engine). Postgres is the supported backend when an installation outgrows the single-file model. The SQLAlchemy layer is the same either way, so the switch is a connection concern, not a rewrite. In-process scheduling uses APScheduler to drive the evidence connectors, CVE-feed pulls, and backup jobs on a cron without standing up a separate worker fleet. The whole thing ships as a single Docker image behind a standard reverse proxy / CDN of the operator’s choice; the deliberately small footprint is what makes it realistic for one person to maintain and for an organization to self-host without a platform team behind it.
Tenant isolation
For a system whose job is to hold an organization’s compliance and risk record, the multi-tenant boundary is a feature surface in its own right rather than a config flag. Rather than trusting every query to remember a WHERE org_id = ? clause, org scoping is enforced centrally and is designed to fail closed. The current org lives in a ContextVar set per authenticated request/task; a SQLAlchemy do_orm_execute listener intercepts ORM SELECTs and attaches a with_loader_criteria predicate scoped to that org context, and a complementary before_flush hook scopes writes, so the filter is injected below the service layer instead of being hand-written per query. When no org context is set, the default is to deny rather than return an unscoped result, so a missing context yields nothing. Sub-org hierarchies are reconciled with the filter by scoping to the org subtree (resolved through a recursive query that’s memoized per request to keep the cost down) rather than a single id, so a parent can see its children without the filter having to be turned off. I treat this layer as something to keep hardening rather than a solved invariant. Central enforcement removes the most common class of cross-tenant bug from the surface area, but I keep testing the boundary rather than assuming it’s airtight.
Defensive engineering
Layered on top of the tenant boundary:
- Encryption: column- and secret-level authenticated encryption (AES-GCM) for the most sensitive fields, on top of SQLCipher’s full-database encryption at rest.
- Authentication: MFA via TOTP and WebAuthn/passkeys, role-based access control, geo/IP access controls, and new-IP sign-in alerts.
- Auditability: an append-only, hash-chained audit trail. Each entry incorporates a hash of the prior entry, so editing or deleting any record breaks verification of everything downstream and makes silent tampering detectable.
- Outbound safety: outbound fetches go through a single SSRF-aware chokepoint that resolves and screens destinations against internal, link-local, and metadata IP ranges and restricts schemes, so connectors, webhooks, and document fetches can’t be coerced into pivoting into internal networks.
- LLM input safety: untrusted text is run through a guardrail before it reaches a model. It’s framed as data inside clearly delimited BEGIN/END markers with an explicit instruction-hierarchy reminder that wrapped content must never be treated as commands, invisible/control characters used by injection vectors are stripped, and a best-effort detector flags likely injection attempts. A GRC tool ingests the attacker-influenced material that prompt injection targets, like vendor questionnaires and uploaded architecture documents, so that chokepoint sits on the hot path.
AI engineering
The chat copilot is read-only and data-aware: it can query your own GRC data and answer across it, but it cannot mutate anything. The tool surface exposed to the model is deliberately read-only, so it can’t turn an assist into an action. Its data access runs through the same org-scoped filtering as everything else, which means read-only is also tenant-scoped: the copilot can’t reach another org’s rows any more than a service method can. AI risk and control suggestions, predictive analytics, AI-written executive summaries, and AI-governance scoring round out the assistive layer.
Elsewhere AI drafts and a person decides: AI impact assessments, post-incident review hypotheses, architecture threat models and control suggestions all arrive as drafts that fill only what is still empty and never overwrite what someone wrote, and each runs the record it reasons over through the same untrusted-input guardrail. Underneath sits a provider-agnostic LLM adapter with a single configuration and connection-test path: the same pipeline runs against Anthropic, OpenAI, or an operator-supplied custom endpoint, with the adapter normalizing model families, request shape, and JSON-wrapping quirks so the orchestration code doesn’t care which provider is behind it. System prompts are editable rather than hard-coded, so analysis behavior can be tuned without touching code.
Built solo
Building and running this alone is the constraint that shaped every choice above. A single encrypted file as the default datastore, one Docker image, in-process scheduling, and one language across the stack keep the operational surface small enough for one person to own while the compliance surface stays large. That’s the point of them, more than minimalism for its own sake. The tension is that a GRC platform’s whole value proposition is trustworthiness, and trustworthiness usually buys you a team, an audit budget, and a SOC. Without those, the trust has to come from the architecture instead. Central fail-closed tenant scoping, layered encryption, a tamper-evident audit chain, and the SSRF and prompt-injection chokepoints are the things that let a one-person build credibly hold the data it holds. Working on it taught me to treat the security model as the product rather than a wrapper around it, and that “designed to fail closed” is something you keep working at rather than a box you check once. It’s the inward half of a pair: profile everyone you depend on in DeepReview, manage your own posture here.