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

# Security and data protection

> How vikingQA isolates tenants, protects credentials, controls access and retains data.

This page describes the technical and organisational measures that protect your data. It is written
to be read alongside [How vikingQA works](/architecture/overview), which explains the architecture
these controls apply to.

## Trust boundaries

The clearest way to understand our security model is to look at where data crosses a boundary and
what protects it at each crossing.

```mermaid theme={null}
flowchart TB
    subgraph you["Your organisation"]
        APP["Your application<br/>(test environment)"]
        EXT["Browser extension"]
    end

    subgraph vqa["vikingQA — EU"]
        WEB["Web application"]
        DB[("Database<br/>credentials encrypted<br/>AES-256-GCM")]
        WORK["Agent worker"]
        BR["Cloud browser"]
        SB["Execution sandbox"]
        S3[("Artifact storage")]
    end

    subgraph providers["Model providers"]
        LLM["Anthropic / OpenAI"]
    end

    EXT -->|"TLS, secrets stripped<br/>in your browser"| WEB
    WEB <--> DB
    WEB -->|"authenticated<br/>internal API"| WORK
    WORK --> BR
    BR -->|"fixed IP, optional"| APP
    WORK --> SB
    SB -->|"fixed IP, optional"| APP
    SB --> S3
    WORK -->|"page content + screenshots<br/>NO credentials"| LLM

    style DB fill:#0D9373,color:#fff
    style LLM fill:#f2994a,color:#000
    style S3 fill:#0D9373,color:#fff
```

The orange box is the only boundary that leaves the EU. Everything crossing it is covered in
[Compliance and subprocessors](/security/compliance).

## Tenant isolation

All data is scoped to an organisation, and that scoping is enforced in middleware — before any
application code runs.

```mermaid theme={null}
flowchart LR
    R["Request"] --> A{"Signed in?"}
    A -->|no| X1["Rejected"]
    A -->|yes| B{"Member of this<br/>organisation?"}
    B -->|no| X2["Rejected"]
    B -->|yes| C{"Access to this<br/>project?"}
    C -->|no| X3["Rejected"]
    C -->|yes| D{"Role permits<br/>this action?"}
    D -->|no| X4["Rejected"]
    D -->|yes| E["Handler runs"]

    style E fill:#0D9373,color:#fff
    style X1 fill:#eb5757,color:#fff
    style X2 fill:#eb5757,color:#fff
    style X3 fill:#eb5757,color:#fff
    style X4 fill:#eb5757,color:#fff
```

Four roles are supported, in increasing order of privilege: **Customer**, **Member**, **Admin** and
**Owner**. Sensitive operations — running tests, editing flows, changing agent configuration — are
restricted to Member and above. The role check fails closed: a malformed or missing role claim is
treated as no access rather than full access.

The internal interface used by our own agent worker is held to a stricter standard than the public
one. It derives the organisation, project and user **from the stored session record on the server**,
so the worker cannot assert which tenant it is acting for, and it re-checks organisation membership
against the database on every single call. A user removed from an organisation loses access
immediately, even mid-session.

## Credentials

Your application logins are the most sensitive data you give us, and they get the strongest handling.

```mermaid theme={null}
flowchart LR
    U["You enter a login<br/>in settings"] --> E["Encrypted<br/>AES-256-GCM"]
    E --> DB[("Stored as ciphertext<br/>no plaintext column")]
    DB --> R["Decrypted at run time"]
    R --> SUB["Substituted into the<br/>browser action"]
    SUB --> APP["Your application"]

    R -.->|"never"| LLM["Model provider"]
    SUB --> SCRUB["Result scrubbed:<br/>value → [redacted]"]
    SCRUB --> LLM

    style DB fill:#0D9373,color:#fff
    style SCRUB fill:#0D9373,color:#fff
    style LLM fill:#f2994a,color:#000
```

* **Encrypted at rest** with AES-256-GCM, using a 96-bit random initialisation vector per value and
  an authentication tag that detects tampering.
* **Separate keys for separate purposes.** The key protecting your application logins is held only by
  the web application. The agent worker holds a different key for integration tokens and cannot
  decrypt your logins with it. Compromising one does not open the other.
* **No plaintext fallback path.** The application can only read and write the encrypted form, so a
  credential cannot be stored unencrypted by mistake.
* **Never sent to a model.** The agent references credentials by name. The real value is injected
  immediately before the browser action and stripped from the result before the model or the
  database sees it.
* **Never shown back to you in full.** If a value cannot be decrypted it is reported as an error, not
  as an empty field — so a recoverable secret is never silently overwritten with a blank.
* **Destroyed on deletion.** When you delete a credential, the encrypted value is destroyed
  immediately. Secrets are not held in a recovery window, so a deleted credential cannot be restored
  — you re-enter it instead.

