Security policy
This page is SECURITY.md from the BlastRadius repository,
rendered. Not a summary of it — the same words, held to the code by the
same tests.
BlastRadius reads terraform plan output. That is the most sensitive artefact most teams have — it names every resource, and before redaction it carries passwords, keys and connection strings in plain text. A security report about this product is therefore worth more to us than almost any feature request, and this file is written to make sending one easy.
Every claim below is meant to be true of the code in this repository today. If you find one that is not, that is itself a report worth sending, and it will be treated as a vulnerability rather than as a typo.
Reporting a vulnerability
Email security@blastradiusapp.com with BlastRadius security in the subject.
BlastRadius is a one-person operation, so that address forwards to one inbox rather than to a rota. It is monitored daily. It was a personal address until 25 August 2026 and became this one the day mail on the product domain actually delivered — an address that bounces is worse than a personal one that works.
What helps, in rough order of usefulness:
- What an attacker gets, stated as a capability — "reads another customer's findings", "posts a passing check on a plan that destroys a database", "gets a secret past redaction".
- The smallest input that shows it. A
terraform planJSON fragment is ideal; if it contains anything real, redact it yourself first — we would rather have a synthetic reproduction than your production plan. - Which of the three places it lives in: the Action (runs in your CI), the backend (runs on ours), or the GitHub App's permissions.
What to expect:
| Acknowledgement | within 3 working days |
| First assessment | within 7 working days, saying whether we agree it is a vulnerability and how severe we think it is |
| Fix or mitigation | as fast as the severity warrants; anything reaching another customer's data or forging a merge signal is dropped-everything work |
| Credit | your name in the fix's commit message and in the changelog, unless you would rather not |
There is no bug bounty. There is no money in this product yet; when there is, this line changes.
Please do not open a public issue for a vulnerability, and please give us a chance to ship a fix before writing it up. We will not ask you to sit on something indefinitely: if we have not fixed it in 90 days, publish.
Safe harbour
We will not pursue or support legal action against anyone who reports in good faith under this policy, provided you:
- test only against your own installations, your own repositories and your own plans;
- do not access, modify or retain data belonging to anyone else — if you stumble into someone else's data, stop and tell us what you saw so we can measure the exposure;
- do not degrade the service for other users (no load testing, no denial-of-service, no spam);
- do not use a finding to gain anything beyond demonstrating it.
If you are unsure whether something is in bounds, ask first.
Scope
In scope
- The Action (
packages/action) — anything that leaks a customer's plan out of their runner, executes in their runner, or exfiltrates their secrets. - Redaction (
packages/analyzer/src/redact.ts) — a secret reaching the wire that the documented mechanisms should have caught. Note the documented gaps below first. - The backend (
packages/backend) — authentication and authorisation onPOST /v1/plans, the webhook,/appand/admin; anything that crosses one installation's data into another's. - The merge gate — any way to get a
successcheck run on a plan that did not earn one, or to attach a verdict to a commit or pull request it is not for. - The rendered comment (
packages/narrator) — any way to get active markup, a link, a mention or a rewritten identifier into it from plan content.
Out of scope
- Findings you disagree with. A missed risk or a false positive is a product bug; open an issue.
- Anything requiring a compromised GitHub account, a compromised CI runner, or physical access to a developer's machine.
- Vulnerabilities in GitHub, Anthropic, Neon, Fly.io or Sentry themselves. Report those to them. If one of their behaviours makes our design unsafe, that is ours and is in scope.
- Missing hardening with no stated impact — a header, a TLS cipher preference, a version disclosure — unless you can name what it gets an attacker.
- Denial of service by volume. The service has size caps, a per-installation rate limit and a concurrency gate; a report that it can be made slow by sending it a great deal of traffic is not news.
Limits we already know about
A security policy that only lists strengths is not one. These are the gaps we have measured and decided to live with; they are documented at length in the files named, and a report that lands inside one of them is a design conversation rather than a bug — still worth sending, but you will get an argument rather than a fix.
- Redaction can miss a secret of no recognisable shape, passed under a name nobody would guess, that the plan marks nowhere. All four redaction mechanisms are name-, mark- or format-based. The full list of what redaction does not cover is in the header of
packages/analyzer/src/redact.ts, under "What this does not protect, said out loud". - Findings quote attribute values. That is what makes a review useful, and it means our database holds a description of your infrastructure. See
docs/DATA-HANDLING.md. - Anybody with write access to a repository can upload a plan for a pull request in it. That is the shape of every CI gate on GitHub. A repository can narrow it with the
workflows:key in.blastradius.yml, which pins which workflow file may report. - A browser session cannot be revoked before it expires. Sessions are a sealed cookie and there is no sessions table; the lifetime is two hours, and rotating the server's session secret signs everybody out at once.
terraform_versionis self-reported by the customer's own runner about the customer's own plan. Nothing depends on it being honest.
The security model in one paragraph
Redaction happens in your runner, before anything is uploaded — so the unredacted plan exists only in the process that produced it. What we receive is a redacted, schema-stripped document; what we keep is the findings, for thirty days. The LLM that writes the prose never sees plan JSON and never assigns a severity. Two credentials are required for every upload: a repository-scoped upload token, and a GitHub-signed Actions ID token that proves which workflow run produced the bytes. Only a CRITICAL finding blocks a merge.
The long version, with what is stored named column by column, is docs/DATA-HANDLING.md.
What we ship, and what is supported
There is one supported version: whatever is on main and deployed. The Action is distributed as a bundled, unminified file — reading it yourself is the point, since it is the code that sees your plan before anything leaves your runner.
Terraform 0.15 and newer. Older plans carry no sensitive-value marks at all, so redaction would have nothing to work from; the Action refuses those rather than uploading a plan it could not properly redact.