> ## Documentation Index
> Fetch the complete documentation index at: https://docs.blobrouter.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Security

> How BlobRouter protects credentials and why we never store object bytes.

<Info>
  **BlobRouter v0.1** · Last updated: August 2026 · Architecture version: **2.0**
</Info>

## Security overview

BlobRouter is built so that **your object bytes never transit our servers**. The control plane decides *where* data should live and mints short-lived URLs; providers hold the data.

## Diagrams

### Audit (scanner)

```text theme={null}
BlobRouter
    │
    ▼
STS AssumeRole  (+ External ID)
    │
    ▼
Temporary credentials  (~1 hour, memory only)
    │
    ▼
Your AWS account       (read-only IAM role)
```

### Routing (presigned URLs)

```text theme={null}
Encrypted credentials  (AES-256-GCM at rest)
    │
    ▼
Decrypt in Worker memory
    │
    ▼
Mint presigned URL
    │
    ▼
Your app ↔ Provider    (bytes never touch BlobRouter)
```

## Read-only audits

The free storage audit uses a customer-created IAM role with **read-only** S3 and CloudWatch permissions. There is no PutObject, DeleteObject, or bucket mutation in the scanner policy.

See [Connect AWS](/guides/aws-iam-setup) for the exact policy.

## STS AssumeRole

For each scan, BlobRouter calls AWS STS `AssumeRole` with your Role ARN and External ID. Credentials:

* Are temporary (\~1 hour)
* Are held only in Worker memory for that job
* Are **never** written to the database

External ID prevents confused-deputy attacks across customers.

## Credential encryption (router)

When you connect S3 / R2 / B2 for routing, access keys are encrypted with **AES-256-GCM** before insert into Supabase. Decryption happens only in the Worker when generating presigned URLs. Encrypted blobs are never returned to the client.

## Data we store

* Account email, plan, API key for auth
* AWS connection metadata (account id, role ARN, external id, regions)
* Encrypted provider credentials
* File **metadata** (name, size, content type, provider, status)
* Routing decisions and savings estimates
* Usage events for metering
* Scan results and recommendations

## Data we never store

* Object bytes / file contents
* Long-lived AWS access keys for the scanner
* Plaintext router secrets at rest

## Why BlobRouter never stores object bytes

Presigned URLs mean the upload path is client → provider, not through BlobRouter. That keeps blast radius small and matches the product promise: optimize placement without hosting your files.

## Architecture security model

| Layer     | Control                                                              |
| --------- | -------------------------------------------------------------------- |
| Transport | HTTPS; HSTS in production                                            |
| API       | API keys / dashboard JWT; rate limits; security headers; request IDs |
| Scanner   | Read-only IAM + External ID + STS                                    |
| Router    | Encrypted keys + short-lived presigned URLs + private objects        |
| Product   | Explicit migration approval only                                     |

Also see [Architecture](/architecture) and [Architecture decisions](/decisions/architecture-decisions).
