feat(federation): env-gated unsigned DuckDB extensions (+ Firebird proposal)#67
Conversation
Add an opt-in DUCKDB_ALLOW_UNSIGNED_EXTENSIONS env var. When enabled, project DuckDB instances are created with allow_unsigned_extensions and the federation console accepts `INSTALL <ext> FROM '<source>'` for custom repositories or paths. Default-off preserves current behavior (signed core and community extensions only). Includes the OpenSpec change `add-unsigned-duckdb-extensions`. Co-authored-by: Cursor <cursoragent@cursor.com>
Proposal-only (no implementation). Adds an env-gated `firebird` connection type backed by the unsigned duckdb_firebird extension, activated by DUCKDB_ENABLE_FIREBIRD (effective only when DUCKDB_ALLOW_UNSIGNED_EXTENSIONS is also set) with an optional DUCKDB_FIREBIRD_EXTENSION_REPOSITORY override. Co-authored-by: Cursor <cursoragent@cursor.com>
|
🚅 Deployed to the archmax-pr-67 environment in archmax SemLayer
|
There was a problem hiding this comment.
Security review complete: I did not find concrete issues in the changed files.
Checked threat surfaces:
- MCP endpoint auth:
apps/api/src/mcp/archmax-route.tsauthenticates the bearer token and resolves the project before registering/running tools, re-authenticates resumed sessions against the original token/project/slug, and returns JSON-RPC auth errors for invalid credentials. Token scopes flow intoregisterArchmaxToolsand are enforced by the MCP tool handlers. - Query execution sandboxing:
packages/core/src/services/mcp-tools.tsvalidates SQL withvalidateSqlAstbefore acquiring the project DuckDB instance, materializes scoped model VIEWs, hardens the connection/search path, enforceswithQueryTimeout, and truncates results atMAX_ROWS. The new unsigned-extension flag inpackages/core/src/services/duckdb.tsdoes not relax the MCP validator, andpackages/core/src/services/duckdb-console.tsgates custom-sourceINSTALLparsing behindallowUnsignedExtensions(). - Admin auth:
packages/core/src/config/env.tsstill requiresBETTER_AUTH_SECRETlength >= 32; the API app applies CSRF middleware before session-authenticated routes; Better Auth production cookies remainSecure,HttpOnly, andSameSite=Lax. - API input validation: changed console POST bodies continue to use Zod validation, extension names remain allowlisted, and the new custom source is single-quote escaped before interpolation into DuckDB SQL.
- Environment secrets: no
.env.localor hardcoded secrets were added; docs/examples use placeholders and warn about unsigned native-code risk. Existing DuckDB error paths redact connection secrets before returning/logging. - Dependency exposure: no dependency manifest changes were included in this PR, so no new dependency exposure was introduced.
Sent by Cursor Automation: archmax Security Review
Docker image readydocker pull ghcr.io/archmaxai/archmax:pr-67 |
The federation console PR is merged, so sync specs/ with reality: land the duckdb-console capability and the documentation-site/frontend-shell updates, and move the change into changes/archive/. This lets the stacked add-unsigned-duckdb-extensions delta build on the now-published spec. Co-authored-by: Cursor <cursoragent@cursor.com>
Add an optional, unsigned Firebird connection type gated behind DUCKDB_ENABLE_CUSTOM_FIREBIRD. Enabling it activates the `firebird` connection type, starts DuckDB instances with allow_unsigned_extensions, and installs the custom Firebird extension from a configurable repository. API rejects firebird connections when the flag is off, and the UI exposes availability via /api/config. Update the duckdb test mock with the new config/env exports. Co-authored-by: Cursor <cursoragent@cursor.com>
Adds the remaining Firebird coverage to complete the feature: - env helper tests for allowUnsignedExtensions/customFirebirdEnabled/ firebirdExtensionRepository - buildAttachString firebird DSN tests (default port/charset, uri pass-through) - API integration test for the firebird create/update 400 gate and the accepted-when-enabled path including charset - data-federation guide Firebird section and checked-off tasks Co-authored-by: Cursor <cursoragent@cursor.com>
…rces Address Bugbot findings on the env-gated Firebird / unsigned-extension work: - Skip active firebird connections during federation when DUCKDB_ENABLE_CUSTOM_FIREBIRD is off, so a leftover source no longer aborts getProjectInstance and breaks DuckDB for the whole project. - Gate partial PUT updates on an existing firebird connection by the stored type, not just the (optional) incoming type. - Honor an explicit console INSTALL <ext> FROM '<source>' for firebird instead of always installing from the default repository. - Re-run the install in ensureProjectExtensionLoaded when a custom fromSource is requested, even if the extension is already loaded. Co-authored-by: Cursor <cursoragent@cursor.com>
Move the completed change into changes/archive/ and apply the reconciled "Admin User Seeding" requirement to the auth spec. Co-authored-by: Cursor <cursoragent@cursor.com>
…rd only Build Firebird connections from explicit ATTACH options (HOST/PORT/DATABASE/USER/PASSWORD/CHARSET) with an empty ATTACH path instead of a key=value/URI DSN. The custom extension parses the ATTACH path as a DSN, so a Windows drive-letter colon (e.g. C:\db.fdb) was fed to std::stoi and threw "Invalid Error: stoi", failing every attach. Options also safely carry passwords/paths containing URI metacharacters the DSN parser cannot decode; a raw `uri` is still passed through as the ATTACH path. Consolidate unsigned-extension support behind the single DUCKDB_ENABLE_CUSTOM_FIREBIRD switch: drop DUCKDB_ALLOW_UNSIGNED_EXTENSIONS and DUCKDB_FIREBIRD_EXTENSION_REPOSITORY and the console's custom-source install path, and fold the add-unsigned-duckdb-extensions proposal into add-firebird-connection-type. Co-authored-by: Cursor <cursoragent@cursor.com>
POST /connections/:id/test ran testSingleConnection without checking customFirebirdEnabled(), so a stored firebird connection could install and load the unsigned extension even when DUCKDB_ENABLE_CUSTOM_FIREBIRD is off. Gate the test route (400) and add a defensive guard in testSingleConnection itself. Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit dc5a205. Configure here.
| await db.run(`SET custom_extension_repository = '${repo}'`); | ||
| await db.run("INSTALL firebird"); | ||
| await db.run("LOAD firebird"); | ||
| return; |
There was a problem hiding this comment.
Custom repo breaks core installs
High Severity
The Firebird install path sets custom_extension_repository on the shared project DuckDB instance and never restores the default. Later INSTALL calls for core extensions (e.g. postgres, iceberg) without an explicit FROM community clause can resolve against the Firebird repo instead of DuckDB’s core catalog, so multi-source projects may fail attach or extension load depending on connection order.
Reviewed by Cursor Bugbot for commit dc5a205. Configure here.
| case "sqlite": | ||
| return "sqlite"; | ||
| case "firebird": | ||
| return "firebird"; |
There was a problem hiding this comment.
Setup SQL omits Firebird options
Medium Severity
buildRedactedAttachSql still builds Firebird setup commands from buildAttachString only, which returns an empty ATTACH path for structured Firebird configs. The runtime attach path appends buildFirebirdAttachOptions (HOST, PORT, DATABASE, etc.), so console setup copy-paste SQL does not match what the server actually runs and will not attach structured Firebird sources.
Reviewed by Cursor Bugbot for commit dc5a205. Configure here.




