{
  "$schema": "https://patchrooms.com/security.json",
  "vendor": "Patchrooms",
  "updated": "2026-07-25",
  "status": "early access — not a compliance document, see /security for prose and caveats",
  "humanReadable": "https://patchrooms.com/security",
  "privacyPolicy": "https://patchrooms.com/privacy",
  "termsOfService": "https://patchrooms.com/terms",

  "dataStored": {
    "feedbackReportContext": [
      "url", "pathname", "host", "userAgent", "language",
      "viewport", "screenWidth", "screenHeight", "device", "timestamp"
    ],
    "feedbackReportOptIn": ["consoleErrors (last 10, if enabled)", "networkErrors (last 10, if enabled)"],
    "feedbackReportBlocks": ["text (reporter-typed)", "screenshot (reporter-captured)", "audio (reporter-recorded)", "selection (reporter-picked DOM anchor + quoted text)"],
    "dashboardAccount": ["email", "name", "avatarUrl", "authProvider"],
    "notCollectedAutomatically": [
      "full DOM/HTML serialization",
      "automatic screenshots outside the widget",
      "cookies or session tokens on the public ingest endpoint",
      "keystrokes, network payload bodies, ad/analytics beacons"
    ]
  },

  "infrastructure": {
    "compute": { "provider": "Google Cloud Run", "region": "europe-west1" },
    "objectStorage": { "provider": "Google Cloud Storage", "note": "screenshots and audio blobs" },
    "database": { "provider": "MongoDB Atlas", "note": "managed cluster" },
    "marketingSite": { "provider": "Cloudflare Pages" },
    "selfHostedDataCenters": false
  },

  "encryption": {
    "inTransit": "TLS on all endpoints (dashboard, ingest API, marketing site); no plain HTTP",
    "atRest": "provider-default encryption at rest (Google Cloud Storage, MongoDB Atlas); no additional application-layer encryption of report content",
    "apiKeyStorage": "SHA-256 hash + 16-char lookup prefix; plaintext key shown once at creation, never stored"
  },

  "accessControl": {
    "model": "organization membership (OrganizationMember: owner | admin | member)",
    "scope": "any org member can read every project and report the org owns",
    "publicReportLinks": false,
    "blobReadAuth": "session-authenticated, checks org membership, same-origin response",
    "widgetKeyIsPublic": true,
    "widgetKeyCanWrite": ["submit reports"],
    "widgetKeyCanRead": ["public widget config", "one report by id (deep-link review mode)"],
    "widgetKeyCannot": ["list/enumerate reports", "read other projects", "authenticate as a dashboard user"]
  },

  "apiKeys": {
    "prefix": "pr_sk_",
    "entropyBytes": 24,
    "scopes": ["feedback:read", "feedback:write", "channel:read", "channel:write", "project:read", "project:write", "webhook:read", "webhook:write", "apikey:write", "* (setup-token only, dashboard-minted)"],
    "expiry": "optional TTL, used for setup tokens",
    "revocation": "immediate, dashboard: Integrations -> API keys"
  },

  "retention": {
    "reports": "kept until deleted; per-project auto-delete window configurable",
    "orphanedBlobs": "deleted within ~24h if never attached to a submitted report",
    "dashboardSessions": "~30 days",
    "selfServeDeletion": false,
    "deletionRequestContact": "privacy@patchrooms.com"
  },

  "subprocessors": [
    { "name": "Google Cloud", "purpose": "hosting (Cloud Run), object storage (Cloud Storage)" },
    { "name": "MongoDB Atlas", "purpose": "database and session store" },
    { "name": "Google", "purpose": "dashboard sign-in" },
    { "name": "GitHub", "purpose": "dashboard sign-in" },
    { "name": "OpenAI", "purpose": "audio transcription (opt-in only)" },
    { "name": "Groq", "purpose": "audio transcription (opt-in only)" },
    { "name": "Cloudflare", "purpose": "marketing site hosting/delivery" },
    { "name": "Google Analytics", "purpose": "marketing site analytics only, not in-product" }
  ],

  "certifications": {
    "soc2": false,
    "iso27001": false,
    "note": "No third-party security certification. Early-access product, small team. Inherits provider-level certification (Google Cloud, MongoDB Atlas, Cloudflare) via managed infrastructure. See /security for what we do instead and how to request specific answers.",
    "willProvideOnRequest": ["answers to security questionnaires", "DPA discussion"]
  },

  "knownRisks": {
    "promptInjectionViaReportContent": {
      "description": "Report content (filed by end users, potentially anonymous) is rendered into an AI agent's context via the MCP get_report tool. Treat it as untrusted input, same as any third-party text an agent reads.",
      "mitigations": [
        "report content is returned as inert data, never executed by Patchrooms infrastructure",
        "write actions (set_status, add_comment) require the calling key's own feedback:write scope",
        "add_comment defaults to draft (human review before publish) unless the caller opts into draft:false"
      ],
      "moreInfo": "https://docs.patchrooms.com/for-agents/prompt-injection/"
    }
  },

  "vulnerabilityDisclosure": {
    "contact": "mailto:hello@patchrooms.com",
    "securityTxt": "https://patchrooms.com/.well-known/security.txt",
    "acknowledgeWithin": "3 business days",
    "bugBounty": false,
    "credit": "offered on request after a confirmed, fixed report"
  }
}
