Skip to content
Open the dashboard
Security and data

How Groundrule protects your code

SecurityWorkspace admins9 min read

This page describes the security controls in Groundrule, as the product implements them today. It covers workspace isolation, sign-in, sessions, tokens, connected apps, GitHub, and how your code is handled. Groundrule doesn’t claim any certification. For what data is kept and for how long, see What we store. For AI, see AI and your data.

  • Every workspace’s data is separated in the database by row-level security. Each table that holds workspace data carries the workspace’s ID, and the database itself only returns rows for the workspace a request is acting in.
  • The application checks the same thing again. Workspace access is checked in code before every query, so a mistake in one layer is caught by the other.
  • The workspace comes from your session or token, never from the request. A request can’t ask for another workspace’s data by naming it.
  • Non-members get “not found”. Opening a workspace you don’t belong to returns “not found”, never “forbidden”, so workspace names aren’t revealed.
  • Roles are enforced on the server. A role that can’t do something gets an error, for example “Your role (developer) can’t decide on proposals. Ask an admin.” Hiding a button is never the only control. See Roles and permissions.
Control Detail
Hashing scrypt with N=2^17, r=8, p=1 (128 MiB of memory per hash), a 16-byte random salt, and a 64-byte key. Each hash records its own parameters, so the cost can be raised later
Length 10 to 128 characters, any characters, including spaces
Blocked passwords Common passwords from breach lists, a single repeated character, and passwords that contain your email address
Comparison Constant-time
Unknown emails A failed sign-in takes the same time whether or not the email has an account, and says “That email and password don’t match.”
Forgotten passwords Forgot password? shows the same “Check your inbox” page for any email, so it never reveals which emails have accounts
  • A session is a random token in the gr_session cookie. The cookie is HTTP-only (page scripts can’t read it), Secure (sent only over HTTPS), and SameSite=Lax.
  • Groundrule stores only a SHA-256 hash of the session token, never the token itself.
  • A session lasts 30 days.
  • Settings → Your account → Where you’re signed in lists your sessions by browser and operating system.
  • Changing your password signs out every other session: “Password changed. Other sessions were signed out.”
  • Resetting your password signs out every other session too, and Groundrule emails you that the password changed.

Confirmation, sign-in and password-reset links each carry a random token. Groundrule stores only its hash.

Link Valid for Uses
Sign-in link 15 minutes Once
Password reset 30 minutes Once
Email confirmation 24 hours Once

Opening a link shows a page with a button (Confirm and continue, Sign in), so mail scanners that open links can’t use them up. A used or expired link shows Link expired.

Any request that changes something and is signed in with a cookie must come from the Groundrule app’s own address. Groundrule checks the browser’s Origin header and refuses anything else: “Requests must come from the Groundrule app.” Connecting Notion, Google Docs, Confluence or GitHub uses a one-time state value in a short-lived cookie, so a callback from another browser or another site is refused.

Repeated attempts are slowed down per email address and per IP address. When a limit is reached, the request is refused with a message such as “Too many imports. Wait a while and try again.”

Action Limit
Sign in with a password 10 per email and 50 per IP address, per 15 minutes
Create an account 3 per email and 20 per IP address, per hour
Email a sign-in link 3 per email per 15 minutes, 20 per IP address per hour
Request a password reset 3 per email and 20 per IP address, per hour
Resend a confirmation email 3 per email and 20 per IP address, per hour
Open an email link 30 per IP address per 15 minutes
Change your password 10 per 15 minutes
AI requests (drafts, Describe a rule) 60 per person and 300 per workspace, per hour
Document imports 30 per person per hour
Proposals from the CLI and MCP 30 per person per hour, 500 per workspace per day
Scan uploads 60 per token per hour, 1,000 per workspace per day
Control Detail
Format grt_ followed by 32 random bytes
Storage Only a SHA-256 hash. The full token is shown once, when it is created
Display The first 12 characters, so you can recognize it
Permissions Reading the rulebook is always included. Upload scans and Propose rules are optional
What tokens can’t do Change the rulebook, members or settings. Tokens work only for the CLI’s endpoints, and never with a cookie
Identity A token acts as the person who created it, in one workspace
Expiry 30, 90 or 365 days, or never. groundrule login creates a 90-day token
Revoking Settings → API tokens. Admins can see and revoke everyone’s tokens; others, their own
Active tokens Up to 25 per person per workspace

The CLI saves credentials with file mode 600, in a folder with mode 700. It refuses to send a token over plain http, except to localhost: “Refusing to send credentials to … use https”. See Environment and files.

  • Notion, Google Docs and Confluence are connected through each app’s own OAuth consent screen, by an admin or platform admin.
  • Tokens are encrypted at rest with AES-256-GCM, using a key held only by the Groundrule service. A copy of the database alone doesn’t reveal them.
  • Tokens are never shown or returned, not even to admins: “Tokens are encrypted and never shown.”
  • Access is read-only. Google Docs asks only to read documents, not to browse Drive. Confluence asks to read pages. Notion sees only pages shared with the integration.
  • Pages are read only when someone imports them.
  • Disconnect deletes the tokens, and revokes the access at the app where the app supports it.
  • Least privilege. The Groundrule GitHub App asks for read-only access to pull requests and metadata, on the repositories you choose on GitHub.
  • Installations are tied to the installer. Groundrule saves an installation only when the person installing it can see it on GitHub, so a tampered installation ID can’t attach someone else’s repositories. One installation belongs to one workspace.
  • Webhooks are verified. Every delivery’s HMAC-SHA256 signature is checked against the raw body, in constant time. A delivery with a wrong signature is refused.
  • Each delivery is handled once. A replayed delivery is recognized by its ID and ignored.
  • Bots are ignored, both in review imports and in /groundrule rule.
  • Uninstalling the app on GitHub removes it from Groundrule.

See Rules from pull-request reviews.

  • Scans run on your computer or CI runner. The CLI never executes code from the repository, and reads configuration files as text.
  • A scan uploads results, not source. At most 3 examples per rule, each with a one-line snippet of at most 200 characters. Snippets are never kept for security rules, have secrets redacted on your computer and again on the server, and can be turned off with --no-snippets. See Scan repositories.
  • Uploaded documents are recognized by their content, not their name, and Word files are checked before they are unpacked, so a compressed file can’t expand without limit. The file itself is never stored.
  • Checks written by AI are tested in isolation. A regular expression from Describe a rule runs in a separate sandbox with a time limit, and is probed for patterns that could run forever, before you see it.
  • Logs never record authorization headers, cookies, or webhook signatures.