Userz

Security model

What we encrypt, where customer data lives, and where agent runs execute.

Reporting a vulnerability

Email [email protected]. Please don’t open a public issue for a suspected vulnerability, and please give us a reasonable opportunity to investigate and ship a fix before describing it publicly.

A report is most useful when it contains:

  • what you found, and the impact you believe it has
  • the product and version — the desktop app's version string, the mobile build number, the npm package and version, or the URL and approximate time for the hosted platform
  • the steps to reproduce it, with the smallest proof that demonstrates the issue
  • anything you think we will get wrong about it

We will confirm we have received your report and tell you who is handling it, keep you updated while we work, and tell you when a fix ships. If you would like credit, say so and we will name you when we publish the fix; if you would rather not be named, that is the default.

Scope

In scope: the Userz desktop app, the Userz mobile app, the hosted platform (app.userz.ai, api.userz.ai), the feedback widget and its SDKs, the published @userz-ai/* packages and the Userz harness CLI, and our build and release tooling.

Out of scope, because a report here costs us both time and produces no fix:

  • findings from an automated scanner with no demonstrated impact, and missing hardening headers or best-practice deviations with no exploitable consequence
  • denial of service, volumetric or load testing of any kind
  • social engineering, phishing or physical attacks against Userz staff, users or offices
  • vulnerabilities in third-party services we do not operate — report those to their owners
  • reports that require a compromised device, a malicious browser extension, or an attacker who already holds the user's credentials

Supported versions

We fix security issues in the current release of each product and do not backport to earlier ones.

  • Userz desktop app: The current release on each update channel. Older builds update themselves; if auto-update is off, upgrade.
  • Userz mobile app: The current App Store and Play Store release.
  • Hosted platform (app.userz.ai, api.userz.ai): Always current — there is nothing for you to upgrade.
  • Published packages (@userz-ai/*): The latest published version of each package.

Safe harbour

If you make a good-faith effort to follow this policy while researching a vulnerability:

  • we will treat your research as authorised, and we will not pursue or support legal action against you for it — including under computer-misuse law and under anti-circumvention law
  • to the extent your testing would otherwise conflict with our terms of service, we waive those terms for the activity this policy covers
  • if a third party brings an action against you for research that followed this policy, we will make it known that your research was authorised

This protection depends on you:

  • only access accounts and data that are yours, or that their owner has explicitly permitted you to test — if you encounter anyone else's data, stop and tell us
  • stop at the minimum proof the issue is real. Do not exfiltrate data, pivot, escalate, or persist access beyond that
  • do not degrade, disrupt or destroy anything, and do not run denial-of-service or load tests
  • keep the details confidential until we have shipped a fix or agreed a disclosure date with you
  • comply with the law. Nothing here authorises activity that is illegal where you are, and nothing here binds a third party
If you are unsure whether something is in scope, or whether a test would cross one of these lines, ask us first at [email protected]. Asking is always in scope.

Where agent runs execute

Agent runs execute on your own machine, in the Userz desktop app, driving the coding-agent CLI you are already signed in to (Claude Code or Codex). Each run works in its own git worktree of your repository. The Userz cloud does not run your code.

The cloud keeps what the product needs to show you the work wherever you are: the Directive, its status, and, while run-content mirroring is on (the default), the run’s transcript and diffs, so you can follow it from the web console and the phone. Mirroring can be turned off per machine in the desktop app.

Secret handling

We use two-layer envelope encryption. Your AI provider keys, repository tokens, chat-bot tokens, and per-App signing secrets are each encrypted with a key unique to your organization, which is itself wrapped by a master key held in our secret store and never written to a database.

Repo access scope

GitHub. The Userz GitHub App requests three permissions only:

  • contents: write: to push the agent's branch.
  • pull_requests: write: to open the draft PR.
  • metadata: read: required by GitHub for any App.

We do not request workflow, secrets, actions, administration, or any organization-level scope. We mint a fresh 1-hour installation token scoped to the single repo for each agent run. A leaked token cannot enumerate or modify any other repo in your org.

GitLab. Customers supply a per-project access token (recommended) or an OAuth token with the api scope filtered to a single project. The token is encrypted at rest with a key scoped to your organization, decrypted only in memory at the moment a run starts, never lands in plaintext on disk, and never appears in logs. Self-hosted GitLab is supported via a per-Repo baseUrl override.

Diff guardrails

Before the agent's branch is pushed, we run a post-flight check on the diff and refuse to push if any forbidden path was touched:

  • .env, .env.*: any environment file
  • .github/workflows/**: CI definitions
  • .git/**: git internals (defends against symlink shenanigans)
  • infra/**: IaC
  • scripts/release/**

Rejected diffs surface in the dashboard as pr_failed with the file + rule that tripped the guardrail.

Prompt-injection defenses

End-user feedback is treated as untrusted input throughout. Layered defenses:

  1. Hard limits: 8 KB cap on text, 500-line cap on console logs, 10 attachments max, 8 MB body cap on the ingest endpoint.
  2. Pattern pre-filter: known-injection markers (<system> tags, "ignore all previous instructions", role-override phrasing, very long URLs, large base64 blobs) feed soft signals into the next stage.
  3. Classifier: a separate small classifier model labels the report benign | spam | malicious_injection | abuse | off_topic. It runs in its own context window with no shared state with the coding agent.
  4. Wrapped delivery: the agent's user prompt embeds the feedback inside <UNTRUSTED_USER_REPORT> tags with explicit system-prompt instructions that anything inside is data, not instructions.
  5. Tool restriction: the agent is invoked with a read/edit/search/write toolset only. Shell access is restricted to git operations. No general-purpose shell.
  6. Diff guardrail + human review: covered above.
No prompt-injection defense is perfect. The agent's tool restrictions, its own git worktree on your machine, the scoped repo token, and the explicit human-in-the-loop PR review are the load-bearing protections, the classifier is harm-reduction, not a guarantee.

Authentication

  • Dashboard sessions use industry-standard session cookies: HttpOnly, SameSite=Lax, Secure in production. 30-day expiry, 24-hour activity refresh. Google OAuth and email sign-in are supported.
  • Customer API keys (sk_…): high-entropy random tokens, salted and slow-hashed at rest, prefix-indexed for O(1) lookup, constant-time comparison on verify.
  • Widget public mode: App's pub_… key + Origin allowlist enforced per-App.
  • Widget private mode: your backend signs an HS256 JWT with the App's per-App signing secret. The widget includes it in X-Userz-User-Token and we verify signature + exp + app-id binding.
  • Webhooks: every inbound webhook (Stripe, GitHub, GitLab, Slack, Discord) is signature-verified with the provider's published scheme, with a strict timestamp tolerance window and a replay-guard cache that rejects duplicates.

Where customer data lives

  • Primary datastore: feedback text, console logs, batch summaries, audit events, org/app/repo metadata, and encrypted secrets.
  • Private object storage: screenshot attachments and run logs. Lifecycle-deleted after 30 days unless customer-marked for retention.
  • Ephemeral cache: session cache, queue state, rate-limit buckets, webhook replay guard. No persistent customer data, reconstructible at any time.
  • Source code: agent runs work in a git worktree on your own machine; the Userz cloud keeps no copy of your repository. When code-aware features are enabled, Userz keeps an index of excerpts of the source files in your connected repositories, stored in the United States, so the Service can relate signals to your code. Secrets such as API keys and tokens are removed from each excerpt before it is stored. Excerpts may be sent to the AI model providers named on the subprocessors page while the Service processes your signals.