code<spar>

Security

CodeSpar security architecture including RBAC roles, permission mapping, token-based approval system, audit trail with hash chain integrity, cross-channel identity resolution, and safety guardrails.

Security

CodeSpar implements defense-in-depth security with role-based access control (RBAC), a token-based approval system, an append-only audit trail with hash chain integrity, cross-channel identity resolution, and mandatory safety guardrails for high-risk operations.

RBAC — Role-Based Access Control

Roles

CodeSpar defines six roles, ordered from most to least privileged:

RoleDescriptionTypical User
ownerFull control over project, agents, and configurationProject creator, tech lead
maintainerCan execute all commands, manage autonomy and linksSenior developers
operatorCan execute tasks and deploys, limited configurationDevOps engineers
reviewerCan review PRs and view status, no executionJunior developers, QA
read-onlyCan only view status, logs, and memory statsStakeholders, observers
emergency_adminCan execute kill without approval at any autonomy levelOn-call engineers

Permission Matrix

Each role maps to a set of permitted intents (commands):

Permissionownermaintaineroperatorreviewerread-onlyemergency_admin
statusYesYesYesYesYesYes
helpYesYesYesYesYesYes
logsYesYesYesYesYesYes
context / memoryYesYesYesYesYesYes
whoamiYesYesYesYesYesYes
registerYesYesYesYesNoYes
prsYesYesYesYesYesYes
reviewYesYesYesYesNoYes
instructYesYesYesNoNoYes
fixYesYesYesNoNoYes
linkYesYesNoNoNoYes
unlinkYesYesNoNoNoYes
deployYesYesYesNoNoYes
rollbackYesYesNoNoNoYes
approveYesYesYesNoNoYes
autonomyYesYesLimited*NoNoYes
killYesYesNoNoNoYes

* Operators can set autonomy up to L4. Only owners and maintainers can set L5.

15 Permissions

The complete list of permissions that map to command intents:

#PermissionIntentRisk Level
1view:statusstatuslow
2view:helphelplow
3view:logslogslow
4view:memorycontext, memorylow
5view:identitywhoamilow
6view:prsprslow
7manage:identityregisterlow
8execute:reviewreviewlow
9execute:taskinstructmedium
10execute:fixfixmedium
11manage:linklink, unlinkmedium
12execute:deploydeployhigh
13execute:rollbackrollbackcritical
14manage:autonomyautonomymedium
15execute:killkillcritical

Approval System

High-risk actions require explicit human approval before execution. The approval system is token-based with several safety mechanisms.

How It Works

  1. A user requests a high-risk action (e.g., @codespar deploy production)
  2. CodeSpar generates a unique approval token (e.g., dp-a1b2c3)
  3. A notification is sent to connected channels with the token
  4. An authorized user approves with @codespar approve dp-a1b2c3
  5. The action executes

Approval Token Format and Prefixes

Approval tokens follow the format {prefix}-{random}, where the prefix indicates the type of action being approved:

PrefixActionExample Token
dp-Deploydp-a1b2c3
rb-Rollbackrb-x9y8z7
sg-Suggested action (auto-proposed by L2+ agents)sg-m4n5o6
tk-Task execution (at certain autonomy levels)tk-p7q8r9
kl-Kill switch (emergency stop)kl-j1k2l3

The random portion is a cryptographically secure 6-character alphanumeric string, providing sufficient uniqueness for the token's 30-minute lifespan.

Approval Token Properties

PropertyValue
Format{prefix}-{random} (e.g., dp-a1b2c3)
Expiration30 minutes (configurable via APPROVAL_TIMEOUT)
Single-useYes — token is invalidated after use
Cross-channelYes — approve from any connected channel

Safety Mechanisms

Self-Approval Blocking

A user cannot approve their own request. This prevents a single person from both requesting and approving a high-risk action.

@alice: @codespar deploy production
@codespar: ⏳ Approval required. Token: dp-a1b2c3

@alice: @codespar approve dp-a1b2c3
@codespar: ❌ Cannot self-approve. Another team member must approve this action.

Quorum

For production deployments, organizations can configure a quorum — the minimum number of approvals required:

ConfigurationDefaultDescription
APPROVAL_QUORUM1Number of approvals required
APPROVAL_TIMEOUT30mTime before approval expires
ALLOW_SELF_APPROVEfalseWhether requestor can self-approve

Expiration

Approval tokens expire after 30 minutes (configurable). Expired tokens cannot be used:

@codespar approve dp-a1b2c3

❌ Approval token expired. Request the action again.

Audit Trail

Every action in CodeSpar is recorded in an append-only audit log with cryptographic hash chain integrity.

What Gets Logged

Event TypeExamples
User commandsAll 17 commands and their results
Agent actionsTask execution, PR review, deploy, auto-actions
System eventsWebhook receipt, agent spawn/terminate, errors
Access controlPermission denials, role changes
ApprovalsApproval requests, grants, denials, expirations

Hash Chain Integrity

Each audit entry includes a SHA-256 hash that chains to the previous entry, creating a tamper-evident log.

How It Works

Every audit entry contains these fields for integrity verification:

interface AuditEntry {
  id: string;
  timestamp: string;
  actor: string;          // Identity ID or "system"
  action: string;         // Command or event type
  result: string;         // "success", "denied", "error"
  metadata: object;       // Action-specific data
  previousHash: string;   // Hash of the previous entry
  hash: string;           // SHA-256 hash of this entry
}

The hash for each entry is computed as:

Entry N hash = SHA-256(
  Entry N-1 hash +
  timestamp +
  actor +
  action +
  result +
  JSON.stringify(metadata)
)

Hash Chain Verification

