Security and Data Flow

Review the Python for Excel trust boundaries: local calculation, cross-origin capabilities, notebook network isolation, workbook persistence, and executable source.

This page documents the trust boundaries of the current Python for Excel implementation. It is intended for security reviewers, developers, and workbook authors handling sensitive data. For the runtime topology and lifecycle, see Architecture and Runtime.

The central rule is that Python for Excel has several distinct data paths. Avoid blanket claims such as “everything stays local” or “everything goes to the cloud.” The destination depends on which capability is used.

Data paths at a glance

Activity Data path Main trust decision
Normal notebook calculation Declared bf.inputs() workbook values → Boardflare host → browser Python; published results return to Excel. Trust the workbook and notebook source you execute.
Direct notebook networking External-origin requests from the notebook child are blocked by its permanent connect-src 'self' CSP. Do not embed secrets expecting direct notebook HTTP to work.
Workbook persistence/sharing Executable notebook source is stored with the workbook. Treat the file as a document that can contain code.

flowchart TB
    WB[Excel workbook]
    Parent[Boardflare add-in host]
    Child[Separate-origin notebook iframe\nconnect-src 'self']
    Python[marimo / Pyodide]
    CodeSheet[Workbook _BOARDFLARE sheet]

    WB -->|declared bf.inputs values| Parent
    Parent -->|input capability| Child
    Child --> Python
    Python -->|bf.publish values/functions| Child
    Child -->|outputs capability| Parent
    Parent -->|BF.OUTPUT / BF.FUNCTION| WB
    Parent <-->|saved source + opening mode| CodeSheet

The notebook child does not have arbitrary external-origin network egress.

Normal workbook calculation

Workbook data reaches Python only through the declared workbook integration. bf.inputs() resolves reactive workbook references and materializes their values into the notebook runtime.

Notebook Python does not receive a general-purpose parent-window or Office.js workbook object from the documented API. Published values and callable results return through the separate outputs capability and shared-runtime registry.

This architectural boundary reduces accidental access to unrelated workbook operations. It does not prove that authored Python or third-party packages are safe.

Separate-origin notebook boundary

The notebook executes inside an iframe served from a different network origin from the parent add-in in production.

The iframe currently uses:

sandbox="allow-scripts allow-same-origin"

allow-same-origin is required by the stock marimo/Pyodide runtime, so the trust boundary does not come from sandbox tokens alone. Isolation depends on a distinct notebook origin plus explicit connection validation.

Production loads the child from the single production notebook origin, notebook.boardflare.com, and the parent checks that exact origin on every message; workbooks never supply a runtime address. The child is configured with the exact parent origin and fails closed when that parent information is missing or malformed. Its response CSP permanently includes connect-src 'self', which blocks direct external-origin requests from notebook code while allowing the same-origin runtime functions Boardflare intentionally exposes. Parent code is not supposed to read the child iframe document directly.

Capability handshake

Source, input, data, and outputs connections are explicit capabilities. Before transferring a MessagePort, the parent validates the connection identity.

sequenceDiagram
    participant Child as Notebook child / Anywidget
    participant Window as window.postMessage boundary
    participant Parent as Boardflare parent
    participant Port as Dedicated MessagePort

    Child->>Window: capability connect request
    Window->>Parent: event source + origin + transferred port
    Parent->>Parent: Validate iframe window
    Parent->>Parent: Validate exact child origin
    Parent->>Parent: Validate protocol version
    Parent->>Parent: Validate session ID + secure nonce
    Parent->>Parent: Validate capability label
    Parent->>Parent: Validate widget generation when required
    Parent->>Parent: Require exactly one MessagePort
    Parent-->>Child: Accept / transfer capability
    Child<<->>Port: Ongoing capability traffic
    Port<<->>Parent: Active session/generation only

The current checks include:

  • the active iframe Window as the message source;
  • the exact configured child origin;
  • protocol version 1;
  • the active secure session ID;
  • the active secure nonce;
  • exactly one transferred MessagePort;
  • an allowed source, input, data, or outputs capability label;
  • a non-empty generation identifier for input/data/output models.

Stale sessions and generations cannot claim current input snapshots, publication registries, or function results. These are implementation-level defense-in-depth controls, not notebook APIs.

Workbook persistence integrity

Boardflare persists the notebook source, metadata, and saved Edit/App opening preference directly within the workbook (on the hidden _BOARDFLARE worksheet). The stored record includes the format version, source cells, SHA-256 source digest, internal opening mode, and save timestamp.

A save writes the record, reads it back, and verifies the stored source and metadata. If verification fails, the host attempts to restore the prior stored value.

This is a persistence integrity check. It is not a digital signature and does not establish who authored or approved the notebook.

Authoritative storage limits (such as the 200,000 UTF-8 byte source limit and 32,000 character cell limit) and sheet layout specifications are maintained in the canonical reference:

See Getting Started: saving and reopening for the user workflow.

Uploaded source is staged before it is trusted as durable

Loading a Marimo .py file does not immediately replace the workbook copy.

stateDiagram-v2
    Saved: Last verified workbook source
    Staged: Uploaded source in memory
    Saved --> Staged: Upload .py
    Staged --> Saved: Save succeeds / becomes new verified source
    Staged --> Saved: Startup fails + Restore saved notebook

The staged notebook starts in a fresh Edit session. Until Marimo Save reaches verified workbook persistence, Restore saved notebook can discard the staged replacement and return to the last workbook copy. This design reduces the chance that simply opening a bad .py file destroys the durable notebook source.

It does not make uploaded Python trustworthy: the staged source is still executable code once the notebook session starts it.

Executable workbook trust

Notebook source can execute when a workbook starts the notebook runtime, including cold starts driven by worksheet formulas and workbooks saved to open in App mode.

Treat a notebook-enabled workbook like any file that can contain executable logic:

  • open it only from a source you trust;
  • review third-party dependencies and workbook data paths before using sensitive data;
  • do not treat App mode as source protection;
  • do not treat iframe isolation as proof that arbitrary Python is harmless;
  • revalidate important workbooks after material source or dependency changes.

App mode changes presentation. It is not a sandbox or an authorization boundary.

Notebook network isolation

The notebook child’s CSP permanently sets connect-src 'self'. Notebook code therefore cannot make arbitrary requests to PyPI, user-selected REST APIs, or other external origins. Browser CORS compatibility is not an escape hatch because CSP blocks those external connections first.

Do not place credentials in notebook source or workbook cells on the assumption that App mode hides them.

Validating Excel-specific behavior

Validate Excel-specific controls such as workbook sheet persistence or shared-runtime cold start in the actual Excel add-in.

Threat-model boundary

The current design aims to keep spreadsheet capabilities explicit, scoped, and validated across the notebook iframe boundary. It does not promise that arbitrary Python, arbitrary third-party packages, arbitrary workbooks, or arbitrary external services are safe.

A security review should separately evaluate:

  1. runtime boundary controls — origins, session/nonce identity, capability labels, generations, and message ports;
  2. workbook/source trust — what Python code will execute and who supplied it;
  3. persistence integrity — whether the intended source was durably saved and verified;
  4. external data paths — AI, third-party dependencies, and credentials;
  5. business-logic correctness — whether the analysis itself is appropriate for its intended decisions.

For the detailed lifecycle behind these controls, see Architecture and Runtime.