Security & Privacy

What data does CostSave access, collect, and store?

A complete, honest breakdown — every API call across AWS, Cloudflare, and Google Cloud, every database column, every encryption detail. No marketing language. Just facts.

Last updated: June 2026·12 min read
🔒
The short answer: CostSave only reads metadata — resource names, types, costs, and utilization metrics. We never read your S3 files, database records, application code, secrets, environment variables, KV values, R2 objects, GCS file contents, or Cloud SQL data. We never create, modify, or delete any resource on any platform.

Amazon Web Services (AWS)

How CostSave connects to your AWS account

When you click "Connect AWS Account", CostSave uses a CloudFormation template to create a cross-account IAM Role with read-only permissions in your AWS account. CostSave then calls sts:AssumeRole with an External ID unique to your account to get temporary credentials that auto-expire. No long-lived Access Keys are stored on our servers.

IAM Role via CloudFormation

The one-click CloudFormation template creates a cross-account IAM Role. CostSave stores only the Role ARN and External ID — not secret keys. Temporary credentials are fetched on demand and never persisted.

To revoke access instantly: delete the CloudFormation stack from your AWS Console. CostSave immediately loses all access.

Exact AWS API calls made during a scan

Every call below is read-only — Describe*, List*, Get*. There is no Create*, Delete*, Modify*, or Put* call anywhere in our codebase.

EC2 & EBS
ec2:DescribeInstancesec2:DescribeVolumesec2:DescribeAddressesec2:DescribeSnapshotsec2:DescribeNatGatewaysec2:DescribeNetworkInterfacesec2:DescribeVpcEndpointsec2:DescribeVpnConnections
RDS
rds:DescribeDBInstancesrds:DescribeDBSnapshots
S3
s3:ListBucketss3:GetBucketLocations3:GetBucketVersionings3:GetBucketLifecycleConfiguration
ELB / Load Balancers
elasticloadbalancing:DescribeLoadBalancerselasticloadbalancing:DescribeTargetGroupselasticloadbalancing:DescribeTargetHealth
Lambda
lambda:ListFunctions
CloudFront
cloudfront:ListDistributions
ECS / EKS
ecs:ListClustersecs:DescribeClustersecs:ListServicesecs:DescribeServiceseks:ListClusterseks:DescribeClustereks:ListNodegroupseks:DescribeNodegroup
SQS
sqs:ListQueuessqs:GetQueueAttributes
EFS
elasticfilesystem:DescribeFileSystems
WAF
wafv2:ListWebACLs
GuardDuty
guardduty:ListDetectorsguardduty:GetDetectorguardduty:ListFindings
CloudWatch & Logs
cloudwatch:GetMetricStatisticslogs:DescribeLogGroups
Cost Explorer
ce:GetCostAndUsagece:GetCostForecastce:GetAnomaliesce:GetSavingsPlansCoveragece:GetSavingsPlansUtilizationce:GetSavingsPlansRecommendations
Compute Optimizer
compute-optimizer:GetEC2InstanceRecommendationscompute-optimizer:GetEBSVolumeRecommendationscompute-optimizer:GetLambdaFunctionRecommendations
STS (Identity)
sts:GetCallerIdentitysts:AssumeRole
🔎
Verify it yourself in CloudTrail: Go to AWS Console → CloudTrail → Event History → filter by the CostSave role name. You will see exactly these calls and nothing else.

What we never access on AWS

S3 bucket contents

We call ListBuckets and check bucket configuration only. We never call GetObject on your data buckets. Your files are never read.

RDS / database data

We call DescribeDBInstances for metadata only. We have no database credentials and cannot connect to your databases.

Lambda function code

We call ListFunctions for names, runtimes, and memory settings only. We never call GetFunction which returns the code package.

Secrets Manager / Parameter Store

Zero calls to secretsmanager:* or ssm:GetParameter*. Your secrets are never touched.

EC2 user data scripts

We read instance metadata (type, state, CPU). We never call DescribeInstanceAttribute which returns user data scripts.

IAM users, roles, policies

Zero calls to iam:*. We don't enumerate your users, roles, or permissions.

