Security

Written for the person who has to sign off on us.

Not a list of reassuring adjectives. This is what is actually implemented, in the detail a security reviewer needs - including, at the bottom, the things we have not done yet.

bcrypt 12Password hashing
TOTPTwo-factor + recovery codes
AES-256-GCMCredentials at rest
OIDC + SCIMEnterprise identity

Account access

Getting in is the part attackers try first.

Everything here is enforced on the server, and the thresholds are yours to set rather than ours to assume.

Passwords are hashed, never stored

Passwords are put through bcrypt with a deliberately slow work factor. Nobody, including us, can read a stored password or reverse it.

bcrypt · work factor 12

Your password policy, not ours

Minimum length, uppercase, number and special-character requirements, and an expiry period, are all set by your administrator and enforced on every change.

Configurable: length · case · digit · symbol · expiry

Accounts lock themselves

After a set number of failed attempts the account locks for a period you choose, so guessing a password one try at a time stops being viable.

max failed attempts → timed lockout

Login attempts are rate limited

Sign-in and registration sit behind a rate limiter with a window and ceiling you control, applied before any password is even checked.

window + max, applied to /login and /register

Sessions expire

Sessions are signed tokens with a fixed lifetime, and the idle timeout is an administrator setting rather than a fixed value.

signed session tokens · configurable timeout

Every session can be revoked at once

Each identity carries a version number checked on every single request. Reset a password or force a logout and every existing session everywhere stops working immediately.

token_version compared to the database per request

Two-factor authentication

A password on its own is one thing to steal.

Time-based codes from any standard authenticator app, with recovery codes so a lost phone is an inconvenience rather than a lockout.

Standard authenticator apps

Google Authenticator, Microsoft Authenticator, 1Password, Authy - anything that speaks TOTP. Enrolment is a QR code scan.

TOTP · QR enrolment · 30-second codes

Tolerant of clock drift

Codes are accepted one step either side of the current window, so a phone whose clock is slightly out does not lock somebody out.

±1 step (30 seconds) drift allowed

The secret is encrypted at rest

The shared secret behind your codes is encrypted in the database and never returned to the browser again after enrolment.

AES-256-GCM · never re-served to the client

Recovery codes

A set of single-use backup codes is issued at enrolment. Each works exactly once and is consumed as it is used.

one-time consume · remaining count tracked

Administrators can reset it

If somebody loses their device entirely, an administrator can reset their second factor rather than the account being stranded.

admin-initiated 2FA reset

Enforceable across a tenant

Two-factor can be required rather than offered, so it is not left to whoever remembers to switch it on.

forced enrolment available

Enterprise identity

Or skip our login entirely.

If you run an identity provider, use it. Both of these are switched on per tenant and change nothing for tenants that do not use them.

Single sign-on over OIDC

Sign in through your own identity provider using the Authorization Code flow with PKCE. Tokens are verified against the provider's published keys.

OIDC · PKCE · JWKS-verified · state + nonce

No hand-rolled token checks

Discovery, key verification and token validation are handled by the standard OpenID client library rather than by code we wrote ourselves.

standard openid-client implementation

Automatic user provisioning

SCIM 2.0 lets your directory create, update and deactivate users here automatically, so leavers lose access without anyone remembering.

SCIM 2.0 · per-tenant bearer token · owner-gated

Your data

Credentials are the crown jewels, so they are treated that way.

Every third-party credential the platform holds is encrypted before it touches the database, with a per-value initialisation vector and an authentication tag that makes tampering detectable.

Authenticated encryption at rest

Stored secrets use AES-256-GCM. Each value gets its own random initialisation vector, and the authentication tag means altered ciphertext fails to decrypt rather than silently returning nonsense.

AES-256-GCM · per-value IV · auth tag

What is encrypted

Salesforce credentials, the Circularo API token, storage keys, SMTP and email-provider keys, and two-factor secrets. None of them are readable in the database.

SF · Circularo · storage · SMTP · 2FA secrets

Secrets are masked on the way out

Reading a configuration back never returns the secret itself. The interface shows that a value is set, not what it is.

GET responses mask · edits preserve

Tenants are scoped, always