Summary
DUCKDB_ALLOW_UNSIGNED_EXTENSIONSenv var (default off). When enabled, project DuckDB instances are created withallow_unsigned_extensions, and the federation console acceptsINSTALL <extension> FROM '<source>'for custom repositories/paths. When unset, behavior is identical to today (signed core +FROM communityonly).add-firebird-connection-type, which proposes an env-gatedfirebirdconnection type built on top of the unsigned-extensions gate. This is design/spec docs for review, not implemented in this PR.What changed (implemented)
packages/core/src/config/env.ts—DUCKDB_ALLOW_UNSIGNED_EXTENSIONS+allowUnsignedExtensions()helper.packages/core/src/services/duckdb.ts—createDuckDBInstance()appliesallow_unsigned_extensionsat instance creation (the option can only be set at startup); all three creation sites route through it.fromSourcethreaded throughensureProjectExtensionLoaded→installAndLoadExtension, emittingINSTALL <ext> FROM '<source>'(single-quote-escaped).packages/core/src/services/duckdb-console.ts—parseExtensionSql(sql, allowUnsigned)matches the env-gatedFROM '<source>'shape; rejected with the existing 400 message when the flag is off..env.exampleand a new "Data Federation (DuckDB)" table inapps/docs/.../reference/docker.mdx, both with a security caution that unsigned extensions run arbitrary native code.add-unsigned-duckdb-extensions(proposal/design/tasks/specs, all tasks checked off).Test plan
npx vitest run packages/core/src/services/duckdb-console.test.ts— 16/16 pass (5 new cases for the gated parser)pnpm typecheckexits 0pnpm lintexits 0pnpm --filter @archmax/api buildexits 0 (runs as part of typecheck)DUCKDB_ALLOW_UNSIGNED_EXTENSIONS=true,INSTALL <ext> FROM '<repo>'loads from the console; with it unset, the same statement is rejected with 400Notes
add-firebird-connection-typeproposal has an open question (exact ATTACH DSN for the customduckdb_firebirdextension) to resolve during its own implementation PR. It is intentionally not implemented here.Made with Cursor
Note
High Risk
Enabling the flag loads unsigned native code and turns on
allow_unsigned_extensionsfor all DuckDB instances; misconfiguration or a compromised extension repo is a serious security concern despite API/console restrictions.Overview
Adds an opt-in, default-off
firebirddata source backed by a custom unsigned DuckDB extension, gated byDUCKDB_ENABLE_CUSTOM_FIREBIRD(not a general unsigned-extensions flag).When enabled, project DuckDB instances are created with
allow_unsigned_extensions, the Firebird extension is auto-installed from a fixed archmax-hosted repo (SET custom_extension_repository+INSTALL/LOAD firebird), and connections attach viaTYPE FIREBIRDwith structured fields passed as ATTACH options (empty path +HOST/PORT/DATABASE/etc.) to avoid Windows-path / URI parsing bugs. When disabled, create/update/test for Firebird return 400, active Firebird connections are skipped during federation (without breaking other sources), and the federation console still rejectsINSTALL … FROM '<arbitrary source>'.API & UI:
firebirdon the connection model, optionalcharsetin config,/api/configexposesfirebirdEnabled, and the connections form shows Firebird only when the flag is on (defaults port3050, charsetUTF8).Docs & specs:
.env.example, Docker reference, data-federation guide, OpenSpec changeadd-firebird-connection-type, plus integration/unit tests for gates and attach building.Reviewed by Cursor Bugbot for commit dc5a205. Bugbot is set up for automated code reviews on this repo. Configure here.