Security
Relevant source files
The following files were used as context for generating this wiki page:Security in the Quix application is a multi-faceted system designed to protect sensitive data, ensure the authenticity of communications, and provide granular control over user and channel access. The architecture incorporates request verification for all incoming Slack events, robust encryption for credentials at rest, and a flexible access control model.
Key security pillars include verifying Slack request signatures, encrypting all sensitive credentials like bot tokens and API keys before storing them in the database, and implementing role-based access controls for both users and channels. These measures collectively ensure that data is protected and that the agent operates only within authorized contexts.
Slack Integration Security
The primary interface for Quix is Slack, making the security of this integration paramount. The system employs signature verification to authenticate all incoming requests from Slack.
Request Signature Verification
To prevent forged requests, Quix verifies a signature attached to every incoming HTTP request from Slack. This process uses a shared SLACK_SIGNING_SECRET known only to the Quix application and the configured Slack App.
The verification flow is as follows:
- A request is received from Slack.
- A signature base string is constructed using the request's version, timestamp, and raw body.
- An HMAC-SHA256 hash is computed from the base string using the
SLACK_SIGNING_SECRET. - This computed signature is compared against the
X-Slack-Signatureheader from the request. - If the signatures match, the request is considered authentic and is processed. If not, it is rejected.
This diagram illustrates the Slack signature verification process.
Security Environment Variables
The application relies on several environment variables for its security configuration. These must be set correctly for the application to function securely.
| Variable | Description |
|---|---|
SLACK_BOT_TOKEN | The OAuth token for the Slack bot user, used for API calls to Slack. |
SLACK_SIGNING_SECRET | The secret used to verify the authenticity of requests from Slack. |
OPENAI_API_KEY | The API key for OpenAI, used for LLM interactions. Can be overridden per workspace. |
ENCRYPTION_KEY | A secret key used for encrypting and decrypting sensitive data stored in the database. |
Sources: README.md:30-33, src/lib/utils/encryption.ts:5-6
Credential and Data Encryption
Quix ensures that all sensitive credentials, such as API keys and access tokens, are securely stored by encrypting them before they are persisted to the database.
Encryption Mechanism
The application uses the AES-256-CBC algorithm for symmetric encryption. A 256-bit (32-byte) ENCRYPTION_KEY must be configured in the environment. The encryption.ts utility provides two main functions:
encrypt(text: string): Takes a plaintext string, generates a random 16-byte initialization vector (IV), and returns an IV-prefixed, hex-encoded encrypted string.decrypt(text: string): Takes the IV-prefixed hex string, separates the IV and the encrypted content, and returns the decrypted plaintext string.
Sources: src/lib/utils/encryption.ts:8-30
Encrypted Database Fields
The SlackWorkspace model is central to storing workspace-specific configurations, including sensitive credentials. The model uses custom getters and setters to automatically encrypt data before writing to the database and decrypt it upon reading.
The following diagram shows the SlackWorkspace model and its encrypted attributes.
Key encrypted fields include:
bot_access_token: The Slack bot's OAuth token.openai_key: The workspace-specific OpenAI API key.
Credentials for other integrations (e.g., Postgres, Notion, Okta, MCP) are also collected via modals and are expected to be stored securely, often in their own configuration tables with encrypted fields. For instance, the modals for these connections explicitly state that tokens are stored securely and are not displayed again for security reasons.
Sources: src/database/models/slack-workspace.model.ts:49-62, 166-183, src/slack/views/modals.ts:311-315, 521-526, 686-691
Logging Security
To prevent sensitive information from being exposed in application logs, a utility function encryptForLogs is used. This function is called within the SlackEventsHandlerService before logging responses sent to Slack, ensuring that potentially sensitive data within those responses is not stored in plaintext logs.
Sources: src/slack/slack-events-handler.service.ts:181-184, 240-243, src/lib/utils/encryption.ts:32-34
Access Control
Quix implements a multi-layered access control system to manage who can use the bot and where it can operate. This is configured at the SlackWorkspace level.
Admin and User Roles
The SlackWorkspace model defines two primary levels of access:
- Admins: A list of Slack user IDs stored in the
admin_user_idsarray. Admins have permission to configure the application, such as managing other admins and setting access controls. - General Users: All other users in the workspace.
The isAdmin(userId: string) method on the SlackWorkspace model provides a quick way to check if a user has administrative privileges.
Sources: src/database/models/slack-workspace.model.ts:185-202, src/slack/views/modals.ts:211-236
Authorization Logic
Authorization checks are performed in the SlackEventsHandlerService for incoming messages and app mentions.
- User Authorization: For direct messages (DMs), the system checks if the user is authorized to interact with Quix. This is governed by the
allowedUsersForDmInteractionsetting, which can beQuixUserAccessLevel.EVERYONEorQuixUserAccessLevel.ADMINS_ONLY. TheisUserAuthorizedmethod enforces this rule. - Channel Authorization: For app mentions in channels, the system checks if the channel is in the
allowedChannelIdslist. If the list is empty, the bot is permitted to respond in all channels. Otherwise, it will only respond in the whitelisted channels. TheisChannelAuthorizedmethod enforces this.
This flowchart shows the authorization logic for an incoming event.
Managing Access via Modals
Admins can configure access controls through Slack modals.
- Manage Admins Modal:
publishManageAdminsModalallows admins to add or remove other users from the admin list. - Access Controls Modal:
publishAccessControlModalallows admins to define which channels the bot can operate in and set the access level for DM interactions.
Sources: src/slack/views/modals.ts:211-236, 360-418
API Key Management
The application provides secure modals for users to enter and update API keys and other credentials for third-party integrations.
OpenAI API Key
Each workspace can provide its own OpenAI API key. If no key is set, the application falls back to a trial mode for a limited time (TRIAL_DAYS), using a globally configured OPENAI_API_KEY. The publishOpenaiKeyModal function presents a modal for users to submit their key, which is then encrypted and stored in the SlackWorkspace table.
Sources: src/database/models/slack-workspace.model.ts:141-183, src/slack/views/modals.ts:182-209
Integration Credentials
For other integrations like Postgres, Notion, Okta, and Zendesk, dedicated modals are used to collect connection details. A key security feature of these modals is that they do not display existing tokens or passwords. Instead, they show a message like "Current token is not displayed for security reasons. Enter a new token to update it." This prevents sensitive credentials from being exposed in the UI.
Sources: src/slack/views/modals.ts:311-315, 420-474, 686-691, 755-763