GittonGitton
Back to Blog
philosophy

Security Design Principles Behind Gitton

OS keychain encryption, plugin sandboxing, CSP-based XSS protection, and more. A deep dive into Gitton's security features with actual source code.

Security Design Principles Behind Gitton

Security in the Age of AI Coding

When building Gitton, security was at the center of our design from day one.

For developers using AI coding tools, the Git client is the hub of the development workflow. Repository credentials, API keys, code diffs—everything flows through the Git client. That's why we don't compromise on security.

In this article, we'll walk through Gitton's security features with actual source code.

1. API Key Encryption with OS Keychain

AI provider API keys should never be stored in plaintext files. Gitton uses Electron's safeStorage API to store them in the OS-native secure storage.

// src/main/crypto.ts
import { safeStorage } from 'electron'

export function encryptString(plainText: string): string {
  if (!plainText) return ''

  if (!safeStorage.isEncryptionAvailable()) {
    console.warn('Encryption is not available on this system')
    return Buffer.from(plainText).toString('base64')
  }

  const encrypted = safeStorage.encryptString(plainText)
  return encrypted.toString('base64')
}

On macOS, this uses Keychain. On Linux, libSecret. On Windows, DPAPI. In other words, we leverage the most secure storage each OS provides.

Even if Gitton's database file were to leak, API keys remain encrypted and unusable without OS-level authentication.

2. Plugin Permission System

Gitton is extensible with plugins. But plugins are a potential security risk—malicious plugins could steal API keys or exfiltrate code.

That's why we implemented an Android-style permission system.

// src/main/plugins/types.ts
export const PluginPermission = z.enum([
  'ui:sidebar',         // Add sidebar UI
  'ui:settings',        // Add settings tab
  'settings:read',      // Read settings
  'settings:write',     // Write settings
  'network:fetch',      // Make HTTP requests
  'git:read',           // Read repository files
  'git:write',          // Write repository files
  'git:hooks'           // Manage Git hooks
])

Plugins must declare required permissions in their package.json. And newly installed plugins are disabled by default.

// src/main/plugins/manager.ts
// Register as a new plugin (disabled by default for security)
await queries.addPlugin({
  id,
  name: packageName,
  // ...
  enabled: false  // Disabled by default for security
})

Plugins won't run unless the user explicitly enables them. Users can review permissions before activation.

We also detect when plugin updates change permissions:

// Detect permission changes
const permissionChanged = !this.arePermissionsEqual(
  currentManifest.permissions,
  dbManifest.permissions
)

Version-only updates are auto-applied, but permission changes require user re-approval.

3. Plugin Sandboxing with CSP

Plugin UIs run inside iframes. We apply Content Security Policy (CSP) to prevent malicious script execution.

// src/main/plugins/ui-server.ts
function generateNonce(): string {
  return crypto.randomBytes(16).toString('base64')
}

function buildCSPHeader(nonce: string): string {
  const allowedDomains = pluginManager.getAllAllowedDomains()

  // Nonce-based CSP - only scripts with the nonce can execute
  const scriptSrc = ["'self'", `'nonce-${nonce}'`, ...allowedDomains.script].join(' ')
  const connectSrc = ["'self'", 'https://api.github.com', ...allowedDomains.connect].join(' ')

  return [
    "default-src 'self'",
    `script-src ${scriptSrc}`,
    // ...
  ].join('; ')
}

The key is using nonce-based CSP. We don't use 'unsafe-inline'.

A unique nonce is generated for each request, and only scripts with that nonce are allowed to execute. This means even if an attacker injects inline scripts via XSS, they won't run.

4. Path Traversal Protection

When plugins access files, we prevent access outside the plugin directory.

// src/main/plugins/ui-server.ts
// Security: ensure file is within plugin directory
const resolvedPath = path.resolve(filePath)
const pluginRoot = path.resolve(plugin.path)

if (!resolvedPath.startsWith(pluginRoot)) {
  res.writeHead(403, { 'Content-Type': 'text/plain' })
  res.end('Access denied')
  return
}

Path traversal attacks like ../../etc/passwd are rejected with a 403 response.

5. Secure IPC with contextBridge

The most critical security aspect of Electron apps is communication between the main and renderer processes. Gitton uses Electron's recommended contextBridge API.

// src/preload/index.ts
import { contextBridge, ipcRenderer } from 'electron'

contextBridge.exposeInMainWorld('electronAPI', {
  minimize: () => ipcRenderer.invoke('window:minimize'),
  maximize: () => ipcRenderer.invoke('window:maximize'),
  // ...
})

contextBridge.exposeInMainWorld('terminalAPI', {
  create: (sessionId: string, cwd: string, shell?: string) =>
    ipcRenderer.invoke('terminal:create', { sessionId, cwd, shell }),
  // ...
})

Instead of exposing ipcRenderer directly to the renderer, we wrap and expose only the necessary functions. This way, even if the renderer process is compromised, arbitrary IPC calls cannot be made.

6. Security-Focused AI Code Review

Gitton's AI code review feature focuses on detecting security vulnerabilities by default.

// src/main/ai/index.ts
export const DEFAULT_CODE_REVIEW_PROMPT = `You are an expert code reviewer...

## Focus areas:
- Security vulnerabilities (SQL injection, XSS, etc.)
- Potential bugs or logic errors
- Performance issues
- Missing error handling
- Resource leaks
- Race conditions
- Null/undefined safety
`

In an age where AI writes code, let AI do the security checking. AI catches vulnerabilities that humans often overlook.

7. Local AI Support for Privacy

Sometimes you don't want to send sensitive code to external APIs. Gitton supports Ollama for fully local AI features.

// src/main/ai/index.ts
case 'ollama': {
  const ollama = createOllama({
    baseURL: settings.ollamaBaseUrl || 'http://localhost:11434/api'
  })
  return ollama(modelName) as unknown as LanguageModel
}

With Ollama, commit message generation and code review all happen locally. You can run AI security checks even without network connectivity.

Security is an Ongoing Commitment

These security features aren't a one-time implementation.

  • Vulnerability scanning of dependencies
  • Keeping up with Electron security updates
  • Responding to new attack vectors

Security is an ongoing commitment. Gitton will continue to prioritize security so developers can use it with confidence.

Gitton - The Git Client for Vibe Coding
Integrated terminal for AI coding tools. AI-powered commits, code reviews, and PR management.
/service/gitton

Written by

steelydylan
steelydylan

Web developer and creator of Gitton. Building tools for developers who love Git and AI.