How API Keys Are Securely Stored in Maka's Credential Vault: A Deep Dive into Apache Maka's Security Model

Maka stores API keys in a per-workspace credential-vault.json file located in the Electron user-data directory, enforcing OS-level file permissions, size limits, and strict runtime access controls to prevent UI exposure.

The Apache Maka project implements a credential vault system designed to keep sensitive secrets like API keys confidential and isolated from the renderer process. Unlike cloud-based secret managers, Maka adopts a local-first approach where credentials persist only on the user's machine under strict operational constraints.

The Credential Vault Architecture

Maka's credential storage centers on the CredentialVaultDocumentOwner class, which manages a JSON-based vault file that never leaves the local workspace.

File Location and Permissions

The vault file resides in the Electron user-data directory under the specific workspace path:

…/workspaces/default/credential-vault.json

This location benefits from intrinsic operating system protections: the file inherits the OS account permissions of the running Maka process, meaning only the user executing the application can read the contents. As documented in the repository's README, this file remains excluded from version control and never synchronizes to remote repositories.

Vault Structure and Entry Format

Each secret stored in the vault follows the CredentialVaultEntry interface defined in packages/storage/src/runtime-policy/credential-vault-document.ts. An entry contains:

  • locator: A descriptor object identifying the credential scope, kind, and provider
  • credentialId: A unique UUID generated via randomUUID()
  • revision: An incrementing version number for optimistic concurrency
  • secret: The raw API key or token stored as a plain string
  • updatedAt: A timestamp marking the last modification

The vault document itself maintains a bounded size enforced by the VAULT_DOCUMENT_MAX_BYTES constant, preventing unbounded growth that could impact performance or storage.

Writing Secrets to the Vault

The CredentialVaultDocumentOwner.set() method serves as the primary interface for persisting new API keys or updating existing ones.

Input Validation and Size Limits

Before committing any secret to disk, Maka enforces strict validation rules. The system rejects any secret exceeding 64 KB in length, protecting against buffer overflow attacks and accidental paste errors:

// packages/storage/src/runtime-policy/credential-vault-document.ts
const FILE = 'credential-vault.json';                     // ← vault file name
const MAX_SECRET_LENGTH = 64 * 1024;                     // ← secret size limit

If the input passes length validation, the prepareSet routine constructs a CredentialVaultEntry with either incremented revision metadata for updates or fresh UUID and revision fields for new entries.

The set() Method Workflow

The complete write operation follows this sequence:

async set(root: string, rawInput: SetCredentialInput) {
  const prepared = this.prepareSet(await this.read(root), rawInput);
  if (prepared.kind !== 'ready') return prepared;
  await this.commitSet(root, prepared);                 // writes JSON document
  return committed(prepared.document);
}

Persistence occurs through the private write() method, which delegates to writeJsonDocument for atomic file operations. This low-level helper, defined in packages/storage/src/runtime-policy/document-io.ts, guarantees that writes either complete successfully or leave the existing vault intact, preventing corruption during system crashes:

private async write(root: string, document: CredentialVaultDocument) {
  this.assertDocumentSize(document);
  await writeJsonDocument(root, FILE, document, VAULT_DOCUMENT_MAX_BYTES);
}

Runtime Access Controls

Maka distinguishes between the UI layer (renderer process) and runtime operations (main process), ensuring that raw secrets never traverse process boundaries unnecessarily.

How Secrets Are Retrieved

When runtime components require credential material, they invoke the credentialMaterial() utility function rather than accessing the vault entry directly:

export function credentialMaterial(entry: CredentialVaultEntry): RuntimePolicyCredentialMaterial {
  return deepFreeze({ ...credentialBasis(entry), secret: entry.secret });
}

This function returns a RuntimePolicyCredentialMaterial object containing the secret, but only within the short-lived scope of the runtime operation. The use of deepFreeze() prevents accidental mutation of the credential object after creation.

UI Isolation Guarantees

The architecture explicitly prevents the Electron renderer process from ever receiving the raw secret value. When the UI needs to display credential metadata—such as which API keys are configured—it receives only the credentialBasis() data (locator, ID, revision, and timestamps) without the secret field. This architectural boundary ensures that XSS attacks or compromised renderer processes cannot extract API keys from memory.

Security Layers and Protections

Maka implements a defense-in-depth strategy through three concrete mechanisms:

  • File-system isolation: The credential-vault.json file resides in the OS-protected Electron user-data folder, readable only by the account running Maka.
  • Size and format limits: Secrets longer than 64 KB are rejected, and the total vault document size is capped to prevent resource exhaustion.
  • Controlled access patterns: Raw secrets flow only through credentialMaterial() during runtime operations, maintaining strict separation from the UI layer.

Summary

  • API keys persist locally in credential-vault.json within the Electron user-data directory, protected by OS file permissions.
  • The CredentialVaultDocumentOwner.set() method enforces a 64 KB maximum secret size and writes data atomically via writeJsonDocument.
  • Vault entries track UUIDs, revision numbers, and timestamps to support optimistic concurrency.
  • The credentialMaterial() function exposes secrets only to runtime processes, never to the UI renderer.
  • Size constraints at both the secret level (MAX_SECRET_LENGTH) and document level (VAULT_DOCUMENT_MAX_BYTES) prevent abuse.

Frequently Asked Questions

Where does Maka store API keys on disk?

Maka stores API keys in a file named credential-vault.json located within the Electron user-data directory under the active workspace path (e.g., …/workspaces/default/credential-vault.json). This location ensures that only the operating system user running Maka can access the file, and the file never syncs to version control or cloud storage.

What is the maximum size for a secret in Maka?

Maka rejects any secret longer than 64 KB (65,536 bytes) through the MAX_SECRET_LENGTH constant defined in credential-vault-document.ts. Additionally, the entire vault document cannot exceed VAULT_DOCUMENT_MAX_BYTES, protecting against storage abuse or accidental database corruption from oversized entries.

How does Maka prevent the UI from accessing API keys?

The architecture enforces a strict boundary where the Electron renderer process never receives raw secret values. The credentialMaterial() function only executes within the main/runtime process, returning frozen objects containing secrets exclusively to runtime operations. The UI layer can query for credential existence and metadata but receives entries processed through credentialBasis(), which omits the secret field entirely.

Is the credential vault encrypted?

According to the current Apache Maka source code, the credential vault stores secrets as plain text in the JSON file. Security relies on OS-level file permissions restricting access to the user account and the architectural isolation preventing secret exposure to the UI process. The repository does not currently implement application-level encryption at rest for the vault file.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →