# How Secrets Are Stored in `credential-vault.json` and the Security Boundary Between Renderer and Main in Apache Maka

> Learn how Apache Maka stores secrets in credential-vault.json and the security boundary between renderer and main processes. Renderer requests operations, never accessing raw secrets.

- Repository: [The Apache Software Foundation/maka](https://github.com/apache/maka)
- Tags: internals
- Published: 2026-09-01

---

**Apache Maka stores sensitive secrets in a validated JSON vault file that is accessible only to the Electron main process, enforcing a strict security boundary where the renderer process can request credential operations via IPC but never receives raw secret values back across the process boundary.**

Apache Maka implements a hardened credential storage system that keeps API keys and passwords in [`credential-vault.json`](https://github.com/apache/maka/blob/main/credential-vault.json) while maintaining rigorous isolation between the Electron renderer and main processes. This architecture ensures that untrusted UI code cannot access sensitive data directly, with all persistence logic confined to the trusted main process. The system validates every write operation against strict size and schema constraints before committing secrets to disk.

## The [`credential-vault.json`](https://github.com/apache/maka/blob/main/credential-vault.json) Storage Format

[`credential-vault.json`](https://github.com/apache/maka/blob/main/credential-vault.json) serves as the on-disk persistence layer for Maka’s runtime-policy system. The file stores encrypted credentials as a structured JSON document with strict validation rules enforced by the `CredentialVaultDocumentOwner` class in [`packages/storage/src/runtime-policy/credential-vault-document.ts`](https://github.com/apache/maka/blob/main/packages/storage/src/runtime-policy/credential-vault-document.ts).

### Schema Structure and Hard Limits

The vault document contains a top-level object with three core components: a **schema version**, a monotonic **revision number**, and an **entries array**. The implementation enforces rigid capacity constraints to prevent abuse or accidental bloat:

- **Maximum entries**: `MAX_VAULT_ENTRIES = 2,048` (line 49)
- **Maximum secret length**: `MAX_SECRET_LENGTH = 64 * 1024` (64 KB per secret, line 50)
- **Maximum document size**: `VAULT_DOCUMENT_MAX_BYTES` (line 36-43) prevents the JSON payload from exceeding configured byte limits during write operations

When persisting changes, the `writeJsonDocument` method validates the entire serialized payload against these limits before atomic write, ensuring the vault cannot grow unbounded or corrupt due to oversized secrets.

### The CredentialVaultEntry Shape

Each entry within the entries array follows the `CredentialVaultEntry` interface defined at lines 54-58, containing five fields:

- **`locator`**: Describes the credential’s context (connection ID, web-search provider, or network-proxy scope)
- **`credentialId`**: A UUID that uniquely identifies the specific credential
- **`revision`**: Monotonically increasing integer for optimistic-concurrency checks
- **`secret`**: The raw secret string supplied by the user (up to 64 KB)
- **`updatedAt`**: Millisecond timestamp of the last mutation

The separation of `locator` and `credentialId` allows Maka to update credentials in place while maintaining stable references across configuration changes.

## Security Boundary Between Renderer and Main Process

Maka leverages Electron’s process architecture to establish a cryptographic security boundary. The **renderer process** (Chromium-based UI) operates with reduced privileges, while the **main process** (Node.js) maintains exclusive filesystem access and secret handling capabilities.

### Process Isolation Architecture

The renderer process is explicitly prohibited from direct filesystem access. It interacts with secrets exclusively through the **runtime-host IPC channel**, which forwards high-level requests such as *set credential*, *delete credential*, or *query status* to the main process. Conversely, the main process owns the `CredentialVaultDocumentOwner` class and performs all validation, size-checking, and JSON serialization before persisting to [`credential-vault.json`](https://github.com/apache/maka/blob/main/credential-vault.json).

This design ensures that even if the renderer were compromised via malicious third-party scripts or dev-tools exploitation, the attacker could not extract raw secrets from the local filesystem directly.

### IPC Data Flow and Secret Containment

The security boundary operates through a strict three-phase protocol:

1. **Renderer → Main**: The renderer sends a request object via `ipcRenderer.invoke` (e.g., `{ kind: "set", locator: ..., secret: "..." }`) through the `maka:set-credential` channel
2. **Main Process Validation**: The main process calls `CredentialVaultDocumentOwner.prepareSet` or `prepareDelete`, runs schema validation (checking version, entry limits, and secret length at lines 32-33 and 41-43), and writes the updated vault using `writeJsonDocument`
3. **Main → Renderer**: The main process returns a **snapshot** containing only metadata (`credentialId`, `revision`, `updatedAt`, and a `configured` flag); the `secret` field is explicitly **never** serialized back across the IPC boundary

Because the raw secret string remains confined to the main process and is filtered from all IPC responses, the renderer cannot accidentally expose credentials through memory inspection or network logging.

## Implementation Examples

### Main Process Credential Management

In the Electron main process, the `CredentialVaultDocumentOwner` handles all vault operations. The following example demonstrates reading the vault and storing a new API key:

```typescript
// Main-process side (runtime-host)
import { CredentialVaultDocumentOwner } from '@maka/storage/runtime-policy/credential-vault-document.js';

// Read the current vault
const owner = new CredentialVaultDocumentOwner();
const vault = await owner.read('/path/to/workspace');

// Add or update a credential (typically called from IPC handler)
await owner.set('/path/to/workspace', {
  locator: { 
    scope: 'connection', 
    connectionId: 'conn-123', 
    kind: 'api_key' 
  },
  secret: 'my-super-secret',
  expected: null,  // No optimistic-concurrency expectation
});

```

The `set` method internally performs byte-size validation against `MAX_SECRET_LENGTH` and `VAULT_DOCUMENT_MAX_BYTES` before atomic write.

### Renderer Process Interaction

The renderer process uses Electron’s `ipcRenderer` to request credential operations without touching the filesystem:

```typescript
// Renderer-process side (frontend)
import { ipcRenderer } from 'electron';

// Ask the main process to store a secret
ipcRenderer.invoke('maka:set-credential', {
  locator: { 
    scope: 'connection', 
    connectionId: 'conn-123', 
    kind: 'api_key' 
  },
  secret: 'my-super-secret',
}).then((result) => {
  // result.snapshot contains only metadata: credentialId, revision, updatedAt
  // The secret itself is NOT included in the response
  console.log('Credential stored, snapshot:', result.snapshot);
});

```

The renderer receives only the metadata snapshot, confirming successful storage without exposing the sensitive value.

## Key Files and Components

| File | Role |
|------|------|
| [`packages/storage/src/runtime-policy/credential-vault-document.ts`](https://github.com/apache/maka/blob/main/packages/storage/src/runtime-policy/credential-vault-document.ts) | Implements `CredentialVaultDocumentOwner`, vault schema validation, and read/write logic (see lines 49-53 for limits, 54-58 for entry shape, 32-43 for validation) |
| [`packages/storage/src/runtime-policy/coordinator.ts`](https://github.com/apache/maka/blob/main/packages/storage/src/runtime-policy/coordinator.ts) | Mediates requests from the runtime-host to the `CredentialVaultDocumentOwner` |
| `apps/desktop/src/main/*.ts` | Registers IPC handlers (`maka:set-credential`, `maka:get-credential-status`) that forward renderer calls to the coordinator |
| `apps/desktop/src/renderer/*.ts` | Calls `ipcRenderer.invoke` to request credential operations without filesystem access |

## Summary

- **[`credential-vault.json`](https://github.com/apache/maka/blob/main/credential-vault.json)** stores secrets with strict limits: 2,048 maximum entries and 64 KB maximum secret length, enforced by `MAX_VAULT_ENTRIES` and `MAX_SECRET_LENGTH` constants
- **Validation logic** lives exclusively in the main process via `CredentialVaultDocumentOwner`, which checks schema version, entry limits, and document byte size before every write
- **IPC isolation** prevents the renderer from accessing the filesystem directly; all credential operations route through `maka:set-credential` and related channels
- **Secret containment** ensures raw secret values never cross the IPC boundary—renderers receive only metadata snapshots containing `credentialId`, `revision`, and `updatedAt`
- **Optimistic concurrency** uses the `revision` field to prevent race conditions during concurrent credential updates

## Frequently Asked Questions

### What is the maximum size limit for a single secret in Maka?

Maka enforces a hard limit of **64 KB** (65,536 bytes) per secret, defined by `MAX_SECRET_LENGTH = 64 * 1024` in [`packages/storage/src/runtime-policy/credential-vault-document.ts`](https://github.com/apache/maka/blob/main/packages/storage/src/runtime-policy/credential-vault-document.ts). Additionally, the entire vault document cannot exceed `VAULT_DOCUMENT_MAX_BYTES`, preventing oversized JSON payloads from corrupting the storage file.

### Can the renderer process read [`credential-vault.json`](https://github.com/apache/maka/blob/main/credential-vault.json) directly from the filesystem?

No. The renderer process has no direct filesystem access to [`credential-vault.json`](https://github.com/apache/maka/blob/main/credential-vault.json). According to the Apache Maka source code, the renderer must use `ipcRenderer.invoke` to send requests to the main process, which exclusively owns the `CredentialVaultDocumentOwner` class and performs all file I/O operations.

### How does Maka prevent concurrent modifications to credentials?

Maka implements **optimistic concurrency control** using the `revision` field in each `CredentialVaultEntry`. When updating a credential via `prepareSet`, the main process checks the `expected` revision against the current stored value. If the revisions mismatch (indicating another update occurred), the operation fails, preventing lost updates in multi-process scenarios.

### Why doesn't the renderer receive the secret back after storing it?

The IPC handlers in the main process explicitly filter the `secret` field from all responses to the renderer. When `maka:set-credential` succeeds, the main process returns a snapshot containing only `credentialId`, `revision`, `updatedAt`, and a `configured` flag. This security measure ensures that compromised renderer code or browser dev-tools cannot leak raw credentials, as the sensitive data never enters the renderer’s memory space.