CVE-2026-55098
Arc: DuckDB I/O aliases bypass database RBAC after CVE-2026-47735
Arc is an open, SQL-native time-series database for telemetry. Prior to the repository-verified 26.06.2 repair, the remediation of CVE-2026-47735 leaves a cross-database authorization bypass through DuckDB table-valued I/O functions. In internal/database/sandbox.go, allowed_directories uses cfg.LocalStorageRoot, configured by storage.local_path, while enable_external_access=false blocks access outside that entire multi-tenant root. GetStoragePath in internal/storage/util.go stores all databases beneath it. In internal/api/query.go, extractTableReferences skips names followed by an opening parenthesis and checkQueryPermissions allows queries with no extracted table references, including tokens with permissions: []. The userSQLReadParquetPattern denylist catches literal read_parquet( and the earlier protection also blocks arc_partition_agg(, but misses the parquet_scan alias and glob, parquet_metadata, parquet_schema, read_blob, read_csv_auto, read_json and read_text. A request to POST /api/v1/query using these unblocked functions passes ValidateSQLRequest and convertSQLToStoragePaths without tenant authorization, allowing reads and enumeration of other databases' time-series data, schema and per-column value-range statistics within the allowlisted root. The sandbox still blocks out-of-root OS files and HTTP SSRF, and the sibling SQLite token database outside the root is not exposed by this mechanism. The earlier 26.06.1 remediation does not comprehensively deny these I/O functions. Repository tag 26.06.2 contains the I/O-function repair and supplies the provisional remediation boundary; conflicting advisory affected-version statements require curator adjudication.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- Low
- User interaction
- None
What an attacker can affect
- Confidentiality
- High
- Integrity
- None
- Availability
- None
Exploit likelihood
What each source reports
CVE List Score used
6.5
Arc: DuckDB I/O aliases bypass database RBAC after CVE-2026-47735
Arc is an open, SQL-native time-series database for telemetry. Prior to the repository-verified 26.06.2 repair, the remediation of CVE-2026-47735 leaves a cross-database authorization bypass through DuckDB table-valued I/O functions. In internal/database/sandbox.go, allowed_directories uses cfg.LocalStorageRoot, configured by storage.local_path, while enable_external_access=false blocks access outside that entire multi-tenant root. GetStoragePath in internal/storage/util.go stores all databases beneath it. In internal/api/query.go, extractTableReferences skips names followed by an opening parenthesis and checkQueryPermissions allows queries with no extracted table references, including tokens with permissions: []. The userSQLReadParquetPattern denylist catches literal read_parquet( and the earlier protection also blocks arc_partition_agg(, but misses the parquet_scan alias and glob, parquet_metadata, parquet_schema, read_blob, read_csv_auto, read_json and read_text. A request to POST /api/v1/query using these unblocked functions passes ValidateSQLRequest and convertSQLToStoragePaths without tenant authorization, allowing reads and enumeration of other databases' time-series data, schema and per-column value-range statistics within the allowlisted root. The sandbox still blocks out-of-root OS files and HTTP SSRF, and the sibling SQLite token database outside the root is not exposed by this mechanism. The earlier 26.06.1 remediation does not comprehensively deny these I/O functions. Repository tag 26.06.2 contains the I/O-function repair and supplies the provisional remediation boundary; conflicting advisory affected-version statements require curator adjudication.
- Record
CVE-2026-55098- CVSS 3.1
- 6.5 Medium
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N - Weakness
- CWE-200, CWE-863
- Updated
- 2026-11-02
EUVDEUVD-2026-114443
6.5
Arc: DuckDB I/O aliases bypass database RBAC after CVE-2026-47735
- Record
EUVD-2026-114443- CVSS 3.1
- 6.5 Medium
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N - Updated
- 2026-11-04
GitHub AdvisoriesGHSA-93cm-2v4m-c56c
6.5
Arc: DuckDB I/O aliases bypass database RBAC after CVE-2026-47735
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)
- Sandbox scope is the whole storage root, not the tenant.
internal/database/sandbox.go:111allowlistscfg.LocalStorageRoot(defaultstorage.local_path=./data/arc). Every database lives under it —internal/storage/util.go:33GetStoragePath=><base>/<database>/<measurement>/**/*.parquet. Any in-root path is sandbox-permitted regardless of which database owns it. - RBAC never inspects table-valued functions.
checkQueryPermissions(internal/api/query.go:1181) extracts table refs viaextractTableReferences, which skips any name followed by(as a function (internal/api/query.go:1116); with zero refs it returns allow (:1213-1216). Soparquet_scan(...),glob(...),parquet_metadata(...),read_blob(...),read_csv_auto(...)are never authorization-checked. - The SQL denylist matches only the literal spelling.
userSQLReadParquetPattern(internal/api/query.go:2087) is\bread_parquet\s*\(. DuckDB's documented aliasparquet_scan(is not matched, andread_csv_auto/read_json/read_text/read_blob/glob/parquet_metadata/parquet_schemaare not blocked anywhere. The fix author documented this very threat atinternal/api/query.go:2061-2064(“a user scoped to db1.m1 could read /data/db2/secrets/**/*.parquet”) but blocked only the literalread_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')"}
ValidateSQLRequestpasses (parquet_scan(is notread_parquet(, not a dangerous keyword, single statement).checkQueryPermissionsextracts 0 table refs (it is a function call) and allows.convertSQLToStoragePathsfinds noread_parquetliteral and no bareFROM measurementto rewrite, so the query passes through unchanged.- DuckDB runs
parquet_scan('<root>/<victim-db>/...'); the path is insideallowed_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…
- Record
GHSA-93cm-2v4m-c56c- CVSS 3.1
- 6.5 Medium
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N - Weakness
- CWE-200, CWE-863
- Updated
- 2026-11-04
NVD
6.5
Arc is an open, SQL-native time-series database for telemetry. Prior to the repository-verified 26.06.2 repair, the remediation of CVE-2026-47735 leaves a cross-database authorization bypass through DuckDB table-valued I/O functions. In internal/database/sandbox.go, allowed_directories uses cfg.LocalStorageRoot, configured by storage.local_path, while enable_external_access=false blocks access outside that entire multi-tenant root. GetStoragePath in internal/storage/util.go stores all databases beneath it. In internal/api/query.go, extractTableReferences skips names followed by an opening parenthesis and checkQueryPermissions allows queries with no extracted table references, including tokens with permissions: []. The userSQLReadParquetPattern denylist catches literal read_parquet( and the earlier protection also blocks arc_partition_agg(, but misses the parquet_scan alias and glob, parquet_metadata, parquet_schema, read_blob, read_csv_auto, read_json and read_text. A request to POST /api/v1/query using these unblocked functions passes ValidateSQLRequest and convertSQLToStoragePaths without tenant authorization, allowing reads and enumeration of other databases' time-series data, schema and per-column value-range statistics within the allowlisted root. The sandbox still blocks out-of-root OS files and HTTP SSRF, and the sibling SQLite token database outside the root is not exposed by this mechanism. The earlier 26.06.1 remediation does not comprehensively deny these I/O functions. Repository tag 26.06.2 contains the I/O-function repair and supplies the provisional remediation boundary; conflicting advisory affected-version statements require curator adjudication.
- Record
CVE-2026-55098- CVSS 3.1
- 6.5 Medium
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N - Weakness
- CWE-200, CWE-863
- Updated
- 2026-11-03
OSV
6.5
Arc: DuckDB I/O aliases bypass database RBAC after CVE-2026-47735
Arc is an open, SQL-native time-series database for telemetry. Prior to the repository-verified 26.06.2 repair, the remediation of CVE-2026-47735 leaves a cross-database authorization bypass through DuckDB table-valued I/O functions. In internal/database/sandbox.go, allowed_directories uses cfg.LocalStorageRoot, configured by storage.local_path, while enable_external_access=false blocks access outside that entire multi-tenant root. GetStoragePath in internal/storage/util.go stores all databases beneath it. In internal/api/query.go, extractTableReferences skips names followed by an opening parenthesis and checkQueryPermissions allows queries with no extracted table references, including tokens with permissions: []. The userSQLReadParquetPattern denylist catches literal read_parquet( and the earlier protection also blocks arc_partition_agg(, but misses the parquet_scan alias and glob, parquet_metadata, parquet_schema, read_blob, read_csv_auto, read_json and read_text. A request to POST /api/v1/query using these unblocked functions passes ValidateSQLRequest and convertSQLToStoragePaths without tenant authorization, allowing reads and enumeration of other databases' time-series data, schema and per-column value-range statistics within the allowlisted root. The sandbox still blocks out-of-root OS files and HTTP SSRF, and the sibling SQLite token database outside the root is not exposed by this mechanism. The earlier 26.06.1 remediation does not comprehensively deny these I/O functions. Repository tag 26.06.2 contains the I/O-function repair and supplies the provisional remediation boundary; conflicting advisory affected-version statements require curator adjudication.
- Record
CVE-2026-55098- CVSS 3.1
- 6.5 Medium
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N - Weakness
- CWE-200, CWE-863
- Updated
- 2026-11-06
OSVGHSA-93cm-2v4m-c56c
6.5
Arc: DuckDB I/O aliases bypass database RBAC after CVE-2026-47735
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)
- Sandbox scope is the whole storage root, not the tenant.
internal/database/sandbox.go:111allowlistscfg.LocalStorageRoot(defaultstorage.local_path=./data/arc). Every database lives under it —internal/storage/util.go:33GetStoragePath=><base>/<database>/<measurement>/**/*.parquet. Any in-root path is sandbox-permitted regardless of which database owns it. - RBAC never inspects table-valued functions.
checkQueryPermissions(internal/api/query.go:1181) extracts table refs viaextractTableReferences, which skips any name followed by(as a function (internal/api/query.go:1116); with zero refs it returns allow (:1213-1216). Soparquet_scan(...),glob(...),parquet_metadata(...),read_blob(...),read_csv_auto(...)are never authorization-checked. - The SQL denylist matches only the literal spelling.
userSQLReadParquetPattern(internal/api/query.go:2087) is\bread_parquet\s*\(. DuckDB's documented aliasparquet_scan(is not matched, andread_csv_auto/read_json/read_text/read_blob/glob/parquet_metadata/parquet_schemaare not blocked anywhere. The fix author documented this very threat atinternal/api/query.go:2061-2064(“a user scoped to db1.m1 could read /data/db2/secrets/**/*.parquet”) but blocked only the literalread_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')"}
ValidateSQLRequestpasses (parquet_scan(is notread_parquet(, not a dangerous keyword, single statement).checkQueryPermissionsextracts 0 table refs (it is a function call) and allows.convertSQLToStoragePathsfinds noread_parquetliteral and no bareFROM measurementto rewrite, so the query passes through unchanged.- DuckDB runs
parquet_scan('<root>/<victim-db>/...'); the path is insideallowed_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…
- Record
GHSA-93cm-2v4m-c56c- CVSS 3.1
- 6.5 Medium
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N - Weakness
- CWE-200, CWE-863
- Updated
- 2026-11-06
OSVGO-2026-6913 No score
Arc: DuckDB I/O aliases bypass database RBAC after CVE-2026-47735 in github.com/basekick-labs/arc
Arc: DuckDB I/O aliases bypass database RBAC after CVE-2026-47735 in github.com/basekick-labs/arc
- Record
GO-2026-6913- Updated
- 2026-11-06
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
github.com/basekick-labs/arcGo |
before 0.0.0-20260610131716-5dc8f53b70a3 | 0.0.0-20260610131716-5dc8f53b70a3 |
History
| Recorded | Changed | Sources |
|---|---|---|
| affected, aliases | OSV | |
| published | EUVD | |
| affected, references | OSV | |
| affected, facts, references | GitHub Advisories | |
| facts | NVD, OSV | |
| first indexed | CVE List, EUVD, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-55098 is a medium vulnerability (CVSS 6.5) in Basekick-labs Arc, published October 30, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.32%, the 25th percentile. Fixed in github.com/basekick-labs/arc 0.0.0-20260610131716-5dc8f53b70a3.
References
github.com/Basekick-Labs/arc/security/advisories/GHSA-93cm-2v4m-c56c
github.com/Basekick-Labs/arc/pull/495
github.com/Basekick-Labs/arc/commit/5dc8f53b70a3871b16b0cebf328f07c578af7a45
github.com/Basekick-Labs/arc/tree/v26.06.2
nvd.nist.gov/vuln/detail/CVE-2026-55098
github.com/advisories/GHSA-93cm-2v4m-c56c
github.com/CVEProject/cvelistV5/tree/main/cves/2026/55xxx/CVE-2026-55098.json
github.com/Basekick-Labs/arc
Left out here: the rest of 2 source descriptions. The JSON record has them.