Diffport

Security

The safest data is the data we never asked for.

Most of this page is about what Diffport cannot reach. That is deliberate — a permission never granted cannot be misused, leaked, or subpoenaed, and it does not depend on anyone keeping a promise.

Access

What the GitHub App can and cannot do.

These are properties of the permissions requested, not rules we follow. GitHub enforces them, not us.

Granted
Read code and metadata

Diffs, commit messages, and the trailers agents leave behind. This is where provenance comes from — there is no way to do the job without reading the change.

Granted
Read pull requests and reviews

So a verdict can be attached to the pull request it belongs to, and so merge and review timing are counted rather than guessed from commit dates.

Not asked
Write access of any kind

Diffport cannot push, cannot open or merge a pull request, cannot change a branch, and cannot alter a setting on your repository. It was never requested, so it cannot be granted by accident and cannot be escalated later without you re-approving the app.

Not asked
Your database

No credentials, no connection, no copy. The schema view is reconstructed entirely from the migration files inside your pull requests, which is harder to build than reading the real thing and is the reason there is nothing to leak.

Not asked
Anything from your AI vendor

Detection reads your repository. Which agent wrote something is a fact about your commits, not an integration Diffport has to hold a key for.

Credentials

Nothing that can sign in is stored in a form you could use.

Every token in the product is kept as a SHA-256 of itself. A copy of the database hands the reader no working credential.

SecretStored asNotes
Session tokensSHA-256 Thirty day life, fourteen day idle expiry. Sign out everywhere is available.
Passwordsbcrypt Changing one signs out every session and reissues the current one.
Two-factor secretsstored, single-use codes Optional TOTP. A code that signs you in is spent and will not sign anyone else in.
Two-factor recovery codesSHA-256 Ten, each usable once. Using one emails you to say so and how many remain.
Password reset linksSHA-256 Single use, and expired links are indistinguishable from unknown addresses.
Invitation linksSHA-256 Bound to the address invited. Forwarding one does not work.
API tokensSHA-256 Shown once. The visible prefix is kept in clear so you can tell two apart.
Slack and webhook URLsstored, masked A Slack URL is a credential, so it is never rendered back to the screen in full.
GitHub App private keyon disk, 0600 Outside every web root. Anything under a domain folder is downloadable.

Sign-in is written so that a missing account and a wrong password give the same message and cost the same time — the code runs a verification against a dummy hash when no user is found, so the response cannot be timed to work out who has an account.

Boundaries

Four places where the answer is enforced, not intended.

Each of these is a control with a test behind it rather than a convention someone is expected to remember.

Tenancy

Workspaces cannot see each other

Every query that reads your data passes through a single point that narrows it to your workspace. It is one place rather than thirty-nine, because thirty-nine places is thirty-nine chances to forget.

An isolation suite seeds two tenants, calls every read method as each of them, and searches the output for the other tenant's marker. Any hit fails the build.

Enumeration

404, never 403

Asking the API for a pull request or report belonging to another workspace returns 404, not 403.

A token should not be able to confirm that an id it cannot read exists. The difference between those two answers is itself information, and it is the kind that gets collected.

Ingestion

Signed webhooks, both directions

Events arriving from GitHub are verified by HMAC signature before anything is queued. The endpoint is public because GitHub has to reach it, so the signature is the control.

Outbound alerts are signed too, with a per-destination secret over timestamp + "." + body, so a leaked URL is still not enough to forge one.

Outbound

Where Diffport refuses to send

A webhook destination must be HTTPS on port 443, carry no credentials in the URL, and resolve to a public address. Loopback, private ranges and cloud metadata addresses are refused by name when you add them.

Without that, anyone able to add a webhook could aim the server at something inside the hosting network and read back whatever answered.

Payments

No card details reach this server, ever.

There is no payment form anywhere in Diffport. Stripe hosts both the checkout and the page where you change a card.

Stored
A customer id, a subscription id, a status, a renewal date

That is the entire record. It is enough to answer whether a workspace is paid without a network call on every page load, and not enough to charge anybody.

Never stored
Card numbers, expiry dates, security codes, billing addresses

They are entered on Stripe's own pages and never transit this server. Nothing here can be breached to obtain them because nothing here has them.

Verified
Every message Stripe sends

Signature checked before it is applied, a five minute replay window, and event ids recorded before use so a retry is recognised rather than applied twice. Stripe retries by design, and applying a subscription update twice would extend a paid period for free.

Not yet

What Diffport does not have.

A security page that lists only strengths is a marketing page. These are real gaps, and if any of them is a blocker for you it is better learned here than in procurement.

Not built
SSO and SAML

Sign-in is email and password, or GitHub. There is no directory integration and no enforced domain policy.

None held
SOC 2, ISO 27001, or any audit certification

Diffport holds none, and has not been through a formal penetration test. Saying otherwise would be the first thing on this page a buyer could check and disprove.

Known
Organisation members can claim an installation

Connecting a GitHub installation requires proving through GitHub that you can reach it. GitHub reports installations a person can reach, not ones they administer — so somebody inside an organisation who can already read its repositories could bind that installation to their own workspace. They gain no access to code they could not already read. It is narrowing we have not finished.

Disclosure

Found something? Tell us before you tell anyone else.

Use the support form with enough detail to reproduce it. A person reads these, and a security report goes to the front of the queue rather than into a ticket system.

We will confirm receipt, tell you honestly whether we can reproduce it, and say when a fix ships. If it is real and it was in shipped software, it goes in the public changelog with the rest — that is where the two-factor switch, the filters wired to nothing and a password check that accepted the wrong password all ended up.

There is no bug bounty programme and no payment. Saying so up front is fairer than letting you find out after the work.