Security whitepaper

This page summarises Porticol's threat model and data flows for a security review. It names what Porticol protects, where each boundary sits and the controls on it. Each control is held in place by a test in the repository. For a shorter overview, see the security page.

What is protected

The desktop app

Signed out, with reports off, the only Porticol service the desktop app contacts on its own is the update server. Requests leave from your computer, not from Porticol's servers. Collections, environments and history are kept in one SQLite file in the data folder.

Updates

One signing key signs every update. The app reads nothing in an update manifest before its signature verifies over the bytes it fetched, refuses a manifest meant for another channel, and never offers or installs an older version than the one running. Each file's signature, and the version it was signed for, is checked before anything is replaced. Updates come only from the update server the build names, over HTTPS.

The server

Porticol Cloud and a team server are the same server in two modes. They differ in configuration, not in code.

API tokens

A token holds exactly the scopes it was made with, checked before the operation runs. An organisation's token acts in the one workspace it was made for and answers not found for anything outside it. It reaches the published API and nothing else, whatever its scopes, and stops working once the person who made it no longer administers the organisation. See the REST API reference.

Shared secrets

Shared secret values are encrypted end to end. Each desktop has an X25519 key pair whose private half never leaves it. Each workspace has a random 256-bit data key, wrapped for every device and recovery key that may read it. Values are sealed with XChaCha20-Poly1305, bound to their workspace, environment, name and key version, so a value copied anywhere else doesn't open. The server stores public keys, wrapped keys and sealed values, and nothing it holds opens any of them. When a member leaves or a device is signed out, a remaining desktop replaces the key and seals every value again in one transaction. See Shared secrets.

Requests the server sends

The server sends requests of its own for monitors, runs started on the server, SIEM export and alerts, and, when a team server's operator turns it on, for the web client. Each goes through one guard:

A customer's requests leave Porticol Cloud only in monitors and in runs started on the server through the REST API or porticol-cli --remote. Scripts in them run with time and memory limits.

The browser and the local agent

The web client is served with a content security policy that allows scripts only from its own origin. The local agent lets it send from a person's computer, and so answers only on loopback, only to a web client's origin, and only once the person at the computer has paired the browser with a single-use code. It keeps a hash of the browser's token, never the token, and serves only the commands that reach the network.

Identity

Organisations can require single sign-on over SAML or OpenID Connect for their verified domains and set a sign-in policy: a second factor, session limits, password length and allowed networks. Removing a person signs them out of every session and device. See Identity and access.

Recovery

Porticol Cloud takes an encrypted backup of its database every day, checks each one, and keeps copies away from the server. A team server takes encrypted backups on the schedule its operator sets and checks each one.

Supply chain

Dependencies are checked against security advisories on every build, and a new advisory fails it. Every parser is fuzzed on a schedule. Release builds are checksummed and come with a CycloneDX bill of materials, and the app and the team server list every third-party licence they include.

Out of scope

Report a vulnerability

Read the vulnerability disclosure policy.