Security
A plating shop's database holds its customers, its prices, its employees' hours and the records an auditor or an inspector will ask for. This page describes, specifically, how the hosted Amp-Hour service protects it. Everything here describes the software as deployed; when the software changes, this page changes.
- Architecture
- Encryption in transit
- Encryption at rest
- Authentication
- Sessions
- Rate limiting and lockout
- Access control
- Audit and security event logs
- Backups
- Vulnerability disclosure
- Incident response
- Security reviews
- Subprocessors
- What we do not do
1. Architecture
Amp-Hour is one server process written for Node.js with no third-party packages: the HTTP server, the database driver and the cryptography are the ones built into Node. There is no framework, no package registry dependency and no build step, so there is no supply chain of other people's code to audit or to be surprised by.
Each shop has its own SQLite database file. Accounts, shop memberships, sessions and subscriptions live in a separate platform database that holds no shop records. When you are signed in to a shop, every query the server runs for you is run against that shop's file and no other: there are no shared tables of shop data, so a bug in a query or a mistake in a filter cannot return another shop's jobs, customers or prices. A shop's file is also what its backup and its downloadable export are made from, which is why a shop can take its whole database with it.
The service runs on DigitalOcean in the United States behind the Caddy web server, which terminates TLS and forwards requests to the application. The application container runs read-only, with no extra privileges and every Linux capability dropped except the three its start-up script needs to hand the data directory to the unprivileged application user; the only writable path is the data volume.
2. Encryption in transit
All connections use HTTPS with TLS 1.2 or 1.3; plain HTTP requests are redirected. Certificates are issued and renewed automatically by Let's Encrypt. The server sends HTTP Strict Transport Security (one year, including subdomains), so a browser that has visited once refuses to connect insecurely afterwards. Response headers also set a Content Security Policy that allows scripts only from amphour.io, forbid framing by other sites, disable content-type sniffing, limit the Referer header to our own origin, and isolate the browsing context from other origins.
Email we send travels to the mail provider over TLS. Backup copies sent off-site are uploaded over HTTPS with signed requests.
3. Encryption at rest
The databases and backups live on a DigitalOcean block storage Volume, which DigitalOcean encrypts at rest, when the service is deployed as our deployment guide prescribes. Off-site backup copies are stored in DigitalOcean Spaces object storage in a different region from the server; Spaces encrypts stored objects at rest.
Passwords are never stored; see section 4. Card numbers never reach our servers; see section 13.
4. Authentication
- Passwords must be at least 12 characters and are checked, as you type and again on the server, against a list of commonly used passwords, keyboard patterns and trivially modified versions of them, and against your own name and email address. Any characters are allowed, including spaces, so a few unrelated words make a good password.
- Password storage uses scrypt with a random per-account salt. Comparison is constant-time. Changing or resetting a password signs out every session of the account.
- Password reset is by a single-use link emailed to the account's address, valid for 2 hours. The response to a reset request does not reveal whether the address has an account, and a failed sign-in takes the same time whether or not the address exists.
- The platform console (the pages our own staff use to see and enter shops) is open only to an account whose email address is on our administrator list and has been confirmed, with two-factor authentication turned on.
- Email verification. New accounts receive a verification link valid for 72 hours. A shop cannot invite team members or start a paid subscription until its administrator's address is verified.
- Two-factor authentication (time-based one-time passwords per RFC 6238, the kind generated by Google Authenticator, Microsoft Authenticator, 1Password and similar apps) is available to every account under Settings > Security. Turning it on issues ten single-use recovery codes, shown once and stored only as hashes. Codes are accepted within one 30-second step of the current time and a code is never accepted twice. Turning two-factor authentication on or off signs out every other session and sends an email to the account.
- Shop policy. A shop can require two-factor authentication for its administrators and managers under Settings > Shop. Until an affected person enrolls, they can reach their own security settings and nothing else in that shop.
- Our own staff must have two-factor authentication turned on to use the operator console at all.
5. Sessions
Signing in sets one cookie, sid, which carries a random 256-bit session identifier. The cookie is HttpOnly (not readable by scripts), Secure (sent only over HTTPS) and SameSite=Lax (not sent on requests other sites make to us). A session ends after 7 days without use and in any case 14 days after sign-in, whichever comes first, and when you sign out.
Settings > Security lists every open session of your account with its browser, address, start and last activity, and lets you end any one of them or all but the current one. When your account signs in from a browser and address it has not used before, we email you with the time, address and browser so you can act if it was not you.
State-changing requests are accepted only from our own pages: they must carry a JSON content type that browsers will not send cross-site, and a request whose Origin header does not match amphour.io is refused.
6. Rate limiting and lockout
- Repeated failed sign-ins against a login lock it for a period and write a lockout event to the security log, which the account holder and the shop's administrators can see.
- Wrong two-factor codes are limited; after a few, the sign-in has to start over from the password.
- Every client address is rate limited on the sign-in, sign-up, password reset, verification and invitation endpoints and, more loosely, on the application as a whole. Over the limit, the server answers 429 and says when to retry.
- Verification emails can be requested at most once every 2 minutes per account.
- Uploads are bounded: attachments must be images, PDFs, text, CSV or office documents, at most 10 MB each within 2 GB per shop, must belong to an existing record, and are served for download rather than displayed unless they are images or PDFs; CSV imports are limited to 5,000 rows per upload. Request bodies are limited in size, and the server closes connections that send headers or bodies too slowly.
- Behind the reverse proxy the client address is the one the proxy itself reports, so a forged
X-Forwarded-Forheader cannot evade the limits or mislabel the security log. - The server itself accepts administrative access by key only and exposes nothing beyond the web ports.
7. Access control
Within a shop, each person has one of five roles. Administrators manage the team, billing, settings and data; managers run the shop and see financial reports; office staff handle quotes, orders, shipping and invoicing; QC signs off inspections and certificates; operators record work on the floor. Every API route declares which roles may call it, and the server enforces that on every request regardless of what the page shows: prices, job costing, pay rates, invoices, purchasing and financial reports are withheld from QC and operator logins by the server, not only by the screens. Only administrators can grant the administrator or manager role; managers add and manage office, QC, operator and portal logins. Removing a member under Settings > Team ends their access to that shop at once.
Customer portal logins are a separate kind of user. A portal user is bound to one customer record and every portal query is filtered by that customer, so they see their own quotes, jobs, shipments, certificates and invoices and nothing else. Portal users cannot reach any staff page or route. The shop switches the portal, and each part of it, on or off under Settings > Customer portal, and the server honours those switches.
Messages between staff are stored in the shop's database and are readable only by the people in the conversation; a message can be edited only by its author while they are still in the conversation, and removed by its author or a manager.
Amp-Hour staff can enter a shop for support. Doing so requires two-factor authentication, is written to the platform audit log, and is written to that shop's own security log as a visible "support access" event with the time and the operator's address, so the shop's administrators can always see when we were there and ask us why.
8. Audit and security event logs
Each shop's database carries an audit log of changes to its records: who changed what and when, visible to its administrators. Separately, the platform keeps a security event log. For your own account (Settings > Security) it shows sign-ins with address and browser, failed attempts and lockouts, password and two-factor changes, sessions you ended, exports you downloaded, invitations, promotion codes applied, and deletion requests. For a shop, its administrators and managers see the shop's events: sign-ins of its members, members added, removed or changed, every export and backup download, demo-data clears, policy changes, and every time Amp-Hour staff entered the shop.
| Log | Contents | Kept |
|---|---|---|
| Shop audit log | Record changes in the shop, by user | Life of the shop; it is part of the shop's database |
| Security event log | Sign-ins, failures, lockouts, password and two-factor changes, sessions, exports, member changes, support access, deletions | 400 days |
| Web server access log | Time, address, URL, status, user agent | 90 days |
| Platform audit log | Operator and billing actions | Life of the platform |
We review the security event log on a regular schedule for lockouts against one account from many addresses, exports at unusual hours, and support entries we cannot account for.
9. Backups
Once a day the server takes a consistent snapshot of every shop's database and of the platform database using SQLite's VACUUM INTO, which produces a clean copy without interrupting the application. Each copy is compressed and recorded in a manifest with its size and SHA-256 digest. Daily sets are kept for 30 days on the data volume and then deleted. When an off-site copy is configured, every set is also uploaded to object storage in a different region, so that a failure of the server, or its deletion, does not take the backups with it.
Every quarter we restore a backup into a scratch copy, verify its integrity and compare it with the live shop, and record the result; a backup that has not been restored is not trusted. Shops do not depend on us for this: an administrator can download the shop's complete database as one SQLite file, or any table as CSV, at any time from Settings > Data.
10. Vulnerability disclosure
If you find a security problem in Amp-Hour, we want to hear about it. Email support@amphour.io with what you found, how to reproduce it and, if you have one, a suggested fix. We acknowledge reports within 3 business days, tell you what we found when we have investigated, and tell you when it is fixed. We do not currently pay bounties; we will credit you by name if you want.
We will not take legal action against research done in good faith, which means: test against your own trial shop or an account you own, stop as soon as you have shown the problem exists, do not read, change or delete anyone else's data, do not run denial-of-service or load tests, do not use social engineering against our staff or our customers, and give us a reasonable time to fix the problem before you publish. Machine-readable contact details are at /.well-known/security.txt, and the repository's SECURITY.md says what is in scope.
11. Incident response
An incident is anything that could have exposed a shop's data to someone who should not have it. When we confirm one, we first contain it (ending sessions, rotating credentials, taking the site offline if necessary), then preserve the logs, then work out which shops and which data were involved. We notify the owner of every affected shop within 72 hours of confirming the incident, in plain words: what happened, when, what data of theirs was involved, what we did, and what they should do. We write a post-mortem for every incident and change whatever let it happen.
12. Security reviews
October 2026: an adversarial review of the authentication surface, every API route, the HTTP layer and the browser code, each finding reproduced before it was reported. Findings covered role escalation by managers, a request that could stop the server, address-based rate-limit evasion behind the proxy, financial data reaching floor logins through the API, unbounded uploads and imports, and spreadsheet-formula injection in exports. All were fixed and each is pinned by an automated test that runs with every change. We will note further reviews here.
13. Subprocessors
The companies that process data on our behalf, what each does and where, are listed in the Privacy Policy: DigitalOcean (hosting and storage), Stripe (payments), Microsoft 365 or Resend (transactional email) and GoDaddy (domain and DNS). We notify shop owners 30 days before adding one that would handle shop data.
14. What we do not do
- No analytics, advertising or tracking scripts, on the marketing site or in the application. The only JavaScript that runs is ours, served from amphour.io.
- No selling or sharing of shop data or account information.
- No training of artificial intelligence or machine learning models on shop data.
- No card numbers on our servers. Payment details go from your browser to Stripe; we hold only Stripe's identifiers for your customer and subscription.
- No support access to a shop without it being logged where the shop's administrators can see it.
- No other software on the server: no other sites, databases or tools share the machine.
Questions about anything on this page: support@amphour.io.