Security

How Semhack handles your data

Plain answers to the questions agencies ask before connecting a client’s Search Console. If something here isn’t clear, email us.

Search Console access is read-only

When you connect Search Console, Semhack asks Google for one permission: read-only access to Search Console (the webmasters.readonly scope). With it, Semhack can list the properties you have access to and read their search performance data. It can’t add or remove users, change settings, submit sitemaps or request indexing.

You can revoke access at any time from your Google Account, under third-party connections. After that Semhack can’t read anything new from Search Console.

Tokens are encrypted at rest

  • Google refresh tokens for Search Console are encrypted with AES-256-GCM before they’re stored, and are never written to logs.
  • Tokens from “Sign in with Google” are stored encrypted as well.
  • The Google connection uses a short-lived, signed state value, so a connection can’t be completed for someone else’s workspace.

Nothing is installed on your websites

Semhack needs no script, tag, plugin or server access. Audits read the public pages of a site the way a browser does, identified as SemhackBot. Site audits follow robots.txt and its crawl-delay, and send only a few requests at a time.

Semhack never logs in to your sites, never submits forms and never changes anything on them. Suggested fixes, including AI drafts, are text for you to review and apply yourself.

Requests from our servers are fenced in

Audits, crawls, uptime checks and the free tools fetch addresses that users type in. Every one of those requests goes through the same protected client: only http and https on the standard ports, and any address that resolves to a private or internal network is refused at connection time, including after redirects. That stops Semhack being used to reach systems that aren’t on the public internet.

Audits, crawls and the tools are rate-limited per workspace and per visitor.

When you run a Core Web Vitals test, the page’s address is sent to Google’s PageSpeed Insights API, which loads the page from Google’s servers. Nothing else from your workspace is sent with it.

Accounts and workspaces

  • Passwords are hashed by our authentication library (Better Auth) and never stored in plain text. You can also sign in with Google.
  • Every client, audit, brief and alert belongs to one workspace, and every read and write is checked against the signed-in member’s workspace.
  • Client briefs and audit reports are only public when you share them, behind long random links (see shared links).
  • Semhack staff can open the admin console only with accounts listed in the server’s configuration, and staff actions there are written to an activity log.

Team invitations and roles

  • An invitation link carries a long random secret, works for 7 days, and can only be accepted by someone signed in with the email address it was sent to.
  • Roles are checked on the server for every change: only owners and admins invite, only owners change roles, and a workspace always keeps an owner.
  • An @mention can only reach members of the same workspace, however the comment is written.

Shared links and client emails

  • Shared briefs and shared audit reports sit behind 256-bit random links. Only someone with the link can open them, and the page is read-only.
  • Those pages tell search engines not to index them, and tell browsers not to pass the link on to other sites they link to.
  • Each audit report link can expire after 7, 30, 90 days, or last until you turn it off. A revoked or expired link stops working on the next request.
  • Unsubscribe links in client emails are signed for the one recipient they were sent to, so they can’t be changed to unsubscribe someone else. Emails also support one-click unsubscribe in mail apps that offer it.

Uploaded logos are checked and cleaned

Agency logos appear on public pages and in emails, so Semhack trusts nothing about an upload:

  • The file type is read from the file’s own bytes, never from its name. Only PNG, JPEG and SVG are accepted, up to 300 KB.
  • SVGs that contain scripts, event handlers, links to outside files or embedded content are refused. The rest are rebuilt keeping only known drawing elements and attributes.
  • Logos are served from Semhack’s own domain with a policy that stops any script from running, and are only ever shown as images.

API keys and webhooks

  • An API key is shown in full once, when it’s created. Semhack stores only a SHA-256 hash of it and the first few characters, so a key can’t be read back from our database.
  • Keys are read-only or read-and-write, can be revoked at any time, and are rate-limited. Repeated requests with wrong keys from one address are blocked for a while.
  • Webhooks are sent only to HTTPS addresses, through the same protected client as audits, so they can’t be pointed at private networks.
  • Each webhook endpoint has its own signing secret, stored encrypted (AES-256-GCM). Every delivery is signed with HMAC-SHA256 over a timestamp and the body, so your server can check it came from Semhack and reject old deliveries replayed later.

The API docs show how to check a signature.

Payments are handled by Stripe

Checkout and the billing portal are run by Stripe, so your card details never reach Semhack’s servers. Semhack stores the subscription and payment status Stripe reports back, and verifies the signature of every notification Stripe sends.

AI drafts are opt-in

AI drafts are off by default, and only offered when Semhack’s AI provider is set up. A workspace admin can turn them on and set a monthly budget. When they’re on and you ask for a draft, the facts it needs (for example the page’s title, the failing check and the page’s top Search Console queries, or the lines of a brief) are sent to Anthropic’s API to write the suggestion. Nothing is sent while the feature is off.

Our privacy policy describes how AI providers may use that data.

Reporting a security problem

If you think you’ve found a vulnerability, email hello@semhack.com with the details and how to reproduce it. Please give us a reasonable chance to fix it before telling anyone else, and don’t access other people’s data while testing. We’ll reply, keep you updated and credit you if you’d like.