KEVWire

Security intelligence, with context.

Response snapshot Nov 4, 2026, 23:06 UTC

Back to the wire
Permalink
VulnerabilityCVE-2026-55098

Arc: DuckDB I/O aliases bypass database RBAC after CVE-2026-47735

The fix for CVE-2026-47735 (released 2026.06.1) is incomplete. It added a DuckDB sandbox (SET GLOBAL allowed_directories=[ ]; SET GLOBAL enable_external_access=false) and an Arc SQL-layer denylist of the literal functions read_parquet( and arc_partition_agg(.

At a glance

Exploited
Not known
Severity
6.5 Medium (CVSS 3.1)
Chance of exploitation
Not estimated
Sources
1 source

What to do

GitHub lists first patched versions: github.com/basekick-labs/arc: 0.0.0-20260610131716-5dc8f53b70a3. Confirm the affected range and upgrade guidance in the exact advisory.

Read GitHub-reviewed advisory GHSA-93cm-2v4m-c56c (opens a new tab)

What happened

Summary

The fix for CVE-2026-47735 (released 2026.06.1) is incomplete. It added a DuckDB sandbox (SET GLOBAL allowed_directories=[ ]; SET GLOBAL enable_external_access=false) and an Arc SQL-layer denylist of the literal functions read_parquet( and arc_partition_agg(.

The sandbox correctly blocks reads outside the storage root (OS files, http:// SSRF), but it allowlists the entire multi-tenant storage root, and the SQL denylist still misses the rest of the DuckDB I/O family the original advisory enumerated. As a result, any authenticated token — including one with permissions: [] — can read or enumerate every other database's data within the deployment, defeating RBAC.

Verified at HEAD c08b892 (v26.06.1-36, includes 26.06.2). Confirmed still live; no later commit blocks these functions.

Continue reading

Root cause (three composing gaps)

1. Sandbox scope is the whole storage root, not the tenant. internal/database/sandbox.go:111 allowlists cfg.LocalStorageRoot (default storage.local_path=./data/arc). Every database lives under it — internal/storage/util.go:33 GetStoragePath => / / /**/*.parquet. Any in-root path is sandbox-permitted regardless of which database owns it. 2. RBAC never inspects table-valued functions.

checkQueryPermissions (internal/api/query.go:1181) extracts table refs via extractTableReferences, which skips any name followed by ( as a function (internal/api/query.go:1116); with zero refs it returns allow (:1213-1216). So parquet_scan(...), glob(...), parquet_metadata(...), read_blob(...), read_csv_auto(...) are never authorization-checked. 3. The SQL denylist matches only the literal spelling.

userSQLReadParquetPattern (internal/api/query.go:2087) is \bread_parquet\s*\(. DuckDB's documented alias parquet_scan( is not matched, and read_csv_auto/read_json/read_text/read_blob/glob/parquet_metadata/parquet_schema are not blocked anywhere. The fix author documented this very threat at internal/api/query.go:2061-2064 (“a user scoped to db1.m1 could read /data/db2/secrets/**/*.

parquet”) but blocked only the literal read_parquet(.

Exploit (authenticated, any token incl. permissions:[])

POST /api/v1/query
Authorization: Bearer 
Content-Type: application/json
{"sql": "SELECT * FROM parquet_scan('./data/arc/ / /**/*.parquet')"}

- ValidateSQLRequest passes (parquet_scan( is not read_parquet(, not a dangerous keyword, single statement). - checkQueryPermissions extracts 0 table refs (it is a function call) and allows. - convertSQLToStoragePaths finds no read_parquet literal and no bare FROM measurement to rewrite, so the query passes through unchanged. - DuckDB runs parquet_scan(' / /...'); the path is inside allowed_directories, so the other database's rows are returned.

glob('./data/arc/**/*') enumerates every database/measurement/file; parquet_metadata(...)/parquet_schema(...) leak column names and per-column min/max value statistics; read_blob(...) returns raw file bytes. All operate within the allowlisted root.

Proof (poc/poc_sandbox_alias_bypass.py, poc/OUTPUT.txt)

Reproduces Arc's exact sandbox config (allowed_directories=[ ], enable_external_access=false) on DuckDB 1.5.x (Arc pins duckdb-go-bindings 1.5.1) with a victim parquet written under the root:

[BLOCKED ] read_blob OUTSIDE root -> Permission Error: Cannot access file ...
[EXECUTES] parquet_scan victim (read_parquet ALIAS) -> [('tenant-VICTIM-row', 42)]
[EXECUTES] glob enumerate every db under root -> [('.../data/arc/victim-db/secrets/f.parquet',)]
[EXECUTES] parquet_metadata victim -> [('leaked','tenant-VICTIM-row','tenant-VICTIM-row'), ('v','42','42')]

The sandbox blocks escape (as designed) but permits every in-root cross-database read.

Impact

Cross-database / cross-tenant confidential read by any authenticated principal, including a least-privileged (permissions: []) token, on RBAC-enabled deployments. This is the same RBAC-bypass impact the original advisory described for read_parquet, still reachable via the alias and the unblocked I/O family. (Arc's SQLite token DB ./data/arc.db is a sibling of .

/data/arc/ and is not in the allowlist, so it is not readable this way — the exposure is the time-series data of every database, plus its schema and value-range statistics.)

Remediation

Per-request scope the sandbox to the requesting token's authorized database path(s): allowed_directories = [' / /'], so the file layer cannot cross the RBAC boundary regardless of which function is used. Alternatively, replace the function-name denylist with a strict allowlist of permitted table functions (alias-resolved, reject all others). A denylist of literal spellings is structurally fragile — this is the second alias/family miss after the original audit.

Affected package ranges reported by GitHub: github.com/basekick-labs/arc: < 0.0.0-20260610131716-5dc8f53b70a3

Scores and how they were measured

CVSS base severity

6.5

Version 3.1As of

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N

Measurement source (opens a new tab)

How bad it is if exploited. Not a prediction of exploitation or proof you are exposed.

EPSS probability

Not available

A model's estimate of exploitation in the next 30 days, not certainty or your own risk.

Related technology

Sources

  1. Primary source

    GitHub-reviewed advisory GHSA-93cm-2v4m-c56c (opens a new tab)

    The public advisory supplies the description, affected package/version ranges, and any listed CVSS metric. GitHub review is not local review.

    Published Checked

  2. Primary source

    GitHub public advisory API page (opens a new tab)

    The API page supplied GHSA-93cm-2v4m-c56c, its actual identifiers, source dates, and structured metrics.

    Published Date not suppliedChecked

Cite this record

For factual claims, cite the primary sources above; cite KEVWire for its compilation, dates, and classifications.

APA

KEVWire. (2026, November 4). Arc: DuckDB I/O aliases bypass database RBAC after CVE-2026-47735 (CVE-2026-55098). https://kevwire.com/record/CVE-2026-55098

MLA

"Arc: DuckDB I/O aliases bypass database RBAC after CVE-2026-47735 (CVE-2026-55098)." KEVWire, 4 Nov. 2026, kevwire.com/record/CVE-2026-55098.

Chicago

KEVWire. "Arc: DuckDB I/O aliases bypass database RBAC after CVE-2026-47735 (CVE-2026-55098)." Last modified November 4, 2026. https://kevwire.com/record/CVE-2026-55098.

Evidence summary (plain text)

Arc: DuckDB I/O aliases bypass database RBAC after CVE-2026-47735 (Nov 4, 2026).
The fix for CVE-2026-47735 (released 2026.06.1) is incomplete. It added a DuckDB sandbox (SET GLOBAL allowed_directories=[ ]; SET GLOBAL enable_external_access=false) and an Arc SQL-layer denylist of the literal functions read_parquet( and arc_partition_agg(. The sandbox correctly blocks reads outside the storage root (OS files, http:// SSRF), but it allowlists the entire multi-tenant storage root, and the SQL denylist still misses the rest of the DuckDB I/O family the original advisory enumerated.
CVSS 6.5 (version 3.1; evidence as of Nov 4, 2026; https://github.com/advisories/GHSA-93cm-2v4m-c56c).
Sources:
GitHub-reviewed advisory GHSA-93cm-2v4m-c56c: https://github.com/advisories/GHSA-93cm-2v4m-c56c
GitHub public advisory API page: https://api.github.com/advisories?type=reviewed&per_page=100&sort=updated&direction=desc
Record ID: CVE-2026-55098.
Record origin: Ingested record.
AI evidence: Not assessed.
Known exploitation: Not assessed.
Zero-day status: Not assessed. KEV membership alone does not establish zero-day status.
About this data

This record was ingested from a data source. Retrieved: Nov 4, 2026, 23:05 UTC. Ingestion is not an independent editorial investigation.

A CISA KEV listing documents known exploitation, not necessarily a zero-day; absence from the catalog does not prove a vulnerability has never been exploited.

Technology tags indicate possible relevance, not verified exposure. Confirm the affected product, version, and configuration against your own inventory; KEVWire does not scan your systems.

A personal reading checklist on this device, not verified remediation.

Record JSON

Your account

Email alerts

Email alerts are coming as part of KEVWire Premium: join the waitlist. To follow your stack today, use its RSS feed, which honors your filters, or connect an AI agent through the API.

Suggest an improvement

Ideas, missing sources, corrections, and bugs are all welcome. No account needed. Suggestions are reviewed by a person before anything changes.

Record details

Record detail