Security
Everything a security reviewer asks for, on one page, including what we do not have.
BarrierOps has not yet taken on a customer, and no customer data has entered these systems. Everything below is written in the tense it is true in: what runs today is described as running, what is decided and not yet built is described as decided and not yet built, and the gaps are named rather than left for you to find.
Last reviewed 17 September 2026.
What we hold, and what we deliberately do not
We hold
- Public page content fetched from your site during a scan
- Findings, issues, occurrences and evidence events
- Screenshots and DOM snapshots of scanned public pages — in object storage, with the database holding only the key
- Your users’ names, work email addresses and their role: owner, admin, editor or viewer
- If you connect Search Console, one OAuth refresh token for that asset — encrypted with a key held outside the database, never used to sign in to anything, and revocable from the asset’s own settings. No access token is ever stored
We do not hold
- Any credential that can sign in to your site. No password, no session cookie, no SSO assertion, no basic-auth header, and no code path that authenticates to a page in order to scan it
- Authenticated-session content of any kind. Scanning is public pages only
- Card numbers. No payment processor is engaged and no payment path exists
- Source code from your repositories
- Page content from an organisation that has not verified it owns the asset. What we hold before that is the prospecting record described on our crawler page — rule identifiers, WCAG success criteria and counts, no page content
We hold no credential that can sign in to your site, and we scan public pages only. That is an architectural decision, not an omission: it means a breach of our systems does not hand anyone a route into yours. Our reading is that it also places this data in the lowest classification band of the state frameworks we have compared it against — check it against yours, and tell us if you read it differently. Any feature that would change it moves the whole product into a more expensive band, so we treat it as a constraint with a price tag.
How data moves
- A visitor loads this sitebarrierops.com, served by Cloudflare Workers static assets. The pages are static files; a form you submit goes to our API through a Cloudflare Worker that keeps nothing. Every page but the barrier-report pages and the error pages also loads Google Tag Manager and the Cookiebot cookie banner, from Google and Usercentrics, as the privacy notice describes
- A signed-in user loads the applicationapp.barrierops.com, a static single-page bundle served by Cloudflare Workers static assets
- The application calls the APIapi.barrierops.com, on a Vultr cloud instance in New Jersey
- Sign-in redirects to the identity providerWorkOS AuthKit. The application never renders a credential field and never sees a password
- The API reads and writes the databaseVultr Managed PostgreSQL 18 in New Jersey, over a connection that requires TLS
- A scan job runs in a workerA Vultr instance in New Jersey fetches your public pages. Each page is scanned in a child process the worker can kill
- Heavy artifacts are written to object storageCloudflare R2, in a bucket created in the US jurisdiction. The database stores the object key, never the bytes
- The database is backed upAutomated backups taken by the managed database provider, in the same account and the same region. There is no second copy at a different provider yet — see business continuity below
Every component above, except the two services from other companies that the marketing site loads, is in the United States: New Jersey for compute, the database and the backups, and a Cloudflare R2 bucket created in the US jurisdiction. Static hosting runs on Cloudflare’s global edge and holds nothing at rest.
Where data lives
The two stores that will hold customer data are both in the United States. The database is Vultr Managed PostgreSQL 18 in New Jersey, a region we last verified on 16 September 2026. Object storage is a Cloudflare R2 bucket created in the US jurisdiction, which we last verified on 1 October 2026.
The R2 jurisdiction is fixed when the bucket is created and cannot be changed afterwards, and it is not a location hint. Our own code refuses to start against a bucket outside it, which makes this the one residency control you can verify by reading our source rather than by believing us.
Compute is in the same place: the API and the scan worker run on Vultr instances in New Jersey, a region we last verified on 16 September 2026. Static hosting runs on Cloudflare’s global edge and holds nothing at rest, which we last verified on 21 October 2026.
The providers that are not yet in use are listed below with their state. Each one’s region is established before the account is created, because for several of them it is fixed at creation and cannot be moved afterwards — which is why it is decided first rather than audited later.
Subprocessors
11 providers. 7 are engaged today; 4 are decided or intended and not yet in use. Every row says which, and the ones that are not in use name what does not exist yet.
| Subprocessor | What it does for us | Customer data it can reach | Region | Security attestation | Region verified |
|---|---|---|---|---|---|
| Vultr | Compute for the API and the scan worker | Everything the API and the worker can reach, and their logs | New Jersey, United States — fixed at instance creation | Not yet obtained | 16 Sep 2026 |
| Vultr Managed PostgreSQL | The database of record, and its automated backups | All customer data, including the evidence ledger | New Jersey, United States — fixed at cluster creation | Not yet obtained | 16 Sep 2026 |
| Cloudflare R2 | Object storage for scan artifacts, documents, reports and exports | Screenshots, DOM snapshots, raw engine output, documents, reports and exports | US jurisdiction — fixed at bucket creation, and enforced by our own code at startup | Not yet obtained | 1 Oct 2026 |
| Cloudflare Workers | Static hosting for this site and for the application, DNS, and forwarding this site’s form submissions to our API | A form submission and the IP address it came from, forwarded to our API as it arrives. Nothing is kept | Global edge. Nothing is stored at rest, so there is no region to hold data in | Not yet obtained | 21 Oct 2026 |
| WorkOS | Authentication, through its hosted AuthKit sign-in | User names, work email addresses and sign-in events | Not yet established. It is fixed when the production environment is created | Not yet obtained | In use today against a test environment only — the production environment is not created, and we have asked WorkOS in writing which region a production environment is stored in before we create one |
| Cloudflare R2 backups | The encrypted nightly copy of the database, held off Vultr | Nothing today; once in use, an encrypted copy of the database, which only a key held elsewhere can read | US jurisdiction, fixed when the bucket was created | Not yet obtained | The bucket exists and its US jurisdiction was proved on 3 October 2026, but it is empty: the nightly backup runs on a server that is not yet deployed |
| Sentry | Error tracking | Nothing today; once in use, error messages and stack traces, with scan and organisation identifiers. No cookies, request bodies or form contents | United States, fixed when the organisation was created | Not yet obtained | The organisation exists, but the services are not yet deployed with its address, so nothing is sent |
| Resend | Transactional email: report links, setup emails, verification reminders, requests to suppliers and notices of undeliverable email | Recipient addresses and message bodies, which Resend keeps for 30 days | United States, sending from US East (Virginia) — fixed for each sending domain when it is added | Not yet obtained | 20 Oct 2026 |
| Better Stack | Uptime monitoring and the public status page | Probe URLs and the responses to them. No customer data | Not yet established | Not yet obtained | One uptime monitor exists and is paused until the API is live; there is no status page yet |
| Axiom | Log storage and search | Nothing today; once in use, our services’ log lines, which carry page URLs and scan and organisation identifiers | United States (US East), fixed when each dataset was created | Not yet obtained | The account exists, but the services are not yet deployed, so no log line leaves our servers yet |
| GitHub | Source control and continuous integration | None. No customer data is in the repository or in any test fixture | Not a store of customer data, so there is no residency question to answer | Not yet obtained | 2 Oct 2026 |
This register is reviewed whenever a provider is added or changed, and at least once a year. You are told before a new provider reaches customer data, not after.
To be told when this register changes, write to us and say so. A subscription form is not built yet, and we would rather answer an email than publish a button that does nothing. The address is security@barrierops.com.
We have not yet obtained and filed each provider’s own security attestation, so this page links none of them rather than naming a report we have not read. When they are filed, each row links the provider’s own document and carries the date we read it.
Access control
- Company policy
- Multi-factor authentication is required for everyone who works here. No exceptions, no grace period.
- Company policy
- Staff roles are least-privilege and are reviewed quarterly, with the review recorded.
- Company policy
- There is no standing direct access to the production database. Access is requested, approved by a named person, time-bound and logged.
- Company policy
- Offboarding runs to a checklist with a 24-hour completion target.
- Enforced in the product
- Staff see a customer’s workspace only in a read-only session. It needs a written reason and ends after 30 minutes, every change attempted in it is refused, the organisation’s owners are emailed when it starts, and it is written to the organisation’s audit log with the staff member’s name and the reason. The API refuses every change in a read-only session. A test attempts every documented change as each staff role and checks that each one is refused and recorded.
- Enforced in the product
- Customers hold four roles — owner, admin, editor and viewer — and every API request is authorised against the caller’s role in the organisation named in the URL. The four roles are a database check constraint, not application convention.
Four of the six above are commitments by this company rather than properties of the system, and they are labelled so you can see which four to ask us to demonstrate. A vendor page that renders a policy and a build gate in the same voice is asking you to take the first on the strength of the second.
Change management and tenant isolation
- Every change to the default branch goes through a pull request, branch protection enforces that for administrators too, and continuous integration (CI) runs on every pull request and on every push to the default branch. One engineer makes every change today, so no pull request is reviewed by a second person yet.
- CI gates typecheck, lint, three test suites, an accessibility sweep of every route in Chromium, Firefox and WebKit with zero violations and no allowlist, Lighthouse thresholds, a PDF/UA-1 conformance check on the authorisation form we publish, a check that the generated API client still matches the API, and a scan of every workspace manifest and of the lockfile for dependencies this product refuses to ship.
- A committed migration is never edited. CI fails any pull request that modifies, renames or deletes one, compared against the merge base so a rename cannot slip through.
- We do not yet run an automated dependency vulnerability scan, and our deployment is not yet automated. Both are on the list; neither is claimed here until it runs.
Tenant isolation
- Every table holding customer data carries an organisation id, and the set of tenant-scoped tables is derived from the database schema by the presence of that column rather than maintained by hand.
- Every tenant query goes through a typed organisation scope that adds the predicate. A query against a tenant table written without it does not compile — the failure is found by the typechecker, not by a customer.
- The evidence ledger and the audit trail are append-only. An UPDATE or a DELETE against either one fails to compile, and the database refuses it from a trigger as well.
- A cross-tenant test seeds two organisations and asserts that reading another organisation’s resource returns 404 rather than 403, with a body identical to a genuine miss, so the response cannot be used to discover what exists. It runs in CI and cannot skip.
The GitHub App, and every permission it asks for
The GitHub App is registered with GitHub and requests exactly these four permissions and no others. GitHub shows the same permissions on the page where an installation is approved, and the App can reach only the repositories chosen there.
The settings screen in BarrierOps that starts an installation is not built yet. Until it is, we send an Admin or Owner of your organisation the link that starts one.
| Permission | Level | Why it is needed |
|---|---|---|
| Checks | read and write | To create and complete the check run on a pull request |
| Contents | read | To read the files a pull request changed, so an annotation can point at one |
| Pull requests | read and write | To post one summary comment and update it in place |
| Metadata | read | Required by GitHub for any App. It grants no additional access |
Webhook events it acts on: pull_request (opened, synchronize, reopened) · check_run (rerequested) · installation
We do not store your source code. A check reads .barrierops.yml from the default branch. It reads a file the pull request changed only to confirm that the line a finding points at exists, and then discards it. From a repository it keeps only what its report shows: the settings in .barrierops.yml, the repository and branch names, the commit, the pull request number, and the path and line of each finding it places in a file.
We do not build your application. A check scans an address your own pipeline already publishes, such as a preview deployment or a staging address. The address must be on a domain your organisation has verified it owns. Building arbitrary customer code in our infrastructure is a security surface we are not taking on.
Encryption, retention and deletion
| Control | What is true today |
|---|---|
| In transit | HTTP Strict Transport Security is sent on this site and on the application, with a two-year max-age covering subdomains. We have not yet pinned a minimum TLS version in configuration, so we do not claim one. |
| At rest | The database and object storage are encrypted at rest by their providers. That is their control rather than ours, so it is theirs to attest, and we have not yet obtained and read any provider’s attestation — the register says so for each one. |
| Scan artifacts | Not deleted. A retention job is not built yet. When it is, the default period and what each edition can change about it are published here before it runs. |
| Evidence events | Never deleted. The table refuses UPDATE, DELETE and TRUNCATE at the database, it has no foreign key that a cascade could travel along, and its partitions carry no retention setting. All of it is asserted by tests. |
Portability and deletion
- The evidence ledger is hash-chained, and the chain verifies with your own tools. It does not depend on us being here for you to check it, which is the point of building it that way.
- Any member of an organisation can export all of it as one archive, from Data, exports and imports in the organisation’s settings, with no support ticket. The archive is JSON: every asset’s issues, occurrences, documents, scan history and evidence ledger with its hashes, plus vendor products, the audit trail and every finished report. Deleted assets are not in it.
- Deleting an asset marks it deleted and removes nothing: its pages, documents and issues are retained, and the deletion can be undone by us.
- Evidence is never deleted automatically, never by cascade, and never as a side effect of deleting an asset. Deleting it at all requires written instruction from an organisation owner.
- Account deletion as a documented process — a grace period, a final export, a written confirmation — is not built and not written down yet. Ask for the contract term instead; we will send you the clause before you sign.
Business continuity
- Automated backups of the production database are taken by the managed database provider, in the same account and the same region as the cluster.
- A second copy at a different provider is set up and not running yet: its bucket exists, in the US jurisdiction, and stays empty until the server that writes the nightly copy is deployed. Until it runs, a failure that took the provider account would take the backups with it, and we would rather you read that here than discover it in an incident.
- We publish no Recovery Time Objective (RTO) and no Recovery Point Objective (RPO), because we have not yet exercised a recovery against production. The restore test has run once, on a local copy, and that is not the same evidence. When the first production restore runs, the date, how long it took and what it recovered are published on this page — including the parts that did not go well.
A recovery target nobody has exercised is a number, not a control. If a vendor shows you one with no date beside it, that is a fair thing to ask them about — including us.
Compliance status
| Item | Status |
|---|---|
| SOC 2 Type II | Not audited. We will not claim it before the report exists. |
| GovRAMP Snapshot | Not submitted. If your solicitation requires one, tell us and we will say whether we can meet the timeline. |
| Third-party penetration test | Not yet commissioned. It is scoped — the API, the public portal, the scanning worker’s handling of hostile third-party HTML, and tenant isolation — and it runs before the first customer’s data enters the system. When it does, the date and the scope are published here, and nothing about the findings beyond the fact that they were remediated and when. |
| Higher Education Community Vendor Assessment Toolkit (HECVAT), lite | Not completed yet. Send us yours and we will fill it in; a security questionnaire we have answered once is a document we should be publishing, and that is what this page is for. |
| Our own accessibility conformance report | Not published yet — the same answer this page gives everywhere else. Our conformance report, our accessibility statement and our dated remediation plan are named on our about page with what each will contain. What runs today is the automated gate set, and it is described there too. |
At this contract size the procurement vehicle usually does not require SOC 2. What it does require is a straight answer, and this is ours: we are not SOC 2 audited, and we have not yet taken on a customer. What we have is this page, the subprocessor register with the date each region was verified, the data-flow list, and the residency control you can read in our source. If your policy requires an audited report, tell us now rather than at contract stage.
Who we are, how the company is registered and what we refuse to build are on our about page, and every price is on the pricing page rather than behind a form.
Reporting a vulnerability
security@barrierops.com — and /.well-known/security.txt names the same address.
- We acknowledge within 1 business day and either fix it or explain why we will not.
- In scope: barrierops.com, app.barrierops.com, api.barrierops.com and our crawler’s behaviour on your site.
- Out of scope: denial of service, physical and social engineering, and reports generated by a scanner with no demonstrated impact.
- We will not pursue you for research carried out in good faith within that scope, and we will credit you if you want to be credited.
- There is no bounty. We say so rather than implying one.
- Our full disclosure policy states the scope, the rules of engagement, safe harbour and every window — the triage decision follows within 5 business days. Read the vulnerability disclosure policy.
Support hours
| What | The number |
|---|---|
| Support hours | 09:00–17:00 US Eastern, Monday to Friday, excluding US federal holidays |
| Response target inside hours | 1 business day for a normal request; 4 business hours for a service outage |
| Outside hours | No rotation: one engineer is paged for an outage or a failed integrity check of the evidence ledger, on a best-effort basis with no response target — automated acknowledgement of email is not built yet, so a message sent overnight is read in the morning |
| Barrier-report service level | 5 business days by default, configurable per organisation, computed against your jurisdiction’s business calendar — the barrier portal is specified and not yet built |
These are deliberately all business-day based, so the support hours, the response targets and the barrier-report service level cannot contradict each other. The support-hours line above is the same string as the one on our about page — one constant, two renderings, checked by a test.
Our crawler
Our crawler sends BarrierOpsBot/1.0 (+https://barrierops.com/bot) and nothing else. What it fetches, how to slow it down, how to block it entirely and how to reach a person about it are on our crawler page, which is the address inside that string.
Questions reviewers ask
Can you sign our data processing agreement or security addendum?
Send it and we will read it and mark it up rather than refuse it on principle. We are a small company and we do not have the leverage to insist on our own paper, which works in your favour. What we will not do is sign a term we cannot meet — if your addendum requires an audited report or a control listed above as not yet built, we will say so before you send it to your attorney rather than after.
Does any of our data leave the United States?
The database and object storage are both in the United States and neither is configurable away from it: the object-storage jurisdiction is fixed when the bucket is created, and our own code refuses to start against a bucket outside it. Static hosting runs on a global edge and holds nothing at rest. The one open question is our identity provider, whose production environment is not created yet; it will be created in a US region, and that is stated above as pending rather than as done.
What happens on a breach, and within what notice period?
We tell you without undue delay and in any case within 72 hours of becoming aware, with what we know at the time rather than after an internal review has tidied it. The notice names what was reached, what was not, and what we have done. We have not had one, and we have not yet been through a rehearsal of this, which is a gap rather than a reassurance.
Do you support single sign-on and SCIM provisioning?
Single sign-on through your own identity provider is how the product is built to work, and it is priced as an add-on per connection rather than bundled, because the identity provider charges us per connection. Neither the connection flow nor SCIM provisioning is available to a customer yet. If single sign-on is a requirement of your solicitation, ask us for the current state before you score it.
Will you share penetration test results?
There is no test to share yet — it is commissioned before the first customer’s data enters the system. When there is, you get the date, the scope and confirmation that the findings were remediated. You will not get the report itself, and no vendor should hand you one: it is a map of the systems your own data will sit in.
Can we run our own security or accessibility test against the product?
Yes, against your own organisation in the product, and you do not need to ask permission to run an accessibility test or a keyboard test — several states instruct procurement officers to do exactly that before scoring a bid, and we would rather you did. For load testing or an authenticated security test, tell us the window first so we do not treat it as an incident, and so we can tell you which environment to point it at.
Anything this page does not answer goes to security@barrierops.com, and the answer comes back in writing. If the answer is one this page should have carried, it ends up here.