For demonstration purposes only.
This document describes the security measures implemented in EDB Postgres® AI Blueprints.
The chat agent does not enforce a command whitelist. Its run_command tool (engine/agent/agent.py) passes the string it receives straight to the shell via subprocess.run(cmd, shell=True). The tool description suggests it is limited to Docker commands, but that is advisory only and does not constrain what runs — anyone who can reach the agent can run arbitrary shell commands on the host.
This is acceptable only under the trusted-host assumption in the Threat Model: run it on your own machine, on a trusted network or behind a VPN, never on a shared or internet-facing host.
Mitigation: restrict network access to the agent. For genuine enforcement, replace the free-form run_command tool with structured deploy/destroy/logs actions that build the Docker command server-side, rather than filtering shell
strings after the fact.
All /api/*endpoints except/api/health` are protected with API key authentication:
| Endpoint | Protection | Description |
|---|---|---|
/api/exit |
API Key Required | Stops all containers and shuts down agent |
/api/reset |
API Key Required | Resets chat history |
/api/chat |
API Key Required | Chat functionality |
/api/stacks |
API Key Required | List available stacks |
/api/health |
Public | Health check (the only unauthenticated route) |
The API key is:
- Auto-generated on startup (printed to console)
- Or set via
AGENT_API_KEYenvironment variable
Scope limit: this guard is HTTP-only and does not cover the WebSocket endpoints. /ws/terminal opens a shell into containers without an API key (it validates the container name, not the caller). The shipped UI also does not send an Authorization header on its /api/* calls, so the key must be supplied by a reverse proxy or run configuration.
All user inputs are validated using Pydantic models:
- Message length: 1-10,000 characters
- Required fields enforced
- Type validation on all inputs
The agent application (engine/agent/app.py) does not register any CORS middleware, and the SynthDB API (engine/synthdb/api.py) is configured with allow_origins=["*"], which accepts requests from any origin.
In the shipped setup this carries little practical risk: browsers never call the SynthDB service directly. UI requests go to /api/synthdb/* on the agent, which proxies to SynthDB server-side, so the permissive policy is not reachable from a browser. It should still be tightened as a matter of hygiene.
Mitigation: keep all services bound to localhost. To enforce origin restrictions, add CORSMiddleware to app.py and replace the wildcard in synthdb/api.py with an explicit allow-list (for example, http://127.0.0.1:4000).
Database ports are bound to localhost only:
| Service | Port Binding | Access |
|---|---|---|
| PostgreSQL | 127.0.0.1:5432 |
Local only |
| ClickHouse | 127.0.0.1:8123 |
Local only |
| Catalog DB | 127.0.0.1:9901 |
Local only |
UI ports (3000, 4000, 7860, 8888) are exposed for browser access.
- Passwords are NOT included in LLM system prompts
- Credentials are stored in
stack.yamlfiles (not transmitted to AI) - Default credentials are for development only
- Logging limits prevent disk exhaustion (10MB max, 3 files)
- Healthchecks monitor service availability
- Restart policies ensure recovery from failures
- GRANT_SUDO disabled in Jupyter containers
These are development-only credentials. Change them for any shared environment.
Each stack supports password configuration via environment variables:
cd stacks/data-engineering
cp .env.example .env
# Edit .env with your custom passwords
docker compose up -d| Service | Username | Password | Environment Variable |
|---|---|---|---|
| PostgreSQL | admin | admin123 | POSTGRES_PASSWORD |
| PostgreSQL | aidev | aidev123 | POSTGRES_PASSWORD_AIDEV |
| ClickHouse | admin | admin123 | CLICKHOUSE_PASSWORD |
| ClickHouse | default | (no password) | - |
| MinIO | _peerdb_minioadmin | _peerdb_minioadmin | MINIO_SECRET_KEY |
| Catalog DB | postgres | postgres | CATALOG_PASSWORD |
| Jupyter | N/A | Token: databox | JUPYTER_TOKEN |
| Grafana | admin | admin123 | GRAFANA_ADMIN_PASSWORD |
| Langflow | admin | admin123 | LANGFLOW_SUPERUSER_PASSWORD |
Note: ClickHouse passwords are defined in volumes/clickhouse/etc/clickhouse-server/users.d/users.xml.
To change them, edit this file directly before starting the stack.
- Run on localhost only
- Use auto-generated API keys
- Don't expose ports to external networks
- Regularly update Docker images
- Change all default credentials
- Set
AGENT_API_KEYenvironment variable - Use a reverse proxy with TLS
- Implement network segmentation
- Enable Docker content trust
This framework is not designed for production use. In order to make it production ready, some improvements are required, including the following:
- Remove or secure the chat agent
- Implement proper IAM/authentication
- Use secrets management (Vault, AWS Secrets Manager)
- Enable audit logging
- Perform security assessment
- Consider using managed services instead
If you discover a security vulnerability:
- Do NOT open a public issue
- Email the maintainers directly
- Include detailed steps to reproduce
- Allow time for a fix before disclosure
When adding new stacks or features:
- No hardcoded production credentials
- Database ports bound to localhost
- Input validation on all user inputs
- No arbitrary command execution
- Healthchecks for all services
- Logging configuration included
- Documentation updated
CI/CD includes automated security scanning:
- Trivy: Fails on CRITICAL vulnerabilities
- TruffleHog: Checks for exposed secrets
- Lychee: Validates documentation links
Released on 25 June 2026.
- Initial security implementation
- Command whitelist
- API authentication
- input validation