Find the attack paths that matter.
Basalt reads your AWS account and your code, maps your whole platform, and shows the few paths to sensitive data, including the ones that run through your AI agents.
Your customer asks. Your graph answers.
Every question in a security review is a question about your platform. Basalt finds the answer in the graph and attaches the proof.
Can your AI agents reach customer data?
Yes. SupportBot can read s3://customer-exports through its read_file tool.
- Can your AI agents reach customer data?Yes. SupportBot can read s3://customer-exports through its read_file tool.support_bot/tools.py:8infra/iam.tf:22
- Who can assume roles in production?Any AWS account. ci-deploy trusts "AWS": "*" with no ExternalId.infra/iam/ci.tf:7
- Are credentials kept out of config?One plain-text token, in a Cursor MCP config. Its value was never stored..cursor/mcp.json:9
- Is any data store open to the internet?No. None of your data stores allows anonymous reads.bucket policies checked
One path, with the proof.
Each finding is a chain from an entry point to data, with the file, line and resource behind every step.
Path: a public Lambda function URL with no authentication exposes the function support-api, which runs the agent SupportBot; prompt injection makes it call the tool read_file; the tool uses IAM role support-bot; the role can read s3://customer-exports.
Impact
From a public function URL to read access on s3://customer-exports, tagged pii.
Cause
The role allows s3:GetObject on *, and read_file accepts any path.
Fix
Scope the policy to tickets/* and restrict the tool to one directory. Either change breaks the path.
Evidence
- infra/lambda.tf:31
- support_bot/agent.py:13
- support_bot/tools.py:8
- infra/iam.tf:22
- arn:aws:s3:::customer-exports
Impact
Production database, Stripe and OpenAI credentials, readable from any AWS account.
Cause
The trust policy of ci-deploy allows "AWS": "*" with no sts:ExternalId condition.
Fix
Name the CI account in Principal and require an ExternalId. The role keeps working for your pipeline; the path disappears.
Evidence
- infra/iam/ci.tf:7
- infra/iam/ci.tf:19
- arn:aws:secretsmanager:us-east-1:…:secret:prod/database
The fix writes itself. You approve it.
Ask the Basalt assistant to close a path. It reads the files involved, writes the smallest change that breaks the chain, and only after your yes creates a branch and opens the pull request. Never on your default branch.
data "aws_iam_policy_document" "support_bot" { statement { actions = ["s3:GetObject"] resources = ["*"] resources = ["arn:aws:s3:::customer-exports/tickets/*"] }}
from pathlib import PathROOT = Path("/srv/tickets") @tooldef read_file(path: str) -> str: """Read a support attachment.""" target = (ROOT / path).resolve() if not target.is_relative_to(ROOT): raise PermissionError(path) return open(path).read() return target.read_text()
A CLI that knows your platform.
Scan a repository on your laptop, check a branch before it deploys, or ask the assistant to fix a path. The same read-only engine everywhere.
- >_Runs locally
- ●○○Pre-deploy check
- <?>Assistant with approvals
- tf ↔ awsTerraform + live AWS
Reads configuration.
Never data.
{ "Effect": "Allow",
"Action": ["iam:GetAccountAuthorizationDetails", "s3:GetBucketPolicy", …] },
{ "Effect": "Deny",
"Action": ["s3:GetObject*", "secretsmanager:GetSecretValue",
"dynamodb:Query", "kms:Decrypt", …] }
Three ways in.
Pick the one that matches where you are this week. You can move to the next at any time.
See what's open.
A full scan of one product, every attack path with its evidence, and the fix for the first two critical ones.
Free, by waitlistPass the review.
The report and questionnaire answers your customer's security team expects, checked by our team before you send them.
One-timeStay closed.
Scans as your code changes, an alert when a change opens a path, and the fix as a pull request.
SubscriptionOne-time reviews are credited if you subscribe.
Questions we get first.
More on the security page and in the docs.
What access does Basalt need?
For AWS, a role you create that we assume with an ExternalId. It allows 14 configuration reads and explicitly denies data reads such as s3:GetObject and secretsmanager:GetSecretValue. For code, the CLI scans your repositories on your own machine; a GitHub App with read access to the repositories you pick is rolling out.
Do you read our data or store our secrets?
No. We read configuration and code structure. When AWS returns environment variable values, they are classified in memory and dropped; the value is never written, logged or sent anywhere.
Can we try it without giving you access?
Yes. The CLI runs on your machine against a repository or Terraform, and against AWS with your own credentials. Nothing leaves the machine unless you link it to an account.
Do you attack our systems?
No. Path analysis is static: it reads configuration and code and never sends traffic to your applications or agents.
How is this different from Wiz, Snyk or Aikido?
They list issues. Basalt joins your agent code, IAM and data into one graph and shows the few chains that actually reach something sensitive, at a price a startup can pay. Dependency CVEs and container scanning stay with the tools you already use.
What about false positives?
Every finding carries its evidence and a confidence level. When a condition or boundary could change the result and we can't resolve it, the step is marked uncertain instead of reported as critical.
Find your first path this week.
Join the waitlist, or talk to us if a review is on the calendar.