NIST deprecates RSA-2048 from 2030. Find every one of them before attackers do.
🐹
🐹 Go
Not in CISA KEV
MEDIUM severity

Arc: DuckDB I/O aliases bypass database RBAC after CVE-2026-47735GHSA-93cm-2v4m-c56c

MEDIUMFix: Basekick-Labs/arc#495

GHSA-93cm-2v4m-c56c is a medium-severity (CVSS 6.5) Information Exposure vulnerability in github.com/basekick-labs/arc. A fix is available for github.com/basekick-labs/arc — see the affected versions and patch details below.

Also known asCVE-2026-55098GO-2026-6913
Published
Updated
Affected
1 pkg
Patched
1 / 1
Exploits
None indexed
Exploitation data as of Nov 6, 2026 · OSV.dev, NVD, FIRST.org (EPSS)

Exploitation Status

Proof-of-concept exploit code exists

  • CISA’s SSVC triage found public proof-of-concept exploit code for this CVE, though no confirmed active exploitation.

Exploitation and automatability from CISA’s SSVC triage for GHSA-93cm-2v4m-c56c.

EPSS Exploitation Probability

via FIRST.org ↗
0.3%probability of exploitation in next 30 days
Lower Risk0.00%
Lower risk than most CVEs25th percentile — riskier than 25% of all scored CVEsHighest risk
0.00%0.27%0.55%0.82%0.3%0.3%Nov 26Nov 26

Probability of exploitation in the next 30 days, from FIRST.org EPSS.

How urgent is this, really

Where this sits among everything scored

Real-World Exposure

1 pkg affected
🐹github.com/basekick-labs/arc

Real-time download stats are indexed for npm and PyPI packages. This vulnerability affects Go packages — download data is not available via public APIs for these ecosystems.

Description

Summary

The fix for CVE-2026-47735 (released 2026.06.1) is incomplete. It added a DuckDB sandbox (SET GLOBAL allowed_directories=[<storage root>]; 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.

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 => <base>/<database>/<measurement>/**/*.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 <token>
Content-Type: application/json
{"sql": "SELECT * FROM parquet_scan('./data/arc/<victim-db>/<measurement>/**/*.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('<root>/<victim-db>/...'); 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=[<root>], 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 = ['<base>/<authorized-db>/'], 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 Packages

1 total 1 fixed
EcosystemPackageVulnerable rangeFix
🐹Gogithub.com/basekick-labs/arcall versions0.0.0-20260610131716-5dc8f53b70a3go get github.com/basekick-labs/arc@v0.0.0-20260610131716-5dc8f53b70a3

Detection & mitigation playbook

Open-source dependency
  1. Detect

    Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for github.com/basekick-labs/arc, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.

  2. Fix

    Update github.com/basekick-labs/arc to 0.0.0-20260610131716-5dc8f53b70a3 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms GHSA-93cm-2v4m-c56c is resolved across your whole dependency graph.

  3. Workarounds

    Restrict outbound requests from the affected component to an allowlist of hosts, block access to link-local and internal address ranges at the network layer, and require authentication on internal services so a forged request cannot reach them unauthenticated.

Frequently Asked Questions

### Summary The fix for CVE-2026-47735 (released 2026.06.1) is incomplete. It added a DuckDB sandbox (`SET GLOBAL allowed_directories=[<storage root>]; 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 o
O3 Security · Impact-Aware SCA

Is GHSA-93cm-2v4m-c56c in your dependencies?

Find it across Go, including transitive dependencies.

Arc: DuckDB I/O aliases bypass database RBAC after…