<Warning>
  Encryption at rest protects against disclosure of the database itself — a stolen connection string,
  a stray backup, a misconfigured replica. It does not protect against a compromised application
  server, and it cannot protect a credential once it has been typed into your application, where it
  may appear in a screenshot or a video. Scope your test accounts accordingly: use dedicated test
  users with the minimum privileges the test needs.
</Warning>

## Test execution isolation

Each test run and each agent session gets its own sandbox, identified by its owner. Sandboxes are
**never pooled across organisations** and never reused between customers. Filesystem snapshots, used
to resume a paused session quickly, are chained within a single owner — a snapshot cannot be
restored into another tenant's sandbox.

Runs are bounded by a wall-clock limit, output size caps and a per-session budget, so a runaway or
manipulated test stops on its own. Every command executed in a sandbox is logged.

## Reaching your environment

If your test environment is behind an IP allowlist, enable **fixed-IP egress** for your project.
Every browser session and test run then originates from one static address you control in your own
firewall.

This path **fails closed**. If we cannot determine your project's egress configuration, the run
fails with a clear error instead of falling back to a shared dynamic address. An allowlisted
environment is never reached from an unexpected IP because of a transient lookup failure.

## Recording safety

The browser extension records only on URLs your project administrator has explicitly allowlisted.
The allowlist is enforced twice: in your browser before capture begins, and again on our server when
the recording is submitted.

Before anything leaves your browser, the recorder strips passwords, one-time codes, card numbers,
JSON web tokens, API keys and credentials embedded in URLs. If the sanitiser fails its own start-up
self-test, recording refuses to start rather than proceeding unprotected.

## Data retention

<Note>
  Retention periods are being rolled out as described here. Contact us if you need a specific schedule
  written into your agreement.
</Note>

```mermaid theme={null}
flowchart LR
    subgraph life["Normal lifecycle"]
        direction TB
        A["Internal agent<br/>working state"] --> A1["30 days"]
        B["Run artifacts<br/>video, traces, screenshots"] --> B1["90 days"]
        C["Telemetry and<br/>diagnostics"] --> C1["90 days"]
        D["Agent conversations"] --> D1["12 months"]
        E["Test cases,<br/>scripts, results"] --> E1["Life of the project"]
    end

    life --> DEL["You delete a project,<br/>or the contract ends"]
    DEL --> Z["Deleted or returned,<br/>at your choice"]

    style Z fill:#0D9373,color:#fff
    style DEL fill:#55D799,color:#000
```

| Data                                                                            | Retained                                   |
| ------------------------------------------------------------------------------- | ------------------------------------------ |
| Run artefacts — screenshots, video, Playwright traces, console and network logs | 90 days                                    |
| Agent conversations and messages                                                | 12 months                                  |
| Internal agent working state                                                    | 30 days                                    |
| Telemetry and diagnostics                                                       | 90 days                                    |
| Test cases, scripts and results                                                 | For the life of the project                |
| Encrypted credentials                                                           | Destroyed immediately when you delete them |

Deleting a project or an organisation removes its data on the same schedule. On termination we
delete or return your data at your choice.

## Account deletion

When a user account is deleted, we remove their organisation memberships and irreversibly anonymise
their personal data — email address, name and preferences — in a single transaction. The record is
not merely flagged; the values are overwritten.

## Secrets management

All application secrets are held in a dedicated secrets manager and injected at deploy time. No
secret is stored in source control. Continuous integration receives short-scoped, read-only tokens
minted per environment, and a secret removed from the manager is actively unset from the running
service rather than left behind.

## Logging and monitoring

We use structured logging with automatic redaction of credential-shaped values — passwords, tokens,
API keys, authorisation headers and cookies are stripped before a log record is stored. Session
replay in the product interface masks all text and blocks all media by default.

## What we do not claim

We would rather you hear this from us than discover it in a questionnaire.

* **No SOC 2 or ISO 27001 certification.** We are an early-stage company and have not completed
  either audit. We are happy to answer a security questionnaire directly.
* **No independent penetration test** has been completed to date.
* **Single sign-on and enforced multi-factor authentication are not yet available.** If you need
  either, tell us — it affects our roadmap priority.
* **Row-Level Security is enabled in our database**, but as defence for the realtime subscription
  channel. Tenant isolation for the API is enforced in the application layer described above, and
  that is where you should focus a review.

## Reporting a vulnerability

Email **[security@vikingqa.io](mailto:security@vikingqa.io)**. Tell us what you found and how to reproduce it. We will confirm
receipt within two business days. We will not pursue legal action against good-faith research that
respects customer data and avoids service disruption.
