Skip to content
RootSpend

Security at RootSpend

You are trusting us with keys to your bills. Here is exactly what we do with them, with the details to check it, not just promises.

  • Read only
  • Keys encrypted
  • Data walled off
  • AI on your terms
  • Every change logged
  • Yours to export or delete

We only read

RootSpend reads costs and usage. It never creates, changes or deletes anything in your tools. Here is every permission each connector asks for, word for word.

Billed by usage

Your keys stay locked up

A key is encrypted before it touches the database, and only decrypted for the moment a sync needs it.

  1. 1You paste it and can test it with a read call before you save.
  2. 2It is encrypted with Fernet: AES 128 encryption, signed with HMAC SHA256. A tampered value refuses to decrypt.
  3. 3It is stored encrypted next to your tool, never in plain text.
  4. 4It is used in memory only while a sync runs, then thrown away.
  5. 5It never comes back No screen, API, export or log returns it. AI keys show a masked hint, nothing more.
  6. 6You stay in control Replace it or disconnect the tool at any time.
  • In production, the server refuses to start without a valid encryption key, so it can never fall back to storing keys in plain text.
  • Error messages from vendors are scrubbed of every credential before anything is logged.
  • RootSpend only calls each vendor’s own addresses. For example, it won’t follow an Azure link to any host other than management.azure.com.

Your data is walled off, twice

Every request is tied to one company. The app filters by it, and the database enforces it again on its own.

Each table that holds company data has this rule, straight from our database setup. A request that doesn’t say which company it is for sees nothing at all, and a write for the wrong company is refused by the database, not just skipped by our code.

Database rule on every company table (tools shown)
ALTER TABLE tools ENABLE ROW LEVEL SECURITY;
ALTER TABLE tools FORCE ROW LEVEL SECURITY;

CREATE POLICY tenant_isolation ON tools
  USING      (org_id = NULLIF(current_setting('app.current_org_id', true), '')::uuid)
  WITH CHECK (org_id = NULLIF(current_setting('app.current_org_id', true), '')::uuid);
  • FORCE means the rule applies to RootSpend’s own database user too, not just to everyone else.
  • Background jobs, like syncs and analyses, run inside the same rule, one company at a time.

The AI analyst, on your terms

It reads a short summary of your spend and suggests savings. It never acts, and it never gets the last word on a number.

What it sees

  • Spend totals by tool, service, resource, category, team and project
  • How each total changed against the period before
  • How steady each cost is from day to day
  • How many people have spend on a tool: a count, never who

What it never sees

  • Names or emails of people
  • Raw bill lines
  • Your keys
  • Your tables, files or prompts
  • Notes your team writes, like why a finding was dismissed
What the AI receives: a shortened example with the real field names
{
  "currency": "USD",
  "period": { "start": "2026-09-28", "end": "2026-10-27", "days": 30 },
  "totals": { "spend": 18158.42, "change_pct": 4.6 },
  "tools": [
    { "id": "t1", "name": "Snowflake", "connector": "snowflake",
      "category": "Databases", "spend": 7906.10, "change_pct": 2.4,
      "people_with_spend": 14 }
  ],
  "services": [
    { "id": "s1", "tool": "t1", "name": "ANALYTICS_WH", "spend": 3120.50,
      "active_days": 30, "period_days": 30, "daily_variation_pct": 8.2 }
  ],
  "teams": [ { "name": "Data", "spend": 3688.00, "change_pct": 6.1 } ],
  "daily_spend": [ { "day": "2026-10-27", "spend": 612.40 } ]
}
  • Names from your tools are sent as data the AI is told never to follow, so text hidden in a resource name can’t give it orders.
  • The AI never writes an amount. It writes placeholders, and RootSpend fills in every figure from your data.
  • Each finding must cite the exact spend it is about. Anything that cites spend that doesn’t exist is dropped, and no saving can be bigger than what you really spend.
  • Links and markup are stripped from its answer before anyone sees it.
  • It can’t change anything in your tools. People decide, and RootSpend measures the result 14 days later.
  • AI spend is capped. Each request reserves its worst case cost before it is sent, so an allowance can’t be overrun.
  • An admin chooses RootSpend AI, your own Anthropic, OpenAI or Gemini key, or off.

Data about people is opt in

Seeing what each person costs is useful, and sensitive. So it is off until you decide otherwise.

  • Costs per person stay off until an owner turns them on for the organization.
  • Even then, only roles allowed to see people can view them. Everyone else sees teams and tools.
  • People data is never sent to the AI analyst.

Accounts and sign in

The basics, done properly.

  • Passwords are hashed with bcrypt. Nobody can read them, including us.
  • Sign in, sign up and password reset allow 5 attempts a minute from one address, which stops password guessing.
  • Your session lives in a secure, httpOnly cookie that scripts on the page can’t read. Signing out or changing your password ends it.
  • In production the sign in cookie only travels over HTTPS.
  • Roles decide who can view costs, manage budgets, connect tools or see people.

Our own access is limited, and you can see it

Sometimes we need to look at an organization to help. That access is narrow and leaves a trace.

  1. 1

    On the list

    Only emails on a list kept on the server can open the console. No button in the app adds anyone.

  2. 2

    Second factor

    A code from an authenticator app, which can’t be reused.

  3. 3

    30 minutes

    Console sessions end after 30 minutes, or when the person signs out.

  • Inside your organization, staff can only look. Anything that would change your data is refused.
  • Every visit is written to your own audit log, as platform_admin.viewed.

Every change is logged

Who did what, and when. A few of the events your audit log records:

  • tool.connected
  • tool.reconnected
  • tool.deleted
  • budget.updated
  • alert_rule.created
  • group.people_set
  • member.updated
  • invitation.created
  • ai.settings_updated
  • ai.key_deleted
  • recommendation.marked_applied
  • org.exported
  • platform_admin.viewed

Keys are never written to the audit log, not even masked.

Your data, to export or delete

It is yours. You can take it with you, or remove it for good.

  • Owners can export everything at any time: every table that holds your organization’s data.
  • The export leaves out your connector keys, and drops any field that looks like a secret.
  • Deleting an organization removes every one of those tables in one go, after you type its exact name.

This website

The site you are reading is as careful as the app.

  • No cookies, no analytics and no advertising trackers.
  • Served only over HTTPS, with strict security headers.
  • The contact form is delivered by Web3Forms straight to our inbox. We don’t add you to any list.

Report a security issue

Found something? Tell us, and we will look at it straight away.

Email hello@rootspend.com with what you found and how to reproduce it.

Or use the contact form

Questions security teams ask us

No. RootSpend only reads costs and usage. Wherever a vendor offers a read only key, role or user, that is all it asks for, and it never creates, changes or deletes anything in your tools.

No. Keys are encrypted before they are stored and are only decrypted in memory while a sync runs. No screen, API, export or log ever shows them again, so not even our own team can read them back.

Only for support, only read only, and only after passing three checks: an email on a list kept on the server, a code from an authenticator app, and a session that ends after 30 minutes. Every visit is written to your own audit log.

RootSpend never trains models on your data. The AI analyst gets spend totals only, never people, raw bills or your keys. With RootSpend AI the request goes through the provider’s business API; with your own key, your own agreement with that provider applies. An admin can switch the AI off at any time.

An owner can export everything at any time, then delete the organization. The delete removes every table that holds your data in one go, and it asks for the organization’s exact name first.

Ask us anything about security

Book a demo and bring your security questions. We will walk through every one of them, on screen.

Opening soon. The waitlist gets in first.