> For the complete documentation index, see [llms.txt](https://docs.stackai.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.stackai.com/stackai-auto-cli/docs/devops-712-storage-api-upgrade-plan.md).

# Plan: DEVOPS-712 — storage-api upgrade (CVE-2026-42043)

## Vulnerability

CVE-2026-42043 (CVSS 7.2 High) is an SSRF in the **axios** library bundled by `supabase/storage-api` — the CVE-2025-62718 fix only blocked `127.0.0.1`, leaving the rest of `127.0.0.0/8` able to bypass `NO_PROXY`. Fixed in axios 1.15.1. Practical exploitability in our topology is low (storage talks only to MinIO/Postgres internally), but the image is flagged and customer scanners (BAE) will keep flagging it.

## Target version: v1.68.0 (decision 2026-08-03; supersedes the v1.59.1 minimal-bump option)

Checked upstream `package-lock.json` per tag:

| storage-api                              | locked axios         | CVE status                           |
| ---------------------------------------- | -------------------- | ------------------------------------ |
| v1.33.5 (BAE today)                      | 1.12.0               | vulnerable                           |
| v1.36 – v1.43                            | 1.12.0               | vulnerable                           |
| v1.44 – v1.58                            | 1.13.6               | **still vulnerable** (needs ≥1.15.1) |
| **v1.59.0 / v1.59.1**                    | **removed entirely** | **clear**                            |
| v1.60.4 (Supabase self-host pin) / v1.68 | removed              | clear                                |

No tag ever shipped axios ≥1.15.1 — the dep was dropped at v1.59.0. So the minimal bump would be v1.59.x — but trivy showed the v1.59/1.60 dep vintage still carries 51 HIGH/CRIT findings vs 10 on v1.68.0, with ZERO additional tenant migrations between v1.59.1 and v1.68.0. Same DB risk, 5x cleaner scan → v1.68.0.

## Primary risk: tenant DB migrations at boot

v1.33.5 → v1.68.0 spans **28 tenant SQL migrations (0026 → 0060)**, applied automatically to the `storage` schema in Postgres when the new container first boots. Notable:

* **0026–0035 "prefixes" backfill** — creates `storage.prefixes`, computes object levels, adds triggers; work is proportional to `storage.objects` row count. This is the known-heavy migration of the 1.3x→1.5x line.
* 0055 adds prevent-direct-delete triggers; 0052–0054/0059 drop old indexes/functions.
* Migrations are **forward-only**: rollback = Postgres restore, not pin revert.
* Storage API is unavailable while they run (uploads/downloads fail; platform otherwise up).

BAE\_REPLICA carries representative data, so migration duration measured there is our estimate for BAE's window.

## Implementation (CLI repo)

1. Mirror `supabase/storage-api:v1.68.0` → `stackai.azurecr.io/supabase/storage-api:v1.68.0`.
2. Bump the pin in `config/docker-compose.yaml:351` (only place it exists).
3. Env-var diff v1.33.5 → v1.68.0 (upstream `.env.sample` / config): add any new-required vars to compose/`.env.template` + `env_schema.rs`; expect the vector\_store/analytics features to stay disabled by default.
4. Pre-commit green; ships as CLI **v0.1.48** (compose is CLI-owned; customers receive it via `system upgrade`).

## Validation on BAE\_REPLICA (gates the release)

1. **Snapshot**: `stackai system backup`; record `select count(*) from storage.objects`, current `storage.migrations` max, and a pg\_dump of the `storage` schema (cheap targeted rollback artifact).
2. **Upgrade**: pull v1.68.0, recreate `supabase-storage`, **time the migration** and capture its log.
3. **Verify**:
   * `/status` healthy; `storage.migrations` advanced through 0060.
   * Existing objects list + download through the app (knowledge bases, user documents).
   * New upload → download roundtrip; imgproxy transform of an existing image.
   * `stackai diagnose doctor` clean; no errant `storage.prefixes` errors in logs after 30 min of normal use.
4. **Rollback rehearsal** (must pass before release): revert pin + restore the storage-schema dump → confirm v1.33.5 serves again. Documents the real rollback cost for BAE.
5. Re-scan the new image (trivy) to confirm CVE-2026-42043 gone and no new HIGH/CRITICAL surprises.

## BAE upgrade steps (once v0.1.48 is released)

1. `stackai system backup` (full restore point — this upgrade migrates the DB).
2. `sudo stackai system upgrade` → CLI v0.1.48 (compose gets the new pin; nothing restarts yet).
3. Maintenance note: file upload/download unavailable during the storage migration — duration per replica measurement (fill in after step "time the migration" above).
4. `sudo stackai deploy restart supabase-storage --force` — watch logs until "migrations completed"; service healthy.
5. Verify: existing document opens in app, new upload works, `stackai diagnose doctor` clean.
6. Rollback (only if migration fails): restore from step-1 backup, revert via `backups/config_upgrade_*` compose.

## Out of scope

* Bumping other supabase services — separate scanner-driven refresh ticket; postgres engine never moves as a plain pin bump (pgsodium incident, aed4dce).
* Multitenant/vector-store features added upstream — remain disabled.

## Validation results (BAE\_REPLICA, 2026-08-03) — PASSED

* Trivy: v1.33.5 = 104 HIGH/CRIT incl. CVE-2026-42043; v1.68.0 = 10 HIGH/CRIT, CVE gone (one remaining CRITICAL: node `tar` 7.5.11, no upstream release). v1.59.1/v1.60.4 = 51 findings — rejected; zero tenant-migration difference vs v1.68.0, so no DB-risk benefit.
* Migration: storage.migrations 49 → 60, healthy in \~8s on 26 objects. NOTE: duration scales with storage.objects count — replica dataset is tiny; BAE window estimate must come from their object count, not this number.
* Expected state: `storage.prefixes` does NOT exist after upgrade — the prefixes migrations are `-- postgres-migrations ignore` (multitenant-only progressive path); single-tenant deployments keep the backward-compatible indexes. Not a failure. Functional battery green regardless.
* Functional: existing KB document download, folder listing, upload/download roundtrip — all pass on pre-existing v1.33.5 data.
* Migration re-run on restored data (accidental extra test): v1.68.0 booted on a restored 49-state schema re-applies 49→60 cleanly. Idempotent.
* Rollback rehearsal: `pg_dump --schema=storage` restore + pin revert → v1.33.5 healthy and serving. GOTCHA: schema is owned by `supabase_admin`, not `postgres` — rollback psql must run as `-U supabase_admin`.

## Remaining before release

1. ~~Import image into ACR~~ DONE 2026-08-03: ACR manifest digest `sha256:dbef3e47…` matches docker.io byte-for-byte (same image the replica validated); replica pulls it from ACR with its normal creds; trivy scan of the ACR image via scripts/trivy-scan.sh archived in `trivy-reports/` (1 CRITICAL — node `tar`, no upstream fix — + 9 HIGH).
2. Ship compose pin (already bumped in repo) as CLI v0.1.48.
3. BAE runbook step 3: fill maintenance-window estimate from their storage.objects count (`select count(*) from storage.objects`).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.stackai.com/stackai-auto-cli/docs/devops-712-storage-api-upgrade-plan.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
