# How CORS Settings Are Configured in Open Notebook: Security Implications Explained

> Learn how Open Notebook configures CORS using the CORS_ORIGINS environment variable. Understand security implications and secure your production deployments.

- Repository: [Luis Novo/open-notebook](https://github.com/lfnovo/open-notebook)
- Tags: deep-dive
- Published: 2026-06-09

---

**Open Notebook configures CORS through a single `CORS_ORIGINS` environment variable parsed at startup in [`api/main.py`](https://github.com/lfnovo/open-notebook/blob/main/api/main.py), where a default wildcard allows any origin and explicit domains are required for secure production deployments.**

Open Notebook is an open-source **FastAPI** application whose cross-origin resource sharing behavior is governed by a centralized environment variable. Understanding **how CORS settings are configured** in this project is critical because the default wildcard permits any website to reach the API. This analysis walks through the exact source code in `lfnovo/open-notebook` to explain the configuration mechanics and their direct security impact.

## How CORS Settings Are Configured in Open Notebook

All **CORS** behavior in Open Notebook is centralized in [`api/main.py`](https://github.com/lfnovo/open-notebook/blob/main/api/main.py). According to the `lfnovo/open-notebook` source code, the application reads one environment variable, transforms it into a Python list, and passes that list directly to FastAPI's `CORSMiddleware`.

### Load and Parse the `CORS_ORIGINS` Variable

When the application boots, `dotenv.load_dotenv()` reads the process environment or a local `.env` file, as seen at the top of [`api/main.py`](https://github.com/lfnovo/open-notebook/blob/main/api/main.py). The helper function `_parse_cors_origins` then splits the comma-separated string into a Python list. If the value is `"*"` or the variable is missing entirely, it resolves to `["*"]`.

The parsed result is stored in `CORS_ALLOWED_ORIGINS`, and a boolean flag named `CORS_IS_DEFAULT_WILDCARD` records whether the fallback is active. During startup, the code logs a warning if the wildcard is in effect; otherwise it logs the explicit origins list.

### Install `CORSMiddleware` After Authentication

In [`api/main.py`](https://github.com/lfnovo/open-notebook/blob/main/api/main.py), `CORSMiddleware` is added after the authentication middleware so that CORS processing applies to every request. This ordering—visible when comparing the middleware registration in [`api/main.py`](https://github.com/lfnovo/open-notebook/blob/main/api/main.py) with the auth stack in [`api/auth.py`](https://github.com/lfnovo/open-notebook/blob/main/api/auth.py)—ensures that pre-flight and actual requests receive headers even on protected routes. The middleware receives `allow_origins=CORS_ALLOWED_ORIGINS`, `allow_credentials=True`, `allow_methods=["*"]`, and `allow_headers=["*"]`.

### Mirror CORS Headers in Exception Handlers

When an exception fires before the middleware can attach headers, a helper named `_cors_headers` replicates the middleware's origin-check logic and injects identical CORS headers into the error response. This maintains consistent browser enforcement for failure responses such as `413 Payload Too Large`.

## Security Implications of Open Notebook CORS Settings

The simplicity of the single-variable design creates distinct security postures depending on deployment choices.

### Risks of the Default Wildcard

When `CORS_ORIGINS` is unset, Open Notebook defaults to `["*"]`. This means any website can attempt authenticated `fetch` or `XMLHttpRequest` calls to the API. Because the configuration also sets `allow_credentials=True`, browsers will reject responses that carry both credentials and a wildcard `Access-Control-Allow-Origin` header. The server still emits the header, which leads to confusing client failures while signaling an insecure configuration.

### Explicit Origin Whitelisting

Setting `CORS_ORIGINS` to an exact domain restricts the `Access-Control-Allow-Origin` response header to that origin only. This prevents unrelated sites from reading API responses. With `allow_credentials=True` still enabled, authenticated requests are permitted exclusively from the trusted frontend.

### Startup Validation and Runtime Constraints

The `_parse_cors_origins` parser silently drops empty entries, but a malformed origin—such as one missing the `https://` scheme—will be treated as disallowed and trigger browser CORS errors. Additionally, the variable is read once at import time, so changing it requires a full application restart rather than a hot reload.

## Practical Configuration Examples

The project includes an `.env.example` file that shows the `CORS_ORIGINS` placeholder. Use the patterns below to lock down production deployments.

### Setting Allowed Origins in `.env`

Create or edit the environment file to list trusted frontends exactly.

```dotenv

# .env (or an environment variable set by your container orchestrator)

CORS_ORIGINS=https://notebook.example.com,https://admin.example.com

```

### Running the API with Docker

Pass the origin list directly when starting the container.

```bash
docker run -e CORS_ORIGINS="https://notebook.example.com" \
           -p 5055:5055 lfnovo/open-notebook:latest

```

### Calling the API from a Trusted Frontend

The following JavaScript expects the requesting page to match an origin listed in `CORS_ORIGINS`.

```javascript
fetch('http://localhost:5055/api/notebooks', {
  credentials: 'include',   // cookies / auth headers are allowed
})
  .then(r => r.json())
  .then(console.log)
  .catch(console.error);

```

If the caller's domain is absent from the whitelist, the browser blocks the response with a CORS error.

### Verifying Headers with curl

An untrusted origin receives no CORS header.

```bash
curl -I -H "Origin: https://evil.com" http://localhost:5055/api/notebooks

# No Access-Control-Allow-Origin header → request blocked by browser

```

A trusted origin receives the reflected header.

```bash
curl -I -H "Origin: https://notebook.example.com" http://localhost:5055/api/notebooks

# Access-Control-Allow-Origin: https://notebook.example.com

```

## Summary

- **Open Notebook** drives all CORS behavior through the `CORS_ORIGINS` environment variable defined in [`api/main.py`](https://github.com/lfnovo/open-notebook/blob/main/api/main.py).
- The helper `_parse_cors_origins` converts a comma-separated string into `CORS_ALLOWED_ORIGINS`, defaulting to `["*"]` when the variable is missing.
- A default wildcard combined with `allow_credentials=True` causes browsers to reject credentialed requests and creates a security gap.
- Explicit origin whitelisting is required for production to ensure only trusted frontends can read authenticated API responses.
- The `_cors_headers` helper preserves CORS policy consistency even on error responses.

## Frequently Asked Questions

### What happens if I do not set `CORS_ORIGINS` in Open Notebook?

If the variable is missing, `_parse_cors_origins` falls back to `["*"]`. This allows any website to request the API, but because `allow_credentials=True` is set, browsers will block cross-origin responses that include authentication material, resulting in broken frontend behavior.

### Can I change `CORS_ORIGINS` without restarting the application?

No. The value is read once at import time in [`api/main.py`](https://github.com/lfnovo/open-notebook/blob/main/api/main.py). Updating the environment variable requires a rolling restart of the application process or container to take effect.

### Why does Open Notebook place `CORSMiddleware` after authentication middleware?

In the source code, `CORSMiddleware` is installed after the auth middleware in the FastAPI stack so that CORS processing still runs on every request. This ordering—confirmed by the setup in [`api/main.py`](https://github.com/lfnovo/open-notebook/blob/main/api/main.py) and the definitions in [`api/auth.py`](https://github.com/lfnovo/open-notebook/blob/main/api/auth.py)—ensures that protected routes receive proper `Access-Control-Allow-Origin` headers while maintaining intended security boundaries.

### How does Open Notebook handle CORS headers when an API error occurs?

A custom helper called `_cors_headers` mirrors the `CORSMiddleware` logic and injects the same headers into error responses. This guarantees that even when exceptions such as `413 Payload Too Large` bypass the middleware, the browser still receives the correct origin policy and enforces it.