# Security at LightInventory

> Where your data lives, what Google access we ask for, how sign-in, roles and tamper-evident history work, and which providers we use.

Source: https://www.lightinventory.com/security · Last updated: 2026-10-30

Your inventory data stays in your own Google Sheet. LightInventory reads and writes that file on your behalf, keeps no copy of its contents on our servers, and stores only what it needs to run your account. This page explains exactly how that works, what we protect against, and where the limits are.

> **Note:** LightInventory is in development and not yet generally available. This page describes the system as designed. It does not claim audits, certifications or an uptime record, because none exist yet.

## Where your data lives

Business data (items, locations, stock movements, prices, notes, approval proposals and the before/after values in your history) lives only in spreadsheets in your Google account. Our servers read cell values into memory to show pages, compare changes, build exports and write your updates. Those values are not saved to our database, our logs or our error reports. An automated test suite checks that no table, log line or error event contains cell values.

We do store the data needed to run your account:

| What we store | Why | Protection |
|---|---|---|
| Users, profiles, organizations, memberships, roles, invitations (only a hash of each invite token) | Sign-in and team management | Encrypted at rest by the database provider |
| Sign-in factors: passkey public keys, TOTP secrets, hashed recovery codes | Multi-factor authentication | TOTP secrets are additionally envelope-encrypted with keys held in a key management service |
| Google refresh token for the connected spreadsheet | Reading and writing your file | Envelope-encrypted; never sent to the browser or written to logs |
| Spreadsheet metadata: file ID, tab IDs, schema version, lock mode | Finding and checking your file | Contains no cell values |
| Row fingerprints (keyed hashes of each row) | Detecting edits made directly in the sheet | Keyed, so they cannot be reversed to the values |
| Audit hash chain: sequence numbers, entry IDs, hashes, actor ID, action type, time | Proving your history is unchanged | Contains no values |
| Billing references from our payment provider | Subscriptions and invoices | Contains no card numbers |
| Security events: sign-in attempts, permission failures, IP address, browser | Detecting abuse | IP address removed after 90 days, events deleted after 1 year |

