Security

Last updated: 11th September 2026

Mediawork holds commercially sensitive material — quotes, rates, schedules and conversations about work that has not been announced. This page describes how that material is protected, in enough detail to be checked rather than taken on trust.

A penetration test tells you that on one particular day, one particular person did not find a way in. We would rather make a stronger claim: that the rules below are enforced mechanically on every single change to the software, and that a change breaking one of them cannot be released. Everything on this page is a property the build checks, not an intention.

Keeping companies apart

The risk that matters most in a product like this is not an outsider breaking in. It is one customer seeing another customer's work — a competitor's rates, an unannounced title, a rival's quote on the same job.

Every request has to establish three separate things before it does anything: who you are, which company you are acting for, and that the specific record you asked for belongs to that company. The third is the one that is easy to get wrong, and it is the one we have moved out of individual screens.

  • Ownership is declared once per kind of record — a quote, an account, a title, a job — in a single register, rather than being decided again by whoever writes each new screen.
  • The rule is enforced by the programming language itself. A record that has not been ownership-checked cannot be handed to the code that changes it: the software fails to compile. It is not a guideline a developer can forget.
  • Every change runs an automated test that attempts to reach each kind of record as seven different people — the owner; a colleague of the owner who has not been granted the relevant permission; a different site within the same company; someone working at company level rather than at one site; an unrelated company; the client on the other side of a quote; and a colleague of that client. Each must be allowed or refused exactly as declared.
  • Adding a new kind of record without adding it to that test fails the build. Coverage cannot quietly fall behind.

Permissions sit on top of that. Access is granted per company and per site, by role, and can be narrowed further to a single job — so a freelancer brought in for one project sees that project and nothing else. Where content is restricted, the people who can see it are shown to those who post it.

Signing in

  • Sign in with a passkey, with a password, or with an existing account from an identity provider such as Google, Microsoft 365 or Apple. Passwords are stored only as a bcrypt hash and are never recoverable, by us or by anyone else.
  • Single sign-on over OpenID Connect is available for companies that want it, and can be made compulsory for a verified email domain. A user arriving through it starts with no permissions until an administrator assigns a role.
  • Repeated failed sign-ins lock the account for fifteen minutes, and a separate limit applies per network address, so the same protection covers someone guessing at many accounts rather than one.
  • We do not confirm whether an email address has an account. Signing up and requesting a password reset give exactly the same response either way, and the difference is sent to the address itself — which only its owner can read.
  • Public forms are protected against automated abuse.

Passkeys and two-step verification

Both are available today, on every account and on every plan. A company can also require them.

What you can use

  • A passkey signs you in with your fingerprint, face or device PIN. It replaces the password rather than adding a step after it, so you are never asked for a code as well.
  • A passkey is tied by the browser to app.mediawork.io itself. It will not work on a site that merely looks like ours, and there is nothing to type, so there is nothing to hand over. That is what makes it the strongest option here, rather than only the quickest.
  • An authenticator app is the alternative: a six-digit code, changing every thirty seconds, from 1Password, Authy, Google Authenticator or any other.
  • We deliberately do not offer one-time codes by email or text message. A code sent to the same mailbox that can reset the password is not a second factor. The option is absent rather than switched off.
  • Setting up an authenticator produces ten recovery codes. They are shown once, stored encrypted, and each works once. Afterwards even we can only count how many are left, not read them.
  • An enrolment counts only once a code from it has been accepted. An abandoned setup never becomes a challenge someone is locked behind.

Requiring it

Nothing is demanded by default. Each company chooses between a password alone, an authenticator app or a passkey, or a passkey specifically.

  • Anyone who does not meet the requirement is sent to set it up before they can go further. Where someone belongs to more than one company, the strictest requirement applies to the whole session — so a passkey-only company's work cannot be reached by switching in from a company that requires nothing.
  • People who sign in through their own identity provider are exempt, and that is a property of the mechanism rather than a setting. Their organisation already decides what it takes to prove who they are, and it very likely demands a second factor of its own.
  • Turning the requirement on takes effect within five minutes, for the same reason ending a session does. We would rather state the number than imply it is immediate.
  • The requirement is checked wherever a request establishes who you are, not on the screens people navigate. That distinction is the whole of it: enforced in a page layout, it would have left file downloads outside the gate. A check run on every change lists every route that identifies a person, and fails the build if one neither answers the requirement nor is named with a reason for not needing to.
  • An administrator holding the specific permission can reset a colleague who has lost their authenticator and run out of recovery codes. That clears the authenticator, every passkey and every session together — half a reset would leave whoever holds the device still signed in. The administrator must prove who they are again first.

Sessions, and ending them

  • A session lasts at most 30 days from sign-in, however active it has been. Staying busy does not extend it indefinitely.
  • Separately, a session ends after a period of inactivity. Each company can set its own limit between two hours and seven days; where someone belongs to more than one company, the strictest of those applies to the whole session.
  • You can see your own active sessions — device, network address and last activity — and end any of them, or all of them at once. Changing your password ends every other session. Resetting a forgotten password ends all of them, which is what makes a reset useful after a compromise.
  • An administrator can end a colleague's sessions from the user screens, which is how a departing employee is cut off without deleting their account and the work attached to it.
  • Ending a session takes effect within five minutes rather than instantly. That is a deliberate trade for the speed of every page in the product, and we would rather state the number than imply it is immediate.
  • Some actions ask you to authenticate again even though you are already signed in: granting someone access, creating credentials that outlive the session, exporting in bulk, and changing billing. A passkey, an authenticator code or your password will answer that — whichever you hold, since somebody who signed in with Google or through their employer has no password to re-enter. Ordinary day-to-day work does not ask, because a prompt people see constantly is a prompt they stop reading.

