- keep access scoped to the providers you configure in
bridge.yaml - fail closed when configuration is missing or incomplete
- prevent obvious unsafe reads such as filesystem path traversal
- constrain database reads to validated identifiers and parameterized values
- return machine-readable errors so humans and agents can react safely
What Bridge secures today
Bridge sits between an agent and your configured backends. Its job is to normalize access, not to replace the permissions of those backends. That means:- filesystem access is limited by the directory root you configure
- database access is limited by the credentials in the connection URI you provide
- Bridge does not currently add a separate authentication layer on top of those providers
- Bridge does not currently provide row-level authorization, tenant isolation, or policy rules of its own
Configuration safety
bridge.yaml is local, explicit, and required for most Bridge commands.
Current safety properties:
- Bridge only reads
bridge.yamlfrom the current directory - it does not search parent directories for another config file
- provider names must be chosen explicitly
- provider type inference rejects unsupported URI schemes
- environment variable expansion fails fast when a referenced variable is missing
Environment variables fail closed
Bridge expands${VAR_NAME} references from bridge.yaml before connecting a provider.
If a referenced variable is not set, Bridge does not continue with a partial value. It returns env_var_not_set instead.
This is important for secrets because it avoids accidental fallbacks like:
- connecting to the wrong database
- treating a malformed URI as valid
- silently removing credentials from a connection string
bridge.yaml directly or by running bridge connect DATABASE_URL --type postgres --as db.
Unsupported URIs fail early
bridge connect only recognizes the schemes Bridge knows how to handle today:
file://postgres://postgresql://
invalid_uri instead of being guessed or coerced into another provider type.
If you use an environment variable name as the bridge connect target, Bridge requires --type because there is no URI scheme to infer from.
Filesystem guardrails
The filesystem provider is designed to keep reads inside the configured root directory. When Bridge reads a filesystem path, it:- canonicalizes the configured root
- joins the requested path to that root
- canonicalizes the requested target
- checks that the resolved path still lives under the root
path_traversal.
That means inputs like these are blocked:
../../etc/passwd../secrets.txt- any other path that resolves outside the configured provider root
- Bridge refuses to connect a filesystem provider if the configured path does not exist
- Bridge refuses to connect if the path is a file instead of a directory
- reads fail if the target path does not exist under the configured root
Postgres guardrails
The Postgres provider keeps its query surface intentionally small. Today, it only supports:- listing tables from the
publicschema - reading a whole table
- reading a single row by primary key path
Identifier validation
Table names are validated before Bridge uses them in SQL. Bridge only accepts identifiers that match:users; DROP TABLE usersusers where true- quoted or multi-statement payloads
Parameterized row values
When you read a specific row such asbridge read users/42 --from db, the row identifier is passed as a bound parameter rather than interpolated directly into the query string.
That reduces injection risk for row values even when the primary key type changes between tables.
Scope restrictions
The current Postgres provider is conservative by design:- it only lists tables in the
publicschema - it requires a primary key for row reads
- it refuses suspicious table identifiers before they reach SQL
Secret handling and redaction
Bridge does not encrypt your provider URIs or manage secrets for you. The recommended pattern is to keep secrets in environment variables and reference them frombridge.yaml.
Bridge reads those values from the process environment when commands run. It does not automatically load a .env file.
When Bridge needs to show a database URI in user-facing metadata or health output, it redacts the password portion.
Example:
- Postgres read metadata
bridge statusoutput
Timeout model
Provider operations run inside a global timeout controlled by--timeout.
timeout error instead of waiting indefinitely.
This applies to operations such as:
- connecting to a provider
- listing entries
- reading data
- provider health checks
- exit code
1for most validation and provider failures - exit code
2for I/O, database, and timeout failures
Error model
Bridge uses one error envelope across commands.- successful JSON goes to stdout
- error JSON goes to stderr
- failures are machine-readable
- failures also carry a human-readable message
Common error codes
| Code | What it means | Typical fix |
|---|---|---|
config_not_found | bridge.yaml was not found in the current directory | Run bridge init or change into the correct project directory |
config_parse_error | bridge.yaml exists but could not be parsed | Fix the YAML structure or invalid field values |
invalid_uri | The provider URI is malformed or uses an unsupported scheme | Use a supported file://, postgres://, or postgresql:// URI |
invalid_connect_target | A bridge connect target was neither a full URI nor a bare environment variable name | Pass a literal URI such as postgres://localhost:5432/mydb or an env var name such as DATABASE_URL |
missing_provider_type | bridge connect received an environment variable name without --type | Pass --type <provider>, for example --type postgres |
invalid_provider_type | bridge connect --type named an unsupported provider | Use one of the supported provider types |
provider_type_conflict | bridge connect --type conflicts with the type implied by a literal URI | Remove --type or pass the matching provider type |
invalid_env_var_name | bridge connect received an invalid environment variable name | Pass a bare name like DATABASE_URL without ${} |
env_var_not_set | A ${VAR} reference in bridge.yaml could not be resolved | Export the missing environment variable before running Bridge |
provider_not_found | The provider named by --from or remove does not exist | Check the provider name in bridge.yaml or run bridge status |
provider_error | The provider rejected the operation or the backend was unavailable | Inspect the message for the backend-specific failure and verify the provider configuration |
path_traversal | A filesystem read escaped the configured root | Read a path inside the configured provider directory |
invalid_identifier | A Postgres table identifier failed validation | Use a simple table name that matches the supported identifier pattern |
timeout | A provider operation exceeded the configured timeout | Increase --timeout or fix the underlying connectivity problem |
database_error | The database driver returned an unexpected failure | Check the database connection, permissions, and backend logs |
Degraded behavior and recovery
Bridge tries to fail clearly and locally. Examples:- if one provider in
bridge statusis misconfigured, Bridge still reports the others - if a single filesystem read fails, Bridge does not mutate your config as part of error handling
- if environment variable expansion fails, Bridge stops before attempting the provider connection
Operational advice
The safest way to run Bridge today is:- keep provider roots narrow on the filesystem side
- use dedicated database credentials with the least access required
- keep secrets in environment variables, not inline in
bridge.yaml - use
bridge statusafter adding or changing a provider - set
--timeoutintentionally in automation so long waits fail predictably
Related pages
Commands
See how Bridge commands expose timeouts, errors, and machine-readable output.
Configuration
Learn how Bridge loads
bridge.yaml, resolves provider names, and expands environment variables.Providers
See the backend-specific behavior and limits that sit behind these guardrails.