Our own system runs in **London**. The database (Supabase, region `eu-west-2`), the application servers (Vercel, region `lhr1`), and our encryption keys and history anchors (Google Cloud, region `europe-west2`) are all pinned there. Transactional email is the one documented exception, covered under [infrastructure and subprocessors](#infrastructure-and-subprocessors).

## The Google access we ask for

LightInventory asks Google for two things. At sign-in with Google, it asks for your basic profile: `openid`, `email` and `profile`. When you connect a spreadsheet, it asks separately for one Drive permission, `drive.file`.

In plain words, `drive.file` lets an app work only with the files you create with it or choose for it. Google describes it as access to files "that you open with an app or that the user shares with an app while using the Google Picker API" ([Google Drive API scopes](https://developers.google.com/workspace/drive/api/guides/api-specific-auth)). Google classifies it as a non-sensitive scope.

What that means for you:

- LightInventory cannot list, open or search the rest of your Google Drive. A file you never created with LightInventory or picked in the Google file picker is invisible to it.
- We never ask for the broader `spreadsheets` scope or any full-Drive scope.
- After every grant, we check that Google returned exactly the access we asked for.
- You can remove the access at any time from your Google Account. See [Revoke LightInventory's Google access](/help/data-and-privacy/revoke-google-access).

Only the person who connects the spreadsheet grants this access, and that person must own the file. Your team members are never added to the file in Google. They work through the app, under the roles you give them.

## Sign-in and sessions

Every user signs in with two factors, on every plan, every time a session starts.

1. **First factor:** Google sign-in, or an email and password. Passwords must be at least 12 characters and are checked against lists of breached passwords. Google sign-in counts as the first factor only, never as both.
2. **Second factor:** a passkey, which is the default and resists phishing, or a TOTP code from an authenticator app. Each user enrolls at least two methods and receives 10 single-use recovery codes.

For Owners and Admins, phishing-resistant sign-in is required by default, so TOTP is turned off for those roles unless the owner changes the setting. Hardware security keys work as passkeys. An email link can reset a password, but it never replaces the second factor.

Multi-factor authentication is checked in two independent places: in our server code and in the database's own access rules. A session that has passed only the first factor can read nothing, even if it calls the database directly.

| Session setting | Value |
|---|---|
| Sign-out after inactivity | 60 minutes |
| Maximum session length | 24 hours |
| Fresh second factor for sensitive actions | Within the last 5 minutes |
| Failed second-factor attempts before lockout | 10, with delays from 30 seconds to 1 hour |

Sensitive actions include role changes, billing changes, connecting or disconnecting a spreadsheet, exports, bulk reverts, changes to sign-in methods and deleting the organization. You can see your active sessions and end any of them. We email you when a new device signs in, when a sign-in method is added or removed, and when recovery codes are used.

## Roles, locations and approvals

Each organization has five roles: Owner, Admin, Approver, Editor and Viewer. Editors and Viewers can be limited to specific locations, so a store team sees and changes only its own stock.

| Capability | Owner | Admin | Approver | Editor | Viewer |
|---|---|---|---|---|---|
| View items, stock and history | Yes | Yes | Yes | Own locations | Own locations |
| Record movements | Yes | Yes | Yes | Own locations | No |
| Approve requests | Yes | Yes | Yes, not their own | No | No |
| Bulk revert | Yes | Yes | No | No | No |
| Manage members | Yes | Yes | No | No | No |
| Connect the spreadsheet, delete the organization | Yes | No | No | No | No |

Permissions are read live on every request, so removing someone or changing their role takes effect on their next action. Every request is denied unless a rule allows it. Each role is explained in [Team and roles](/help/team-and-roles).

Approvals are optional. When they are on, an organization can require approval for changes such as price edits or stock adjustments. The proposed change is written to a protected tab in your spreadsheet, and nobody can approve their own request. Learn more in the [audit trail](/features/audit-trail) overview.

## Tamper-evident history

Every change made through LightInventory is written as a history entry in a protected `Log` tab inside your spreadsheet, in the same Google update as the change itself. Stock is never edited as a number. It is calculated from an append-only list of movements, and a revert is a new, opposite entry rather than a deletion.

Tamper-evident means that if anyone alters or removes a past entry, verification shows it. It does not mean the change is impossible. This is how it works:

- **A keyed chain.** Each entry gets a code computed from its contents and the previous entry's code, using HMAC-SHA256 and a secret key for your organization that only LightInventory holds. Changing one entry breaks the chain from that point on. Because the key is secret, nobody can quietly recompute the codes after an edit.
- **A copy of the chain, without values.** We keep the chain's codes, never your values, in a database table that rejects updates and deletes.
- **Daily anchors outside our database.** Once a day, a single fingerprint of every organization's latest chain position is written to a Google Cloud Storage bucket with a locked retention policy of 7 years. Once locked, that policy cannot be shortened or removed. An attacker who could change our database still could not rewrite those anchors.
- **Nightly verification.** Each night, and whenever the owner asks, we recompute the chain from your `Log` tab and compare it with our copy and the latest anchor. If anything does not match, every member sees an integrity warning and the Owner and Admins get an email.

The limit is ownership. The owner of a Google file can always edit, unlock, copy or delete it; Google does not allow anyone to be excluded. The chain cannot stop that, but it makes it visible. Google also records our app's writes under the owner's account, because we write with the owner's permission. Our `Log` records the actual team member.

## Edits made directly in the sheet

By default, your managed tabs are protected so that only the owner can edit them in Google Sheets, and editors of the file cannot share it further. An optional strict lock makes the file read-only in Google until the owner deliberately unlocks it.

Because the owner can always make changes, LightInventory also detects them. Every time the app reads your sheet, it compares each row with its stored fingerprint. A background check also runs for organizations nobody is viewing. When a row changed outside the app, the app records it with a best-effort attribution from Google's revision data, then applies your organization's policy: block the change until an Owner or Admin adopts or restores it, accept and log it, or hold it for approval. Edits to past movements or history entries are always flagged.

## Encryption and secrets

- **In transit:** all traffic uses HTTPS. Browsers are told to use HTTPS only (HSTS with preload), and our pages use a strict Content Security Policy.
- **At rest:** our database is encrypted at rest by its provider. Your spreadsheet is stored and encrypted by Google.
- **Tokens and keys:** Google refresh tokens, TOTP secrets and each organization's history keys are encrypted with AES-256-GCM using a fresh key per record. That key is in turn protected by a master key in Google Cloud KMS in London, which never leaves KMS and rotates every year. KMS runs in a separate cloud project with its own access controls, and our servers reach it without any stored long-lived credential.
- **No support access to your sheet.** There is no feature for our staff to sign in as you, and no support tool that opens your spreadsheet. Access to our production database requires two people and is logged.

## Infrastructure and subprocessors

| Provider | Role | Region |
|---|---|---|
| Supabase | Database and authentication (system data only) | London (`eu-west-2`) |
| Vercel | Application hosting and firewall; content delivery network | Functions in London (`lhr1`); global CDN |
| Google Cloud | Key management and history anchors (system data only) | London (`europe-west2`) |
| Resend | Transactional email (invites, security and billing notices) | United States |
| Stripe | Billing and payments | Not region-pinned |
| Cloudflare | DNS with DNSSEC, and the CAPTCHA on sign-in forms | Global network |

Google's Sheets and Drive APIs process your spreadsheet as your own provider. Emails we send never contain your inventory data. For providers based in the US, transfers are covered by the EU-US Data Privacy Framework with the UK Extension, or by standard contractual clauses.

Our Data Processing Agreement is designed to give customers at least 30 days' notice of a new subprocessor and a right to object. The full subprocessor list and the agreement are published at launch.

## Reporting a vulnerability

If you find a security issue, email **support@lightinventory.com** with the steps to reproduce it. Please do not access other people's data or disrupt the service, and contact us before any active testing, because our terms do not allow security testing without permission. Our contact details for security researchers are also published in machine-readable form in [security.txt](/.well-known/security.txt). A full responsible disclosure policy is published before launch.

## Status

LightInventory is preparing for launch. Before launch, the plan includes an external penetration test covering sign-in, tenant isolation, Google authorization, webhooks and spreadsheet injection, plus a full self-assessment against the OWASP Application Security Verification Standard 5.0. This page will add those independent assessments when they exist. Until then, it describes design, not certification.

See [what LightInventory stores](/help/data-and-privacy/what-we-store) for the full list, and [pricing](/pricing) for what each plan includes.
