Security policy
This policy says how Porticol is protected, how we handle a vulnerability report, and what we claim and what we do not claim.
It takes effect on 21 Oct 2026.
1. Reporting a vulnerability
Write to security@porticol.app. If the report is about the licence service or the licensor rather than the product, say which in the first line.
Include what you can of: the affected version (porticol-server --version), the request or
configuration that shows the problem, and what an attacker could do with it. Do not include
other people's data. If you would rather exchange an encrypted message, say so in the first
mail and a key will be sent before any details travel.
We reply within two working days, saying the report arrived and who is looking at it. We give a triage verdict in principle within ten working days: accepted with a severity, or declined with a reason. For an accepted report we publish a fix or a mitigation plan within thirty days for a high or critical finding, and an advisory once the fix has shipped. We credit you in the advisory unless you would rather not be named.
We do not treat the following as vulnerabilities on their own: a self-signed certificate on an administrator's own installation, missing security headers on an instance deliberately served over plain HTTP, and anything that needs a licence file you were not issued.
We publish a finding after a fix is available, or ninety days after the report, whichever comes first. An exception to the ninety days is agreed with the reporter in writing.
Only the newest release receives security fixes. The release notes list, for each release,
the schema version it migrates to; upgrades follow release/UPGRADE.md.
Research done in good faith under our vulnerability disclosure policy is authorised, and its safe harbour says what good faith means. We do not run a paid bug bounty; credit in the advisory is the reward.
2. What the product does with your data
- Requests you send from the desktop application leave from your machine. Our servers do not proxy them.
- The interface makes no network request and no filesystem request of its own. The packaged application's content security policy forbids both, and no plugin granting either is enabled.
- Secret values are held in your operating system's keychain, not in the application's database.
- Shared secret values are encrypted on your device before they are sent. We store the ciphertext and the keys wrapped for each enrolled device, and no key that opens them.
- Send history, saved examples and session transcripts store credentials redacted.
3. How we protect data at rest and in transit
- All traffic to Porticol Cloud uses TLS, which ends at the Caddy proxy in front of the server. A Team Server ends TLS the same way, at the Compose bundle's Caddy proxy or the administrator's own load balancer; the server itself speaks plain HTTP behind it.
- Desktop updates come from an HTTPS manifest signed with an ed25519 key, and a release is refused unless its signature, version, channel, platform and rollout bucket all agree.
- The database is encrypted at rest, and its backups are encrypted and sealed. Backups are replicated across two regions and support point-in-time recovery.
- Porticol Cloud keeps customer data in the Amazon Web Services us-east-1 region, and replicates backups to the us-west-2 region. Both are in the United States.
- The keys that protect data at rest are held in AWS Key Management Service, whose hardware security modules are validated under FIPS 140. Each data store has its own key, rotated automatically. We use no dedicated hardware security module of our own.
- Each organisation's rows are isolated by database row-level security that cannot be bypassed by the application role, and every repository method requires a scope.
4. Access control
- Role-based access control with owner, admin, editor and viewer roles, and custom roles built from a fixed permission list on plans that include them.
- Single sign-on with SAML 2.0 and OpenID Connect, with domains verified by a DNS TXT record, enforcement for members of verified domains, group-to-role mapping, and a break-glass owner login.
- A sign-in policy an organisation can enforce: two-factor authentication, session length, idle timeout, a limit on concurrent sessions, password rules, and IP allowlists.
- Accounts lock after repeated failed sign-ins, public routes are rate limited per address and per account, request bodies have size ceilings, and the source address is ignored unless a request came from a configured proxy.
- Devices are registered, named and individually revocable. Refresh tokens are held in the operating system's keychain.
5. Audit and monitoring
- Every security-relevant or data-changing action is written to a tamper-evident audit log with the actor, the time, the source address, the resource and the outcome. Altering an entry breaks the chain and the verification names the first broken entry.
- Administrators can search the log and export it. An organisation can stream its own entries to syslog, a signed JSON webhook or S3-compatible object storage.
- The server's logs are structured and hold no secret value; a leakage test sends secrets through every route and fails if one reaches a log line.
- Dashboards and alert rules are kept in the repository as code.
6. Resilience
Recovery objectives are a recovery point objective of 5 minutes and a recovery time
objective of 4 hours for Porticol Cloud. Backups are encrypted. A restore drill script
restores a backup into a scratch database, checks it against the source and fails if the
restore takes longer than the recovery time objective; operators run it whenever the
backup path changes and at least quarterly. A Team Server backs up with
encrypted backups and restores from them, following release/UPGRADE.md.
The server runs as several instances on one database, so an instance can stop during a rolling deploy without failed requests.
7. How we find and prevent vulnerabilities
- The importers, the OpenAPI, WSDL, protobuf and GraphQL parsers, the HTTP/1 and HTTP/2 response readers, the cookie and multipart parsers and the script sandbox are fuzzed every night, and a crash found there becomes a regression test.
- OWASP ZAP scans the server's API and its web client, signed in as an organisation, every night and for every version tag. A tag's update manifest and its GitHub release wait for that scan, and a high-risk alert fails it.
- Dependency advisories are checked with
cargo denyand the JavaScript audit. Every ignored advisory is triaged indeny.toml, and a new one fails the build.cargo denychecks every dependency's licence in the same run. - Every release ships a bill of materials listing what links, and the release artifacts are checksummed and signed.
- Infrastructure is defined as code and checked with a validator, a linter and a policy scanner, so a change that makes a storage bucket public fails the build.
- The threat model and the data-flow description are kept in the repository and updated by any change that adds a trust boundary.
- Every screen of the interface the end-to-end tests capture is checked in CI with axe against its WCAG 2.0 and 2.1 Level A and AA rules, with the colour checks repeated in the dark and high-contrast themes, and a serious or critical finding fails the build.
8. What we do not do
- We do not sell or share personal data for anyone else's marketing, and we run no advertising.
- We do not collect crash or usage reporting unless you turn it on, and the reports are built from names, counts and versions rather than from request content.
- We do not export traces from the server unless an operator turns it on. With no licence service configured, a server left alone makes no outbound connection of its own.
- We hold no security certification and no third-party audit report, and claim none.
- We have not commissioned an independent penetration test yet. We test Porticol ourselves, as section 7 describes: the dynamic scan of every release candidate, fuzzing of every parser, dependency and licence audits, and a written threat model.
9. Evidence
Our threat model, data-flow description, incident response plan and vulnerability
disclosure policy are in the project's security/ folder and SECURITY.md. Ask at
security@porticol.app for a copy, for a walkthrough, or for the evidence behind a claim on
this page.
If a personal data breach affects you, the notice period is in section 9 of the data processing agreement. Security reports are not personal data requests; for those see the privacy policy.
10. Contact
Security reports: security@porticol.app. General legal questions: legal@porticol.app, or {{PLACEHOLDER:LEGAL_ENTITY_NAME}}, {{PLACEHOLDER:LEGAL_ENTITY_ADDRESS}}.