Security at ChemLevel
What ChemLevel stores on behalf of a water utility, where it lives, who can reach it, and what it does not yet do.
Last updated: October 31, 2026
1. The data is more sensitive than an inventory app sounds
For each site, ChemLevel holds the plant’s name and address, and every chemical on site and how much of it. It also holds chlorine cylinder counts and weights, current levels and usage history, confirmed delivery dates, delivery days and site hours, supplier contacts, and operator names.
Together, this shows how much chlorine gas sits at a named plant with a known address, and when the next truck arrives. That is the kind of information covered by risk and resilience assessments under AWIA §2013. Many states exempt it from public-records disclosure because it helps an attacker choose a target.
Bringing this data together is what the product is for. A forecast cannot be produced without it. Review it as operational security information, not as ordinary business software data, and apply your own classification and retention rules to it.
2. What is in place
Tenant isolation. Row-level security is enabled on every table, without exception. Access is decided in the database, not in the app, so a client-side mistake cannot expose another organization’s rows. Privileged operations run through procedures that check membership of the site or organization before doing anything.
Multi-factor authentication (MFA). Every user can turn it on with an authenticator app (TOTP). The app calls it “two-factor.” Sign-in asks for a code as well as the password, and the database enforces it too. Until the code is entered, a session for an account with two-factor on can read only its own name and membership, and can change nothing. A password alone opens none of the plant’s data.
Enrollment is per person and voluntary. There are no recovery codes, so if someone loses their device, an owner or chief operator at your own organization has to clear the factor. Only another owner can clear an owner’s. Users are told this before they turn it on. Someone invited back after leaving can have it cleared before accepting. This is done by an owner or chief operator of the organization they were a member of, provided no other organization has them as a member or has invited them. Anyone else who has not joined yet goes to ChemLevel support.
Passwords and account changes. Passwords must be at least twelve characters. The app checks this as you type, and the authentication service enforces it again. Following NIST guidance, we require length and set no composition rules. New passwords are also checked against lists of known breached credentials, and refused if they appear on one. A password already exposed in someone else’s data breach cannot be reused here.
Changing an email address requires confirmation at both the old and the new address. Changing a password requires the current password and a recent sign-in. Email one-time codes are eight digits and expire after ten minutes.
Access from outside the United States. The app and this website both block connections from IP addresses outside the US. Every customer and every operator is in the US. The block stops a large share of opportunistic scanning and credential-stuffing traffic before it reaches a login form. It is one layer of defense in depth and is not a boundary, because anyone determined can route through a US address. It adds to the controls above and replaces none of them.
The block covers this page too. A reviewer outside the US cannot reach it, and should ask us for it directly. Staff who need access while traveling should contact us before they go. A corporate VPN that routes outside the country has the same effect as being abroad.
Automated abuse. The authentication service limits how many sign-in, account-creation and password-reset attempts one address can make in a few minutes. A script that posts straight to the service is slowed down even if it never loads our code. A new password that appears in a known breach is refused. There is no CAPTCHA on these screens. The one we ran turned away real people on managed networks, which is where plant staff work.
Creating an account also requires a confirmed email address before an organization can exist, so an address nobody controls cannot become a tenant. The contact form on this website has a separate, hidden trap field. A person cannot see it, focus it or reach it by keyboard, but a script fills it in. Anything that fills it is discarded.
Audit trail. Inserts, updates and deletes are recorded with the user who made them, a timestamp, and the values before and after. The record is scoped to your organization, and only your own members can read it.
Role permissions. Each person holds one of five roles. Owners hold every permission, including over other owners. Chief operators hold account authority across every plant: adding, archiving and setting up plants, invitations, removals and roles for everyone but owners, who may see budgets, billing, and clearing a member’s multi-factor enrollment. Supervisors hold plant authority at their own plants: chemicals, tanks, cylinder racks, reorder thresholds, budgets, and the operators there. Buyers handle orders, deliveries and budgets at every plant, with no setup. Operators log readings, usage, orders, deliveries and maintenance.
The roles are a ladder. A person can invite, change or remove only people below them: an owner anyone, a chief operator anyone but an owner, a supervisor only the operators at their own plants. A supervisor with full access reaches every plant and can also manage other supervisors and buyers. No one can give a role above their own.
Which plants a person can reach is a separate restriction (see below). An operator’s cost and budget figures are restricted separately again, per person, and the data export applies the same restriction.
Site access. Supervisors and operators reach only the plants given to them. Someone limited to one plant does not see the others at all. That covers their chemicals and readings, and also their names and addresses. For a utility with several plants, those are part of the same operational security picture as the inventory. A plant added later is given to supervisors and operators by hand. For operators describes the same rules for the people they apply to.
Owners, chief operators, buyers and supervisors with full access reach every plant, and account authority always comes with every plant: an owner or chief operator cannot be limited to some. A supervisor limited to some plants can assign people only to plants they can reach themselves. Only owners and chief operators can create or archive a site, since adding one changes what the organization is billed. Renaming a site is restricted to sites that person can already reach.
No one can change their own role or their own site access. The last owner or chief operator cannot leave, be removed or be given another role until someone else holds one of those roles, so an organization cannot lock itself out. Both can be changed only through procedures that enforce these rules. The underlying columns cannot be written directly, so a client cannot bypass the checks. Site access is enforced by the same row-level security described above. It applies to every route into the data, not only to the screens.
Shared devices. A tablet the crew shares can sign in as itself, set up with a one-time code from Settings › Devices. The code is eight characters, works once, expires in 30 minutes and is kept only as a hash; ten wrong codes from one address in fifteen minutes are refused. The device is an operator at its plants who sees no costs or budgets, and nobody can give it more. People unlock it with a PIN, checked on the device so it works with no signal, and the database names the person on every entry: a save from a shared device that names nobody on its roster is refused, never stored without a name. Removing the device cuts it off at once and disables its login for good.
Supplier email. When an operator chooses to send a purchase request, it opens as a pre-filled message in the operator’s own mail app. An order can also be logged without emailing anyone. The order, the PO number and the delivery address go straight from your plant to your supplier. They are never sent by, stored on or routed through ChemLevel servers.
Order confirmations are read, not kept. Lab orders can be added by pasting a vendor’s confirmation, or by choosing the PDF or CSV the vendor sent. The document is read on the device and then discarded. Only the catalog number, quantity and price are saved. There is no upload, no storage bucket and no server-side processing in that path. No copy is ever made, so there is none to delete and none in a backup. This matters because a confirmation is a purchasing document. It carries addresses, contact names, account numbers and terms that an inventory system has no use for.
Crash reporting. Crash reports are kept narrow. The setting that sends personally identifying data is off. Console output and user-interaction breadcrumbs are removed before a report is sent. Request bodies and headers are dropped. The user is reduced to an opaque identifier, and query strings are stripped from URLs.
Data portability. Any member can export the organization’s records as one file, stamped with who exported it and when. The file holds sites, chemicals, tanks and racks, every reading, usage log, order, delivery and maintenance issue, the team, and each plant’s lab orders. It covers every plant in service that the person can reach. An archived plant is left out until it is restored. For someone who may not see costs and budgets, those are left out, and the file names them as left out. The export is meant for retention schedules, records requests and leaving ChemLevel.
3. What it does not do yet
These are the gaps a reviewer would find.
No independent audit. There is no SOC 2 report and no third-party penetration test. The practices described here are our own, and no auditor has checked them. If your procurement process requires attestation, ChemLevel does not currently meet it.
Vendor concentration. ChemLevel is a small operation. There is no escrow arrangement or continuity commitment in place. The mitigation available today is the export above. You can retrieve your records at any time without our involvement. An archived plant’s records can be retrieved once it is restored.
Forecasts are advisory. ChemLevel projects when to reorder. It is not a control system or a compliance system of record, and it does not actuate anything. Operator judgment stays in the loop. Regulatory records should continue to be kept as your state requires.
4. Where it runs and who can reach it
Hosting region. The database is in AWS us-east-1, Northern Virginia. The application is served from Cleveland, Ohio (cle1). Both are in the United States, so a US-residency requirement is met without an exception.
Encryption. Data is encrypted at rest, and every connection uses TLS. Outbound email (password resets, invitations, billing notices) requires TLS and never falls back to an unencrypted connection. A message carrying a one-time sign-in link is never handed to a receiving server in plain text. If a recipient’s mail server cannot negotiate TLS, the delivery fails and we can see the failure. The message is never downgraded silently.
DNS. The DNS records for chemlevel.com are hosted by Cloudflare and signed with DNSSEC. This website and the app at app.chemlevel.com resolve through them. The links in invitation, confirmation and password-reset emails also lead to the app. A resolver that checks signatures rejects a forged address for either. The database and sign-in service is reached at our provider’s own domain, which is not signed. TLS protects that connection. A forged address cannot present a valid certificate for that domain, and the app will not connect without one.
Backups. Daily, retained for seven days.
Production access. Administrative access to the production database is limited to named personnel, protected by multi-factor authentication, and logged by the hosting provider. Row-level security separates your organization from other tenants. It does not separate your organization from that access, so as few people as possible hold it. We will name them on request.
Retention after closure. An organization becomes read-only for a thirty-day grace period when its trial ends without a plan, its subscription lapses, or its canceled plan runs out. During that time its records remain intact, its members can still read and export them, and resubscribing makes it writable again. After that, a nightly job permanently deletes the organization and everything belonging to it.
The grace period is there so that a lapsed card cannot cost a utility its records. Export before it ends, and every plant in service is in the file. An archived plant is in it only if it was restored while a plan was active. The change history is not exported at all. Individual user accounts are removed immediately on request.
5. Services we rely on
Supabase: managed PostgreSQL and authentication. Holds the operational data described above.
Vercel: serves the web application. Does not hold plant data.
Sentry: crash and error diagnostics, scoped as described above.
Resend: account and billing email only. It does not send supplier orders.
Stripe: subscription billing. Card details are handled by Stripe and never reach ChemLevel.
Expo: delivers updates and push notifications to the iPhone, iPad and Android apps. Push notifications go by way of Apple Push Notification service and Google’s Firebase Cloud Messaging, and an alert’s title and short text pass through them on the way to the phone.
Cloudflare: hosts the DNS for chemlevel.com. Holds no plant or account data.
Formspree: delivers the contact form on this website. It is not connected to the app and holds no plant data.
6. Reporting something
Send security questions, suspected vulnerabilities and incident reports to security@chemlevel.com. We acknowledge them within one business day. We provide customers with a telephone contact for urgent matters on request.
We notify affected utilities within 24 hours of confirming an incident involving their data. We email the organization’s owners and chief operators, and telephone where a number is on file. The notice states what happened, what data was involved, when it occurred and when it was discovered, what has been done, and what the utility should do. A written follow-up goes out once the cause is established.
We set that 24-hour window inside the 72 hours that CIRCIA, the federal cyber incident reporting law, gives a covered water system to report a substantial cyber incident to CISA. That duty begins when CISA’s final rule takes effect. A vendor that reports later than its customer’s own deadline makes that deadline impossible to meet.
Utilities evaluating ChemLevel can have a fuller brief, with the specific detail behind each answer above. Ask at security@chemlevel.com.