The chaining works as follows:

  1. Entry 0 (genesis): previousHash is "0" (the initial seed). Its hash is SHA-256("0" + timestamp + actor + action + result + metadata).
  2. Entry 1: previousHash is Entry 0's hash. Its hash includes Entry 0's hash in the computation.
  3. Entry N: previousHash is Entry N-1's hash. The chain continues.

To verify the audit trail's integrity:

For each entry from 0 to N:
  1. Recompute: expected = SHA-256(entry.previousHash + entry.timestamp + ...)
  2. Compare: expected === entry.hash
  3. Verify: entry.previousHash === previousEntry.hash

If any entry has been modified, its hash will not match the recomputed value, and all subsequent entries' previousHash fields will be invalid. This makes tampering detectable.

Example Chain

Entry 0: hash="a3f2..." previousHash="0"
Entry 1: hash="b7c1..." previousHash="a3f2..."
Entry 2: hash="d9e4..." previousHash="b7c1..."
Entry 3: hash="f1a8..." previousHash="d9e4..."

If Entry 1 is modified, its hash changes from "b7c1..." to something else. Entry 2's previousHash still says "b7c1...", which no longer matches Entry 1's actual hash — tampering detected.

Retention

SettingDefault
Retention period365 days
StorageFile-based (.codespar/audit/) or PostgreSQL
ExportAvailable via Audit API pagination

Cross-Channel Identity Resolution

CodeSpar maintains a cross-channel identity system that links users across WhatsApp, Slack, Discord, and Telegram. This is critical for consistent RBAC enforcement, cross-channel approvals, and unified audit trails.

How the Identity Store Works

The identity store maintains a persistent mapping between channel-specific user IDs and a unified CodeSpar identity.

Data Structure

interface Identity {
  id: string;                    // Unique identity ID (e.g., "identity-001")
  displayName: string;           // Registered name (e.g., "John Silva")
  role: string;                  // RBAC role (e.g., "maintainer")
  channels: ChannelIdentity[];   // Linked channel accounts
  registeredAt: string;          // ISO 8601 timestamp
}
 
interface ChannelIdentity {
  channelType: string;    // "slack", "whatsapp", "discord", "telegram"
  channelUserId: string;  // Platform-specific user ID
  displayName: string;    // Platform-specific display name
  linkedAt: string;       // When this channel was linked
}

Registration and Linking Flow

  1. First contact: When a user sends any message from a channel, CodeSpar creates a temporary identity record with the channel-specific ID and a default read-only role.

  2. Registration: The user sends @codespar register John Silva. CodeSpar:

    • Checks if an identity with display name "John Silva" already exists
    • If not: creates a new identity with the display name and links the current channel
    • If yes: links the current channel to the existing identity
  3. Cross-channel linking: The same user sends @codespar register John Silva from a different channel (e.g., WhatsApp after already registering from Slack). CodeSpar:

    • Finds the existing identity with display name "John Silva"
    • Adds the WhatsApp channel identity to the existing record
    • Both channels are now linked under one identity
  4. Identity resolution: On every subsequent message, CodeSpar looks up the channel-specific user ID in the identity store. If found, the message is attributed to the resolved identity, and the identity's RBAC role is applied.

Storage

Identity records are stored in the identity store:

  • File storage: .codespar/identities/ directory (one JSON file per identity)
  • Database: identities table when DATABASE_URL is configured

Cross-Channel Capabilities

With linked identities:

  • Approve from any channel: A deploy requested in Slack can be approved from WhatsApp
  • Unified audit trail: All actions across channels are attributed to the same identity
  • Consistent permissions: RBAC role applies regardless of which channel is used
  • Single notification: Avoid duplicate alerts when the same user is on multiple channels

Identity Lookup

curl "http://localhost:3000/api/identity?channelType=slack&channelUserId=U1234ABCD"

See the Memory API for full details.


Safety Guardrails

Regardless of autonomy level, RBAC role, or configuration, CodeSpar enforces hard safety guardrails.

Never Auto-Executed

These actions always require explicit human approval:

ActionReason
Production deploymentsDirect user impact, requires verification
RollbacksDestructive, may cause data inconsistency
Data migrationsIrreversible database changes
Security-sensitive changesCredential rotation, permission changes, secret updates
Infrastructure modificationsScaling, networking, resource allocation changes
Kill switchEmergency stop affects all running agents

Guardrail Enforcement

Guardrails are enforced at the engine level and cannot be overridden by configuration, RBAC roles, or autonomy settings. Even at L5 (Full Auto) with owner role:

# L5 autonomy, owner role
@codespar deploy production

# Still requires approval:
⏳ Production deploy requires approval (safety guardrail).
Approve with: @codespar approve dp-a1b2c3

The only exception is emergency_admin for the kill command, which can be executed without approval to enable rapid incident response.


Rate Limiting

Note: Rate limiting is not yet implemented. This is a roadmap item planned for a future release.

The planned rate limiting system will enforce:

LimitPlanned ValueScope
Commands per user per minute10Per identity
API requests per minute60Per API key
Webhook events per minute100Per repository
Agent spawns per hour20Per project

Rate limiting will be configurable per organization and will apply to both chat commands and API requests.


Security Checklist

When deploying CodeSpar to production:

  • Set ANTHROPIC_API_KEY and GITHUB_TOKEN as environment variables (never in code)
  • Use HTTPS for WEBHOOK_BASE_URL
  • Configure reverse proxy or API gateway for authentication
  • Set appropriate autonomy level (L1 recommended for production)
  • Assign RBAC roles to all team members
  • Verify audit trail is being written (check .codespar/audit/)
  • Set up monitoring for agent errors and unusual activity
  • Configure approval quorum for production deploys (2+ recommended)
  • Disable self-approval (ALLOW_SELF_APPROVE=false)
  • Review and test the kill switch procedure

Next Steps