Every query is scoped to the tenant it belongs to. Templates, rules, connections and documents cannot be reached from another tenant.

customer-scoped queries throughout

Parameterised queries throughout

Values never reach the database as concatenated strings, which is what closes off SQL injection as a class rather than case by case.

parameterised SQL · no string-built queries

A key change is visible, not silent

If the encryption key ever changes, affected connections show a clear warning and ask you to re-enter the credential, rather than appearing to work and failing later.

connection shows "Token unreadable"

In the browser

The headers that decide what a browser will allow.

A strict Content Security Policy is sent with every page. These are the actual directives, not a summary of them.

Strict-Transport-Security
Browsers are told to use HTTPS only for the next 180 days, including every subdomain. A downgrade to plain HTTP is refused before a request is made.
default-src 'self'
Nothing loads from anywhere but this application unless a narrower rule below allows it.
script-src 'self'
Only our own scripts run. There is no unsafe-inline, so injected script tags do not execute - the single most valuable line here.
object-src 'none'
Flash, Java and other plugin objects are blocked outright.
frame-ancestors 'none'
The application cannot be embedded in an iframe on another site, which rules out clickjacking.
base-uri 'self'
An injected <base> tag cannot redirect relative URLs to somebody else's server.
form-action 'self'
Forms cannot be made to submit to an external destination.
connect-src 'self'
Background requests can only reach this application, not an attacker's endpoint.
upgrade-insecure-requests
Any stray HTTP reference is upgraded to HTTPS automatically.

Signer protection

The document leaves your building. It should still be yours.

Once a document is out for signature, the risk moves to the recipient's inbox. These controls are set per signer, on the template, and apply every time it is sent.

One-time email codes

A signer is sent a code to their address and must enter it before the document will open. Possession of the link stops being enough.

per-signer email OTP

Per-signer passwords

The document itself can be protected with a password, typed in or read from a field on that signer's own Salesforce record so every recipient gets a different one.

manual or from a Salesforce field

It fails loudly, never quietly

If a configured password cannot be resolved for a recipient, the send is blocked with the reason. A protected document is never quietly sent unprotected.

unresolvable protection blocks the send

Signers are resolved, not typed

Recipients come from fields on the record, so a document cannot be sent to a hand-typed address that nobody checked.

resolved from record fields

Reminders without exposure

Unsigned recipients are re-notified on a schedule you set. Reminders re-notify the same verified recipient rather than creating new access.

scheduled automatic reminders

Signing stays on your account

The signature itself, its audit trail and its retention live in your own Circularo subscription, under your organisation's terms.

your Circularo account, not ours

Governance

What is kept, for how long, and who did what.

The parts that matter when somebody asks a question months later, or when a regulation says data should not be kept forever.

Retention you set

Set a retention window per tenant and generated documents and their history are purged once past it, including the stored files. Templates, connections and users are never touched.

per-tenant data_retention_days

Privileged actions are recorded

Administrative actions are written to an audit trail with who, what and when, so a change can be traced back rather than argued about.

administrative audit trail

Backups you can actually restore

Scheduled database backups run to encrypted storage with a retention period, and the restore path is written down and has been followed.

scheduled backups · documented restore

Share links expire

Links to stored documents carry an expiry rather than living forever, and documents can be kept on the Salesforce record only, with no external link at all.

time-limited links · or none at all

What we do not claim

The section most security pages leave out.

A security page that only lists strengths is not much use to somebody doing real diligence. Here is where things genuinely stand.

Current position

Everything above is implemented and in the product today. The following are not, and we would rather tell you now than have it surface in a procurement questionnaire.

  • No SOC 2 or ISO 27001 certification yet. The controls exist; the audit and the certificate do not.
  • No third-party penetration test completed. Automated dependency and code scanning run on every change, which is not the same thing.
  • Encryption keys are held by the application, not yet in a dedicated key-management service.
  • SAML is deliberately out of scope. OIDC is the protocol we support, with SCIM alongside it.

If any of these is a requirement rather than a preference, say so on the first call and we will tell you plainly whether we can meet it and when.

Send us the questionnaire.

If your security team has a standard assessment, send it over. We will answer it straight, including the questions where the answer is no.