Minimum AWS IAM policy required

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "CostSaveReadOnly",
      "Effect": "Allow",
      "Action": [
        "ec2:Describe*",
        "rds:Describe*",
        "s3:ListBuckets",
        "s3:GetBucketLocation",
        "s3:GetBucketVersioning",
        "s3:GetBucketLifecycleConfiguration",
        "elasticloadbalancing:Describe*",
        "lambda:ListFunctions",
        "cloudfront:ListDistributions",
        "ecs:List*", "ecs:Describe*",
        "eks:List*", "eks:Describe*",
        "sqs:ListQueues",
        "sqs:GetQueueAttributes",
        "elasticfilesystem:DescribeFileSystems",
        "wafv2:ListWebACLs",
        "guardduty:ListDetectors",
        "guardduty:GetDetector",
        "guardduty:ListFindings",
        "cloudwatch:GetMetricStatistics",
        "logs:DescribeLogGroups",
        "ce:GetCostAndUsage",
        "ce:GetCostForecast",
        "ce:GetAnomalies",
        "ce:GetSavingsPlans*",
        "compute-optimizer:Get*",
        "sts:GetCallerIdentity"
      ],
      "Resource": "*"
    }
  ]
}

Cloudflare

How CostSave connects to your Cloudflare account

You provide a read-only API token from your Cloudflare dashboard. CostSave never requests write permissions. The token is encrypted with AES-256-GCM before being stored — the same encryption used for AWS credentials.

Read-only Cloudflare API token — minimum permissions

The token needs Account Analytics:Read and Account Settings:Read permissions. No zone-level write permissions are ever requested.

To revoke access: delete the API token from Cloudflare Dashboard → My Profile → API Tokens. CostSave immediately loses all access.

Exact Cloudflare API calls made during a scan

All calls are GET requests to the Cloudflare REST API and GraphQL Analytics API. No POST, PUT, PATCH, or DELETE calls are made.

Account & Zones
GET /accountsGET /zonesGET /zones/:id/dns_recordsDNS record names, types, content — not zone file secrets
Workers
GET /accounts/:id/workers/scriptsReturns script names and metadata only — no source code
Workers Analytics
POST /graphql (workersInvocationsAdaptive)Request counts per worker — no request contents or payloads
R2 Storage
GET /accounts/:id/r2/bucketsBucket names and object counts only — no file contents
KV Namespaces
GET /accounts/:id/storage/kv/namespacesNamespace names and metadata only — no key names or values
D1 Databases
GET /accounts/:id/d1/databaseDatabase names and sizes only — no table contents or schema
Pages
GET /accounts/:id/pages/projectsProject names, last deployment date — no build artifacts
Tunnels
GET /accounts/:id/cfd_tunnelTunnel names and status — no tunnel credentials or config
Queues
GET /accounts/:id/queuesQueue names and message counts — no message contents
Load Balancers
GET /accounts/:id/load_balancers/poolsGET /zones/:id/load_balancersLoad balancer status and origin pool counts only
Analytics (GraphQL)
POST /graphql (httpRequests1dGroups)POST /graphql (r2StorageAdaptiveGroups)POST /graphql (queuesAdaptiveGroups)Aggregate counts only — no individual request details

What we never access on Cloudflare

Worker source code

We list worker script names and fetch invocation counts. We never call the script download endpoint. Your Worker code stays in Cloudflare.

R2 object contents

We count objects per bucket and fetch request metrics. We never call GetObject. Your files are never read.

KV keys and values

We list namespace names and fetch operation counts. We never enumerate keys or read values.

D1 database contents

We read database name and size. We never execute any SQL query against your D1 databases.

Worker environment variables / secrets

Zero calls to the Worker secrets API. Your environment variables and secrets are never touched.

Individual HTTP request logs

Analytics calls return aggregate counts (total requests per day). We never access individual request logs, IPs, or user data.

Google Cloud Platform (GCP)

How CostSave connects to your GCP account

You provide a Service Account key (JSON) with read-only IAM roles. CostSave uses this key to authenticate with Google APIs. The key is encrypted with AES-256-GCM before being stored — exactly the same encryption used for other platforms.

Service Account — minimum required IAM roles

