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

# Security & Privacy

> Protect sensitive data and access in self-hosted Cognee deployments.

Cognee exposes several environment variables that let you harden a self-hosted deployment for production use.
Some controls are enforced by default, while others remain permissive for local development, so you should review each setting before exposing Cognee to untrusted users or networks.

## Security Controls

<AccordionGroup>
  <Accordion title="Authentication">
    ### Require authentication for all API requests

    `ENABLE_BACKEND_ACCESS_CONTROL` is the canonical posture switch; `REQUIRE_AUTHENTICATION` is an optional override on the auth requirement alone.

    | `ENABLE_BACKEND_ACCESS_CONTROL` | `REQUIRE_AUTHENTICATION` | Effective behavior                                                                                                                        |
    | ------------------------------- | ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------- |
    | `true` (default)                | unset                    | Multi-tenant mode: per-user/dataset isolated DBs **and** API endpoints require an authenticated user.                                     |
    | `false`                         | unset                    | Single-user mode: shared DB **and** auth requirement off.                                                                                 |
    | any                             | `true`                   | Auth is forced on (useful for a single-user deployment behind a shared token).                                                            |
    | `false`                         | `false`                  | Auth off.                                                                                                                                 |
    | `true`                          | `false`                  | **Misconfiguration** — multi-tenant mode always requires auth. Cognee logs a warning at startup and forces `REQUIRE_AUTHENTICATION=true`. |

    When neither variable is set, the default is multi-tenant mode with authentication required.

    <Info>
      At startup, Cognee logs an `auth posture: ...` line summarizing the resolved decision and the reason (default, inherited from `ENABLE_BACKEND_ACCESS_CONTROL`, explicit `REQUIRE_AUTHENTICATION`, or forced on by multi-tenant mode). Use this log line to verify what is actually in effect after deployment.
    </Info>

    <Warning>
      If `ENABLE_BACKEND_ACCESS_CONTROL=true` (the default), authentication is **enforced automatically** regardless of the value of `REQUIRE_AUTHENTICATION`. Setting `REQUIRE_AUTHENTICATION=false` in this mode is ignored and a warning is logged at startup.
    </Warning>

    ### JWT token settings

    ```dotenv theme={null}
    FASTAPI_USERS_JWT_SECRET="super_secret"   # default — CHANGE IN PRODUCTION
    JWT_LIFETIME_SECONDS=3600                 # default: 1 hour
    ```

    `FASTAPI_USERS_JWT_SECRET` must be the same across all instances (e.g., all Kubernetes pods) so that a token issued by one pod is accepted by another. Use a long, randomly generated string in production and never commit the real value to version control.

    `JWT_LIFETIME_SECONDS` controls how long a bearer token or cookie remains valid before the user must log in again.

    ### Default user credentials

    When an operation runs without an explicit authenticated user, Cognee falls back to a built-in **default user** — created on first use as a superuser. This happens for SDK/library calls, and for HTTP requests when authentication is off (single-user mode). Override its credentials with:

    ```dotenv theme={null}
    DEFAULT_USER_EMAIL="default_user@example.com"   # default
    DEFAULT_USER_PASSWORD="default_password"         # default
    ```

    When `ENABLE_BACKEND_ACCESS_CONTROL=true`, HTTP endpoints require an authenticated user, so the default user is not used to serve unauthenticated requests — but SDK calls still fall back to it. Set `DEFAULT_USER_EMAIL` and `DEFAULT_USER_PASSWORD` before the default user is first created to give this auto-created superuser known credentials you can then log in with. Changing these values later does not update an existing user; update or recreate that user separately, then restart the process so Cognee reads the new environment. See [Users](/core-concepts/multi-user-mode/permissions-system/users) for the full permission model.
  </Accordion>

  <Accordion title="Data Protection">
    ### API Key Storage

    ```dotenv theme={null}
    HASH_API_KEY="False"   # default
    ```

    When `false`, API keys are stored as plaintext in the relational database.
    When `true`, each key is hashed with **SHA-256** before storage. The raw key is shown to the user only once at creation time and cannot be recovered afterward.

    <Warning>
      **Migration note:** Enabling `HASH_API_KEY` on a running system that already has plaintext API keys stored will break those existing keys immediately — the lookup hashes the incoming value and finds no match. You must either delete and re-issue all existing keys, or run a one-off migration to SHA-256-hash the existing `api_key` column values.
    </Warning>

    ### Local File System Access

    ```dotenv theme={null}
    ACCEPT_LOCAL_FILE_PATH=True   # default
    ```

    When `true`, Cognee accepts local filesystem paths as data sources (e.g., `/etc/passwd`). This is convenient for local development but dangerous when Cognee is exposed as a multi-user backend — an authenticated user could read arbitrary files that the Cognee process has access to.

    Set to `false` when running Cognee as a backend service:

    ```dotenv theme={null}
    ACCEPT_LOCAL_FILE_PATH=False
    ```

    ### Cypher Query Access

    ```dotenv theme={null}
    ALLOW_CYPHER_QUERY=True   # default
    ```

    When `true`, users can execute raw Cypher queries against the graph database (`SearchType.CYPHER`) and use natural language-to-Cypher translation (`SearchType.NATURAL_LANGUAGE`). Disable this to limit users to higher-level semantic search only:

    ```dotenv theme={null}
    ALLOW_CYPHER_QUERY=False
    ```

    ### Outbound HTTP Requests (SSRF Protection)

    ```dotenv theme={null}
    ALLOW_HTTP_REQUESTS=True   # default
    ```

    When Cognee ingests an `http(s)` URL (via `add()` → `save_data_item_to_storage`) or crawls a page, it fetches that URL **server-side**. To prevent Server-Side Request Forgery (SSRF, CWE-918), every user-supplied outbound URL is now validated before any request is made.

    `ALLOW_HTTP_REQUESTS` (default `true`) gates outbound HTTP(S) fetching. Set it to `false` to disable all remote URL ingestion — any `http(s)` URL is then rejected:

    ```dotenv theme={null}
    ALLOW_HTTP_REQUESTS=False
    ```

    Falsey values are `false`, `0`, `no`, and `off` (case-insensitive); any other value leaves outbound fetching enabled.

    When outbound requests are allowed, each URL still passes through these checks before it is fetched:

    * **Scheme** — only `http` and `https` are permitted. Other schemes (e.g. `ftp://`, `gopher://`) are rejected.
    * **Host** — the URL must contain a host, and that host must resolve. Hostless or unresolvable URLs are rejected.
    * **Resolved address** — the host is resolved and *every* resolved IP is checked. The request is blocked if any address is loopback, private, link-local, reserved, multicast, unspecified, or IPv6 site-local. This blocks internal and cloud-metadata targets such as `127.0.0.1`, `::1`, `169.254.169.254`, `10.0.0.0/8`, `172.16.0.0/12`, and `192.168.0.0/16`. IP-literal URLs (e.g. `http://[::1]`) are validated directly, so DNS-rebinding and IP-literal bypasses are also caught.

    To keep public URLs from redirecting the server to an internal address, the crawler's HTTP client runs with `follow_redirects=False` — redirects are not followed automatically.

    <Warning>
      A blocked or disabled request raises `SSRFProtectionError` (an HTTP **403** `CogneeValidationError`) instead of silently fetching the internal target. If you see this during ingestion, check that the URL is a public `http(s)` address that resolves to a routable IP, and that `ALLOW_HTTP_REQUESTS` is not set to `false`.
    </Warning>

    ### Encrypting Neo4j Aura Credentials

    When using the `neo4j_aura_dev` dataset database handler for multi-user mode, Cognee stores per-dataset Neo4j Aura database connection info in the relational database. The stored **database password** is encrypted with **Fernet symmetric encryption**; the encryption key is derived from `NEO4J_ENCRYPTION_KEY`:

    ```dotenv theme={null}
    NEO4J_ENCRYPTION_KEY="test_key"   # default — CHANGE IN PRODUCTION
    ```

    The default value `"test_key"` is intentionally insecure. Replace it with a long random string in any environment that stores real Neo4j Aura credentials.

    <Info>
      The Aura API credentials used to create or delete instances (`NEO4J_CLIENT_ID`, `NEO4J_CLIENT_SECRET`, and `NEO4J_TENANT_ID`) are read from environment variables when needed and are **not** stored in the relational database by this handler.
    </Info>
  </Accordion>

  <Accordion title="Multi-User Isolation">
    ### Dataset & Multi-User Isolation

    ```dotenv theme={null}
    ENABLE_BACKEND_ACCESS_CONTROL=True   # default
    ```

    When enabled, Cognee creates isolated storage per user + dataset combination and enforces permission checks on every read and write operation. This is the primary control for preventing cross-tenant data leakage in multi-user deployments.

    Database support requirements:

    | Layer      | Supported backends                          |
    | ---------- | ------------------------------------------- |
    | Relational | SQLite, PostgreSQL                          |
    | Vector     | LanceDB, PGVector                           |
    | Graph      | Kuzu, Neo4j Aura (`neo4j_aura_dev` handler) |

    If you configure an unsupported backend (e.g., Qdrant, Weaviate), disable access control to avoid runtime errors:

    ```dotenv theme={null}
    ENABLE_BACKEND_ACCESS_CONTROL=False
    ```

    Setting `ENABLE_BACKEND_ACCESS_CONTROL=false` alone also disables the auth requirement (single-user mode). You only need to add `REQUIRE_AUTHENTICATION` if you want to override that default — for example, `REQUIRE_AUTHENTICATION=true` to keep auth on for a single-user deployment behind a shared token.

    See [Dataset Database Handlers](/core-concepts/multi-user-mode/dataset-database-handlers/dataset-database-handlers-what-are-they) for the full list of supported handlers.
  </Accordion>

  <Accordion title="Disabling Authentication for Local Development">
    When running Cognee locally for development or testing, you can disable authentication so that API calls succeed without a bearer token. Setting the single posture switch is enough:

    ```dotenv theme={null}
    ENABLE_BACKEND_ACCESS_CONTROL=false
    ```

    With `ENABLE_BACKEND_ACCESS_CONTROL=false` and `REQUIRE_AUTHENTICATION` unset, `REQUIRE_AUTHENTICATION` inherits from the posture switch and the auth requirement is turned off automatically. (Previously, both variables had to be set to `false` independently; that is no longer required.)

    These values are read once when the server process starts, so you must restart the server after changing them. Check the `auth posture: ...` line in the startup logs to confirm the resolved decision.

    When authentication is disabled, unauthenticated requests are automatically served under a built-in default user (`default_user@example.com`). The relational database must be initialized before the first request so that this default user can be looked up or created.

    **Troubleshooting 401 errors after setting the variables**

    | Symptom                                                    | Cause                                                                                                                                       | Fix                                                                                                           |
    | ---------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
    | Still getting `401` on all endpoints                       | `ENABLE_BACKEND_ACCESS_CONTROL` is still `true`, or `REQUIRE_AUTHENTICATION=true` is set explicitly and overrides it                        | Set `ENABLE_BACKEND_ACCESS_CONTROL=false` and unset (or also set to `false`) `REQUIRE_AUTHENTICATION`         |
    | Startup log says auth was "forced on by multi-tenant mode" | `REQUIRE_AUTHENTICATION=false` is combined with `ENABLE_BACKEND_ACCESS_CONTROL=true` — an unsafe combination that Cognee coerces to auth-on | To disable auth, also set `ENABLE_BACKEND_ACCESS_CONTROL=false`                                               |
    | `401` persists after editing `.env`                        | Server not restarted                                                                                                                        | Restart the server — the variables are evaluated at import time                                               |
    | `500 Failed to create default user`                        | Relational DB not initialized                                                                                                               | Call `cognee.prune.prune_system()` once, or let the server run its startup migrations before sending requests |

    <Warning>
      Only use `ENABLE_BACKEND_ACCESS_CONTROL=false` in local or trusted environments unless you have another protection layer in place. It disables multi-user isolation, and it also disables the HTTP auth requirement unless you explicitly set `REQUIRE_AUTHENTICATION=true`.
    </Warning>
  </Accordion>