Files you upload

  • Only known-safe file types are accepted. No file type that a browser or operating system will execute can be uploaded at all. This is checked on our servers at every point a file can enter, not only in the browser.
  • Private files — documents, message and note attachments, quote PDFs — are placed in quarantine on arrival and are not reachable by anyone, including the person who uploaded them, until they have been scanned.
  • Scanning is done with ClamAV, with virus definitions refreshed daily. A clean file is released; an infected one is deleted and recorded as such.
  • If a scan does not complete, the upload is retried, and after repeated failures it is marked as unscannable rather than being released. A file is never served on the assumption that it is probably fine.
  • Downloading a private file requires a signed-in session with permission to see it, and produces a short-lived signed link rather than a public address.

Artificial intelligence and your material

For anyone working on unreleased content this is usually the first question, so it is worth answering precisely.

  • The AI assistant is off unless a company turns it on, and it works only on your own account with a model provider. You supply your own Anthropic or OpenAI key; we hold no model-provider account of our own for it.
  • Without a key there is no assistant and nothing is sent anywhere. This is a property of how the feature is built, not a setting we promise to honour.
  • The key you supply is encrypted before it is stored.
  • We do not use customer content to train models, and we do not send customer content to a model provider on our own account.

Where your data is held

The application, the database and the file storage are all hosted in the European Union, in Ireland. Virus scanning and document rendering run in the same region. Backups are encrypted.

Address and location lookups are performed by our servers rather than by your browser, so the mapping provider never receives a request that identifies one of your users.

Encryption

  • All traffic is encrypted in transit over TLS. The application is served with HSTS, including its subdomains, so a browser will not connect to it unencrypted even once.
  • Data is encrypted at rest in the database and in file storage, the latter with AES-256.
  • Some values are encrypted a second time by the application before they are stored, so that a copy of the database alone does not yield them: the tokens for a connected calendar account, and the AI provider key described above.
  • Links in outgoing email that let someone reply into a conversation are individually signed for the one recipient and the one thread. Knowing a conversation's address is not enough to post into it.

The application in the browser

The product at app.mediawork.io is served with a strict Content-Security-Policy and the supporting headers — no framing by other sites, no content-type guessing, a restricted referrer policy, and browser features such as camera, microphone and geolocation switched off. An automated test asserts every one of those headers on every change, and the browser reports any policy violation back to us. The public marketing site you are reading now carries no accounts, no customer data and no cookies.

How we build

This is the part we would put in front of a buyer ahead of any certificate. Every change to the software must pass all of the following before it can be released:

  • Type checking, linting and an automated test suite.
  • The cross-company isolation test described above.
  • A scan of every third-party package for known vulnerabilities.
  • A scan for credentials accidentally committed, run over the entire history of the project and not merely the latest change.
  • Checks that the boundaries between layers of the software have not been crossed — for instance, that database access happens only where it is supposed to, and that internal record numbers never reach the browser.

One thing there is worth drawing out, because it is the failure we take most seriously. A check that silently stops checking reports success in exactly the same way as a clean result. So the checks themselves are checked: each one is deliberately fed something it ought to reject, and if it fails to notice, the build fails. A gate that has quietly stopped working is treated as an outage, not as a passing test.

Third-party packages are updated automatically, after a deliberate delay following each release so that a compromised or withdrawn version is not adopted the moment it appears.

The rule we hold ourselves to is that a security problem is not closed when it is fixed. It is closed when the thing that prevents it happening again exists — a compiler error, a test, or a check that runs on every change. A fix on its own only removes one instance.

Retention and deletion

Account data is retained for 90 days after deletion so that an account deleted in error, or maliciously, can be restored, and is then removed. Backups recycle within the same window. What is kept, for how long, and how to request deletion or a copy of your data are set out in full in our Privacy Policy.

Sub-processors

These are the third parties that may handle customer data in the course of running the service. We do not sell customer data, and we do not use it for advertising.

  • Vercel — application hosting, and cookieless traffic measurement.
  • PlanetScale — the database.
  • Amazon Web Services — file storage, virus scanning, document rendering and address lookup, in the eu-west-1 (Ireland) region.
  • Stripe — subscription payments. Card details are entered directly with Stripe and never reach our servers.
  • Postmark — sending and receiving email on behalf of the service.
  • Pusher — the live updates that make messages and notifications appear without reloading a page.
  • Google and Microsoft — only where a user chooses to connect a calendar, and only for the calendar Mediawork itself creates.
  • Anthropic or OpenAI — only where a company has enabled the AI assistant, and then under that company's own account and key rather than ours.

Reporting a vulnerability

If you believe you have found a security problem in Mediawork, please tell us at security@mediawork.io. Include enough detail for us to reproduce it. We will acknowledge your report within three working days and keep you informed until it is resolved.

We will not pursue legal action against anyone who reports a problem in good faith, gives us a reasonable opportunity to fix it before disclosing it publicly, and does not access, alter or delete data belonging to anyone else in the course of finding it. Please do not run automated scans or load tests against the live service. If you need an environment to test in, ask us and we will arrange one.

We do not currently run a paid bug bounty. We will credit you publicly if you would like us to.

What we do not have

A security page that lists only strengths is not much use to anyone assessing us, so here is the other side.

  • We are not certified against SOC 2 or ISO 27001. Both are on the table when a customer needs one; neither is in progress today.
  • We have not commissioned an independent penetration test. The mechanised checks described above are what we offer instead, and we would rather be judged on them than on a report with a date on it.

If you are assessing Mediawork and need something this page does not cover — a completed security questionnaire, a data processing agreement, or detail we have not published — write to security@mediawork.io and we will answer.