The service account needs these roles at the Organization or Folder level (read-only):

  • roles/viewer — basic read access to all resources
  • roles/billing.viewer — access to billing data
  • roles/monitoring.viewer — access to Cloud Monitoring metrics

To revoke access: delete or disable the service account from Google Cloud Console → IAM & Admin → Service Accounts. CostSave immediately loses all access.

Exact GCP API calls made during a scan

All calls are read-only GET / list operations on Google APIs. No write, update, create, or delete operations are ever made.

Cloud Resource Manager
cloudresourcemanager.projects.listLists active projects accessible to the service account
Compute Engine
compute.instances.aggregatedListcompute.disks.aggregatedListcompute.addresses.aggregatedListcompute.snapshots.listVM names, types, statuses — no disk contents or VM data
Cloud Monitoring
monitoring.timeSeries.list (compute.googleapis.com/instance/cpu/utilization)monitoring.timeSeries.list (cloudsql.googleapis.com/database/network/connections)Aggregate CPU / connection metrics only — no application data
Cloud SQL
sqladmin.instances.listInstance names, tiers, and statuses — no database contents or credentials
Cloud Storage
storage.buckets.listBucket names, locations, and IAM policies — no object contents
GKE (Kubernetes Engine)
container.clusters.listCluster names, node counts, and node pool types — no workload data
Cloud Functions
cloudfunctions.functions.listFunction names, runtimes, and memory settings — no source code
Cloud Billing
cloudbilling.billingAccounts.listmonitoring.timeSeries.list (billing.googleapis.com/billing/monthly_cost)Per-project monthly cost totals only
Verify it yourself in Cloud Audit Logs: Go to Google Cloud Console → Logging → Logs Explorer → filter by your service account email. You will see exactly these API calls and nothing else.

What we never access on GCP

Cloud Storage object contents

We list bucket names and check IAM policies. We never call storage.objects.get. Your files are never read.

Cloud SQL data

We list instance metadata only. We have no database credentials and cannot connect to your Cloud SQL databases.

Cloud Function source code

We list function names, runtimes, and memory settings. We never download source code or environment variables.

VM disk contents

We read VM metadata (name, type, zone, CPU metrics). We never read disk images or snapshot contents.

Secret Manager

Zero calls to secretmanager.versions.access. Your GCP secrets are never touched.

GKE workloads / pod data

We list cluster metadata and node counts. We never connect to the Kubernetes API or read pod logs, configs, or secrets.

What we store in our database

TablePlatformWhat's storedWhat's NOT stored
aws_accountsAWSAccount label, Role ARN, External ID, AWS Account ID (12-digit)Secret keys — CloudFormation role uses temporary credentials only
cf_accountsCloudflareAccount label, encrypted API token, CF Account IDPlaintext token — encrypted with AES-256-GCM before writing
gcp_accountsGCPAccount label, encrypted service account JSON, project IDs listPlaintext service account key — encrypted with AES-256-GCM before writing
scans / gcp_scans / cf_scansAllScan timestamp, resource IDs, resource names, instance types, cost numbers, utilization metrics, recommendation flagsFile contents, database data, function code, environment variables, secrets of any kind
shared_reportsAllReport share token, expiry time (3 days), linked scan ID

How your credentials are encrypted

The same encryption scheme applies to all three platforms — AWS role credentials, Cloudflare API tokens, and GCP service account keys.

Algorithm
AES-256-GCM — authenticated encryption, industry standard
Key
256-bit server-side environment variable — never stored in the database or code
IV
Random 12-byte Initialization Vector generated fresh for every encryption — stored alongside ciphertext
Auth Tag
GCM authentication tag detects any tampering with stored ciphertext
In transit
TLS 1.2+ for all communication. Credentials are never returned in any API response after being saved.
In logs
Credentials are never logged. Log lines contain only resource counts and timing information.

Data retention

Scan results (all platforms)
Stored until you delete your account or remove the connected account from CostSave
Credentials (all platforms)
Deleted immediately when you remove an account from CostSave
Shared reports
Automatically expire after 3 days
Your account data
Permanently deleted when you use "Delete Account" in Settings → Danger Zone