</AccordionGroup>

## Recommended Production Settings

<AccordionGroup>
  <Accordion title="Recommended Production Settings">
    ```dotenv theme={null}
    # Authentication
    REQUIRE_AUTHENTICATION=True
    FASTAPI_USERS_JWT_SECRET="<random-64-char-string>"
    JWT_LIFETIME_SECONDS=3600

    # API key security
    HASH_API_KEY=True

    # Multi-user isolation
    ENABLE_BACKEND_ACCESS_CONTROL=True

    # Prevent arbitrary file reads (set False for backend deployments)
    ACCEPT_LOCAL_FILE_PATH=False

    # Limit direct graph queries (optional — set False to restrict to semantic search)
    ALLOW_CYPHER_QUERY=False

    # Outbound URL ingestion is validated against SSRF; set False to disable remote fetches entirely
    ALLOW_HTTP_REQUESTS=True

    # Neo4j Aura credential encryption (only required when using neo4j_aura_dev handler)
    NEO4J_ENCRYPTION_KEY="<random-64-char-string>"
    ```

    <Info>
      For detailed instructions on the multi-user permission system (users, tenants, roles, and ACL), see [Cognee Permissions System](/core-concepts/multi-user-mode/permissions-system/overview).
    </Info>
  </Accordion>
</AccordionGroup>

<Columns cols={2}>
  <Card title="Permissions Setup" icon="lock" href="/setup-configuration/permissions">
    Enable dataset isolation and access control
  </Card>

  <Card title="Multi-User Mode" icon="users" href="/core-concepts/multi-user-mode/multi-user-mode-overview">
    Understand multi-tenant architecture
  </Card>
</Columns>
