Security
Last updated: October 4, 2026
This page describes how ValGuard.ai protects the hosted service and what you can verify in product behavior, legal terms, and repository documentation. It is written for security and procurement reviewers. It is not a certification, penetration-test report, or SOC 2 attestation. For product context and outage behavior, see Trust. For contractual terms, see the DPA and Privacy Policy.
TL;DR for reviewers
- Product: OpenAI-compatible validation and policy proxy (web dashboard, Go engine, Postgres, Redis). Customer LLM providers are configured by the customer (BYOK or Provider Vault), not ValGuard subprocessors.
- Data default: Prompt and completion text is validated in memory and is not written to the database unless the customer enables payload logging on an agent at the full log level. Request metadata is retained per plan for billing and observability.
- Encryption: TLS for service traffic; Provider Vault credentials encrypted with AES-256-GCM using a deployment secret (
INTERNAL_PROXY_SECRET). BYOK keys are not stored. - Access: Organization roles (owner, admin, member) gate dashboard APIs; optional email OTP MFA for dashboard sign-in; API keys are
vg_live_*with bcrypt storage and prefix lookup. - Evidence: Published inventory on Trust; governance audit log (Enterprise dashboard UI); validation/request logs; DPA Annexes; CI dependency scan summary on merge requests and the default branch. Third-party attestation reports are available on request via contact or security@valguard.ai.
Data flow
Traffic path (hosted SaaS):
- Your application sends an OpenAI-compatible request to the ValGuard API with a ValGuard API key.
- Optional input validators run on the prompt.
- ValGuard forwards to the upstream model using BYOK (
X-Provider-Key) or a Provider Vault credential. - Output validators run on the completion (or buffered stream).
- The response returns with validation headers (for example
X-VG-Validation-Status).
What ValGuard sees, stores, and does not store
| Stage | Always in memory for validation | Persisted by default | Persisted only when customer enables it |
|---|---|---|---|
| Prompt / completion text | Yes, for the life of the request | No | Yes, when agent log level is full and payload logging applies (payload_logged=true on the request row) |
| Request metadata (timestamps, provider, model, status, latency, token counts, cost, reask count, key source) | Yes | Yes, for plan retention | Same |
| Per-validator pass/fail and severity | Yes | Yes (outcomes); message body redacted per log level | Full level stores validator messages without redaction |
| Provider Vault secret | Decrypted only to call the provider | Ciphertext + nonce in Postgres | N/A |
BYOK X-Provider-Key | Yes, per request | No | N/A |
Agent log levels (validator messages and stored detail)
Configured per agent (log_level in the engine; default metadata):
| Log level | Validator messages in logs | Prompt/output content in DB |
|---|---|---|
| metadata (default when logging is on) | PII and secrets masked (emails, tax IDs, PESEL/NIP, SSN, IBAN, cards, API key patterns, and similar) | Not stored unless full |
| hashed | Sensitive strings replaced with SHA-256 fingerprints; structural fields kept | Not stored unless full |
| full | Stored verbatim (debug only; corresponds to payload_logged) | Stored when payload logging is active, subject to retention |
Implementation reference: apps/proxy/internal/privacy/redact.go. Privacy policy: Section 5.
Retention and deletion
- Request metadata and logged payloads: 7 days (Free, Developer), 30 (Growth), 90 (Production), 365 (Enterprise), or as in an order form. Customers may set a shorter payload retention per agent up to the plan cap.
- Automated purge:
npm run purge:retention/ scheduled job removes expired payloads (see Privacy Policy). - GDPR erasure: Organization owners can request workspace erasure via the dashboard API (
org.erasure_requestedis recorded in the governance audit log). - Backups: Encrypted backups may retain data for a limited rotation period as described in the Privacy Policy.
Encryption
| Layer | Mechanism | Notes |
|---|---|---|
| In transit | TLS | API, dashboard, and gateway traffic (DPA Annex 3) |
| Provider Vault at rest | AES-256-GCM, per-secret nonce | Key derived from INTERNAL_PROXY_SECRET (apps/web/lib/vault-dev.ts). Operators set this per self-host docs and docs/ops.md in the product repository |
| Dashboard passwords | Hashed by Better Auth | Not stored in plain text |
| ValGuard API keys | bcrypt hash in database; prefix index on first 16 characters of vg_live_* | Raw key shown once at creation |
Not implemented in the open codebase today: AWS KMS envelope encryption for vault (noted as a future direction in vault-dev.ts comments). Self-host operators control their own disk and backup encryption for Postgres.
Authentication and access control
Dashboard sign-in
- Email and password (Better Auth), with optional email OTP MFA after password verification (
apps/web/lib/mfa/). SMS and TOTP methods are defined in code but not wired to providers yet. - OAuth (Google, Facebook, LinkedIn) when the corresponding client ID and secret env vars are set (
apps/web/lib/auth-providers.ts). - Email verification can be required when
REQUIRE_EMAIL_VERIFICATION=true(documented indocs/ops.md).
Organization RBAC
Roles: owner, admin, member (org_members.role). Enforced on API routes via requireOrgRole (apps/web/lib/rbac.ts). Examples:
| Action | Minimum role |
|---|---|
| Billing, Stripe checkout/portal | admin |
| Provider Vault and custom endpoints | admin |
| Org webhook URL | admin |
| Invite teammates | admin (create); owner (revoke pending invite) |
| Change member roles / remove members | owner |
| GDPR org erasure | owner |
| Agents, validators, playbooks (day-to-day) | member |
The RBAC plan feature (team roles) is included on Production and Enterprise plans (apps/web/lib/plans-fallback.ts). Role columns still exist on all plans; gating applies to certain dashboard features.
API access
- Chat and validation traffic authenticate with
Authorization: Bearer vg_live_.... - Invalid-key bursts are short-circuited per client IP and key prefix before bcrypt (
PROXY_API_KEY_PREAUTH_*env knobs indocs/ops.md).
ValGuard staff access
/adminroutes require a signed-in user flaggedis_staffor listed inSTAFF_EMAILS(apps/web/lib/staff.ts,apps/web/lib/admin-auth.ts).- Staff actions such as impersonation, plan edits, and license issuance write to
governance_audit_log(for exampleadmin.impersonate_start,staff.license.issue).
Tenant isolation
- Every API key and request row is scoped to an organization (
org_id). The engine resolves the org from the API key and loads agent configuration for that org only. - Dashboard session APIs resolve an active org and enforce membership before returning data.
- Provider Vault secrets are stored per organization; decrypted values are not returned through the dashboard or API (metadata only).
Cross-tenant access is treated as an authorization bug; report via security@valguard.ai.
Audit logs and observability
Two related surfaces:
- Validation and request logs (Dashboard → Request logs / Validation logs): per-request metadata and validator outcomes. Available when the plan includes analytics features.
- Governance audit log (Dashboard → Audit): configuration and security-relevant changes (API keys, agents, vault credentials, erasure requests, playbook edits, and similar). UI access is gated to the Enterprise plan (
apps/web/app/dashboard/audit/page.tsx); rows are still written for qualifying actions on other plans.
Representative governance actions recorded in code include: api_key.create, api_key.revoke, vault.credential.upsert, vault.credential.revoke, agent.create, agent.update, agent.delete, org.erasure_requested, org.rename, and staff-only admin.impersonate_* / staff.license.*.
PII, redaction, and retention controls
- Automatic masking and hashing at metadata and hashed log levels (see table above).
- Customers choose agent log level and whether to enable payload logging; ValGuard does not turn on full logging by default (Terms §3.2).
- Validator catalog includes compliance-oriented detectors (PII, PCI, secrets, and regional IDs); detection is rule-based and not guaranteed complete (Privacy Policy §16).
Outbound webhooks
When an organization sets a webhook URL (admin role):
- Deliveries are signed with
X-VG-Signature: sha256=<hex>, HMAC-SHA256 over the raw JSON body (apps/proxy/internal/webhook/signature.go). - The HMAC key is the deployment-wide
OUTBOUND_WEBHOOK_HMAC_SECRET, not a per-org secret generated in the dashboard. - There is no timestamp or nonce in the signature today; plan replay controls in your receiver if needed (validation webhooks tutorial).
- Delivery is best-effort (no automatic retry queue documented in product tutorials).
Rate limiting and abuse controls
| Layer | What it limits | Where to verify |
|---|---|---|
| Go proxy | Plan quotas (requests per minute/month), API key auth | apps/proxy rate limit metrics; PROXY_RATE_LIMIT_STRICT fails closed when Redis is down in production |
| Web dashboard | Sensitive actions (account delete, org erasure, invite churn, API key churn, Stripe webhook IP) | apps/web/lib/sensitive-action-rate-limit.ts |
| Web dashboard APIs | General dashboard rate limits (Redis when REDIS_URL set; in-memory fallback) | apps/web/lib/dashboard-rate-limit.ts, docs/ops.md |
| Marketing / auth | Contact form, signup, support | CONTACT_RATE_LIMIT and admin-configurable rate_limits.* |
| API key guessing | Pre-auth guard on invalid attempts per IP + key prefix | PROXY_API_KEY_PREAUTH_* |
Multi-node web deployments should set REDIS_URL for consistent dashboard limits (docs/deploy-readiness-checklist.md).
Secure development lifecycle (SDLC)
What runs in this repository today:
- CI (GitLab):
go test ./...for the proxy; integration tests with Postgres;npm run test:unitand component tests for the web app;make test-systemon merge requests and the default branch (.gitlab-ci.yml). - Dependency scans (CI): on merge requests and the default branch, job
security:dependency-summaryrunsscripts/ci-security-summary.sh(govulncheck ./...onapps/proxy,npm audit --audit-level=highonapps/web) and publishessecurity-scan-summary.jsonas a pipeline artifact. The job is informational (allow_failure: truein.gitlab-ci.yml); we do not claim zero known vulnerabilities at all times. - Coordinated disclosure: Vulnerability disclosure, /.well-known/security.txt, and security@valguard.ai.
- Personal data breach notice: 72-hour notification commitment for Customer Personal Data in the DPA §9 (contractual, not a public incident register).
We do not publish formal secure-code-review policy documents or penetration-test results on this page.
Self-hosted and Enterprise deployment
Enterprise customers may run the same stack in their VPC or on-prem (self-host docs):
- Components: Next.js web, Go proxy, PostgreSQL 16, Redis 7.
- License:
VALGUARD_LICENSE_KEY(Ed25519 JWT), offline verify, cloud heartbeat without customer AI payloads; heartbeat responses HMAC-signed. - Operator responsibilities: TLS at the edge,
INTERNAL_PROXY_SECRET, network isolation for Postgres/Redis, and their own backup and monitoring practices.
Subprocessor and residency statements for hosted SaaS remain on Trust and /legal/subprocessors.
Subprocessors and data residency
ValGuard hosted SaaS uses the subprocessors listed at /legal/subprocessors (currently Vultr for hosting and storage, Amazon Web Services (SES) for email, Stripe for billing). LLM providers you configure are your processors, not ValGuard subprocessors (DPA §2.4).
We do not state a dedicated EU-only SaaS region on this page unless your order form or DPA amendment does.
Incident response
- Personal data breaches affecting Customer Personal Data: notification per DPA §9.
- Service availability: status page (not a security incident feed).
Vulnerability disclosure
ValGuard welcomes good-faith reports of security vulnerabilities in the ValGuard.ai hosted service and this product repository.
Scope (in scope): ValGuard-owned web properties, API endpoints, and open-source components we ship (apps/web, apps/proxy, documented self-host stack). Out of scope: customer applications, customer-configured LLM providers, social engineering, physical attacks, and testing against customer data or production tenants without written authorization.
How to report: security@valguard.ai or /.well-known/security.txt (also lists abuse@valguard.ai for abuse). Include reproduction steps, impact, and affected URLs or versions when known.
Acknowledgment SLA: we aim to acknowledge receipt within three (3) business days and will keep you informed of material status changes during coordinated remediation.
Safe harbor: we will not pursue legal action against researchers who follow this policy, avoid privacy violations and service degradation, and give us reasonable time to fix issues before public disclosure.
Coordinated disclosure: please allow us time to remediate before public release. We may credit reporters when they prefer.
Not publicly attested
The following are not published as public attestations on this site (confirm scope with your order form or private letter):
- SOC 2 Type I/II, ISO 27001, or FedRAMP authorization
- Continuous attack-surface monitoring as a customer-facing report
Product limits (documented, not certifications): per-organization webhook signing secrets and built-in webhook replay protection are not shipped today; Provider Vault uses AES-GCM with a deployment secret rather than KMS envelope encryption in the open codebase; dashboard MFA is email OTP (SMS/TOTP providers are not wired).
Available on request
Under NDA or a countersigned DPA, Enterprise and procurement teams can request:
- SOC 2 roadmap letters, penetration-test executive summaries, and other assessment artifacts referenced in DPA §8 and §11 (scope, date, assessor, and findings must be confirmed)
- Signed customer references and custom security questionnaires
- Countersigned DPA and subprocessors objection process (DPA §6.4)
- Self-host license and deployment guidance via contact
Reviewer checklist
| Control area | Implementation (summary) | Where to verify |
|---|---|---|
| Data minimization | In-memory validation; no payload persistence by default | Trust, Terms §3.2, Privacy §5 |
| Log level / redaction | metadata / hashed / full + payload_logged | This page §Data flow; apps/proxy/internal/privacy/redact.go |
| Encryption in transit | TLS | DPA Annex 3 |
| Secrets at rest | Provider Vault AES-256-GCM | apps/web/lib/vault-dev.ts, DPA §5.2 |
| Authentication | Better Auth; optional email OTP MFA | Dashboard → Account → Security; apps/web/lib/mfa/ |
| Authorization | Org RBAC on API routes | apps/web/lib/rbac.ts; tutorial RBAC |
| API keys | vg_live_*, bcrypt, prefix lookup | apps/proxy/internal/store/store.go (GetAPIKeyByBcrypt) |
| Audit trail | governance_audit_log + request logs | Dashboard → Audit (Enterprise UI); API /api/audit |
| Webhook integrity | HMAC-SHA256 body signature | apps/proxy/internal/webhook/signature.go |
| Rate limits / abuse | Proxy quotas, web sensitive-action limits | docs/ops.md, proxy and web rate-limit modules |
| Subprocessors | Published list + DPA Annex 2 | /legal/subprocessors |
| Breach notification | 72h to customer (processor) | DPA §9 |
| CI dependency scans | govulncheck + npm audit (high); JSON artifact | SDLC; Trust |
| Vulnerability disclosure | security.txt + security email; 3 business day ack aim | /.well-known/security.txt, Vulnerability disclosure |
| Self-host | License + operator runbooks | /docs/self-host, Trust |
Related
- Trust — data residency, failure modes, SLA summary, evaluation paths
- Pricing — plan limits and retention caps
- Privacy Policy · DPA · SLA · Subprocessors
- Self-host operator guide
- Contact for procurement and Enterprise questions