ヘドヨバツホブベラダミェギガエマェプニスザペソゥトィゥドタギ
サヅシネィヶュゾヿゼシニョヵロヨヌヾタムキギプィギヨペシゲィ
ャノテメリゼヸ゠ジイナジバスヰトリソメワメヴアルァ・ネメイヮ
ムラョヱモヹゥガヒベワ゠ギワヂグ・チコケコミホクヿアダテツ゠
ヘアァカェクワヒヮロァノヒヷォプヲボニガヰギュザゲフヽョセセ
ビヂエワヺガユイヂエサキヾドレゲゴァベギヺベキマセネパヶバゾ
ゴワミロヷガヹハヨヂサユパテワコゾシグヴワムア゠ブッヌククパ
ザモヵホヹイォセソヴソナワバズチヶャロァベガピヅォテミホテホ
ヒゾサスユヰヌミアズルヹゥワドガグナヲオズヅルゴヅビヲゥザヰ
ドヺゥカルッ゠ヺソヲーギグムヴヴィビヌピデパヂフヸォンダパヵ
ュヷピノ゠ラニハエマヿケレトバュザヨウダヮリプゾヽヹケゲヾカ
ポョーノ・ヶェピナヽカケェヾョキダヨヽゼヾオヅヽヮテオラハサ
ユヱワヿゴンヴケヿユョヵプヌニャシフマパズヌゲトプレ・ロヮベ
ザレテトヅサワ゠ミニヸスヺケワソポパヅゴフボオユヨヮゲヂヮコ
ゾホヌンラデヂ・ジロエズゼゼタコチアグトトビセヲルユリヸパヅ
ポゥギモヱ゠グプヌムダーォガーセサベヅダルョポヺヴンウカムタ
ダソゥノルャサヾヱヮゲネゲヒネォヶナピエヾザブィホドヱボペュ
ゾヂヂェボスヘズミヱッミヽピチゴヤシヵダゼノグマフノュィケプ
ボヌッヾヲケ゠ャヰォヾヹヌサレセヂパタヿグネカミヘトベィペグ
ィヸスヵゾヷネヾデペヰヘヾャムッフヌゲパギャプドロゴウツエコ
TECH

Credential Management for AI Agent Infrastructure: A Security Framework

Credential management is foundational to infrastructure security. A single exposed API key can compromise entire systems. With AI agents requiring access to multiple services, the credential surface area expands significantly.

This document describes the credential management framework used for ShoreAgents and StepTen operations, covering inventory, storage architecture, access control, rotation policies, and incident response.

Credential Inventory

Current inventory across all projects:

| Provider | Keys | Purpose | |----------|------|---------| | OpenAI | 2 | GPT-4, DALL-E, embeddings | | Anthropic | 2 | Claude API access | | Google | 3 | Gemini, Imagen, Workspace | | Supabase | 10 | 5 projects × 2 keys each | | Vercel | 3 | Deployment APIs | | GitHub | 2 | Repository access | | Xero | 1 | Accounting API | | ElevenLabs | 1 | Text-to-speech | | Replicate | 1 | Image processing | | Runway | 1 | Video generation | | Resend | 1 | Email sending | | Open Exchange Rates | 1 | Currency data | | Others | 22 | Various services |

Total: 50+ credentials requiring management.

Classification System

Credentials are classified by potential impact of compromise:

Tier 1 — Critical

Credentials providing administrative or cross-system access: - Google Workspace service account (can impersonate any domain user) - Supabase service role keys (bypass all RLS policies) - Cloud platform administrative credentials

Requirements: - Monthly rotation - Hardware key protection where supported - Access limited to essential systems only - Enhanced monitoring

Tier 2 — Important

Credentials providing significant data access: - Database connection strings - Financial API credentials (Xero) - GitHub with write access - Production AI model keys

Requirements: - Quarterly rotation - Encrypted storage - Access logging - Regular access review

Tier 3 — Standard

Credentials with limited scope: - Single-purpose API keys (image generation) - Read-only access tokens - Development environment credentials

Requirements: - Annual rotation - Standard encrypted storage - Basic access logging

Storage Architecture

Central Repository

The authoritative source for all credentials is a Supabase table with restricted access:

`sql CREATE TABLE api_credentials ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name TEXT UNIQUE NOT NULL, provider TEXT NOT NULL, credential_value TEXT NOT NULL, tier INTEGER NOT NULL, environment TEXT DEFAULT 'production', rotated_at TIMESTAMPTZ, rotation_schedule TEXT, notes TEXT, projects_using TEXT[], created_at TIMESTAMPTZ DEFAULT NOW() );

-- Restrict access to service role only ALTER TABLE api_credentials ENABLE ROW LEVEL SECURITY; -- No SELECT policies = no access via anon or authenticated roles `

Access requires the service role key, which is itself a Tier 1 credential.

Local Development

Development machines use local credential files:

` ~/.openclaw/workspace/credentials/ ├── api-keys.json ├── google-service-account.json ├── supabase-*.json └── xero-api.json `

Security requirements for local storage: - Directory excluded from all version control - Disk encryption enabled (FileVault/BitLocker) - File permissions restricted to owner - Not synced to cloud storage services

Production Environment

Production credentials are stored as environment variables in deployment platforms: - Vercel: Project Settings → Environment Variables - Supabase Edge Functions: Secrets management - GitHub Actions: Repository secrets

Never stored in code or configuration files that might be version controlled.

Access Patterns

Retrieval Interface

`typescript class CredentialManager { private cache: Map = new Map(); async get(name: string): Promise { // Check cache const cached = this.cache.get(name); if (cached && cached.expires > Date.now()) { return cached.value; } // Try local file (development) const localValue = await this.readLocalCredential(name); if (localValue) { this.cacheValue(name, localValue); return localValue; } // Fall back to central repository const remoteValue = await this.fetchFromRepository(name); if (remoteValue) { this.cacheValue(name, remoteValue); await this.logAccess(name); return remoteValue; } throw new Error(Credential not found: ${name}); } private async logAccess(name: string): Promise { await supabaseAdmin.from('credential_access_log').insert({ credential_name: name, accessor: this.getAccessorIdentity(), accessed_at: new Date().toISOString(), context: this.getAccessContext() }); } } `

Access Logging

Every credential access is logged:

`sql CREATE TABLE credential_access_log ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), credential_name TEXT NOT NULL, accessor TEXT NOT NULL, accessed_at TIMESTAMPTZ DEFAULT NOW(), context TEXT );

-- Useful queries -- Recent accesses SELECT * FROM credential_access_log WHERE accessed_at > NOW() - INTERVAL '24 hours' ORDER BY accessed_at DESC;

-- Access frequency SELECT credential_name, COUNT(*), MAX(accessed_at) FROM credential_access_log GROUP BY credential_name ORDER BY COUNT(*) DESC;

-- Anomalous timing SELECT * FROM credential_access_log WHERE EXTRACT(HOUR FROM accessed_at) NOT BETWEEN 6 AND 23; `

Rotation Procedures

Scheduled Rotation

`bash #!/bin/bash # rotate-credential.sh

CREDENTIAL_NAME=$1 NEW_VALUE=$2

# Update central repository curl -X PATCH "https://$SUPABASE_URL/rest/v1/api_credentials?name=eq.$CREDENTIAL_NAME" \ -H "apikey: $SUPABASE_SERVICE_KEY" \ -H "Authorization: Bearer $SUPABASE_SERVICE_KEY" \ -H "Content-Type: application/json" \ -d "{ \"credential_value\": \"$NEW_VALUE\", \"rotated_at\": \"$(date -Iseconds)\" }"

# Update Vercel projects for project in admin web staff client; do vercel env rm $CREDENTIAL_NAME production -y --cwd apps/$project 2>/dev/null echo $NEW_VALUE | vercel env add $CREDENTIAL_NAME production --cwd apps/$project done

# Trigger redeployments for project in admin web staff client; do vercel deploy --prod --cwd apps/$project done

echo "Rotation complete for $CREDENTIAL_NAME" `

Rotation Monitoring

Automated check for overdue rotations:

`sql SELECT name, tier, rotation_schedule, rotated_at, CASE rotation_schedule WHEN 'monthly' THEN rotated_at + INTERVAL '30 days' WHEN 'quarterly' THEN rotated_at + INTERVAL '90 days' WHEN 'annual' THEN rotated_at + INTERVAL '365 days' END AS due_date, CASE WHEN rotation_schedule = 'monthly' AND rotated_at + INTERVAL '30 days' < NOW() THEN 'OVERDUE' WHEN rotation_schedule = 'quarterly' AND rotated_at + INTERVAL '90 days' < NOW() THEN 'OVERDUE' WHEN rotation_schedule = 'annual' AND rotated_at + INTERVAL '365 days' < NOW() THEN 'OVERDUE' ELSE 'OK' END AS status FROM api_credentials ORDER BY CASE WHEN tier = 1 THEN 0 ELSE tier END, due_date; `

Weekly notification if any credentials are overdue.

Agent-Specific Considerations

AI agents introduce unique security considerations:

Context Window Exposure

Credentials appearing in agent context could be logged or exposed in debugging output.

Mitigation: Never inject credentials directly into prompts. Use placeholder references that are resolved at execution time.

Tool Use Risks

Agents with HTTP request capabilities could potentially exfiltrate credentials through crafted requests.

Mitigation: Input validation, URL allowlisting, credential injection after prompt processing.

Memory Persistence

Agents should not write credentials to persistent memory files.

Mitigation: Credentials are stored only by reference (credential name, not value) in agent memory systems.

Environment Separation

Development

  • Separate credential sets with limited permissions
  • Points to development/staging resources
  • Can be rotated independently of production

Production

  • Full-permission credentials
  • Stricter access controls
  • Enhanced monitoring

Mapping

`typescript function getCredentialName(baseName: string): string { const env = process.env.NODE_ENV || 'development'; if (env === 'production') { return baseName; } return ${baseName}_${env}; }

// Usage const apiKey = await credentials.get(getCredentialName('openai_api_key')); // Returns 'openai_api_key' in production // Returns 'openai_api_key_development' in development `

Incident Response

Suspected Compromise

  1. 1.Immediate revocation — Don't investigate first; revoke the potentially compromised credential
  2. 2.Generate replacement — Create new credential from provider
  3. 3.Update all references — Central repository, environment variables, local files
  4. 4.Deploy updates — Ensure all systems use new credential
  5. 5.Audit access logs — Determine what was accessed with old credential
  6. 6.Investigate source — How did exposure occur?
  7. 7.Document incident — Record timeline, impact, remediation, prevention measures

Recovery Checklist

`markdown ## Credential Compromise Response

- [ ] Revoked compromised credential at provider - [ ] Generated new credential - [ ] Updated central repository - [ ] Updated Vercel environment variables - [ ] Updated local development files - [ ] Triggered production redeployments - [ ] Verified services functioning with new credential - [ ] Reviewed access logs for unauthorized use - [ ] Identified exposure vector - [ ] Implemented prevention measures - [ ] Created incident report `

Naming Conventions

Consistent naming prevents confusion:

` {provider}_{purpose}_{qualifier} `

Examples: - openai_api_key - supabase_service_key_stepten_army - google_service_account_workspace - stripe_secret_key_production

Avoid: - api_key — which API? - prod_key — key for what? - openai — production or test?

FAQ

Why not use a dedicated secrets manager like HashiCorp Vault?

For the current operational scale, Supabase with RLS provides adequate security with lower operational complexity. Vault adds infrastructure that requires its own maintenance, monitoring, and expertise. The approach scales to hundreds of credentials; at thousands, dedicated secrets management becomes more attractive.

How do you handle credentials in CI/CD?

GitHub Actions uses repository secrets. Vercel uses project environment variables. Credentials are never echoed in build logs—build scripts use secret masking.

What if a developer leaves the team?

All credentials they had access to are rotated. Their access to the central repository is revoked. Local credential files on their machines are assumed compromised and treated accordingly.

How do you test without exposing production credentials?

Test environments use separate credential sets pointing to sandbox/development resources. Production credentials never exist in development environments.

What about the Supabase service key that protects the credential table?

It's the most sensitive credential—Tier 1, monthly rotation, stored only in production environment variables and a secure backup location. Access is limited to systems that genuinely require administrative database access.

Security is cumulative. Each control adds to overall protection. The goal is defense in depth—no single point of failure can compromise the system.

securityapi-keyscredentialssecrets-managementinfrastructure
STEPTEN™

I built an army of AI agents. This is their story — and the tools to build your own. No products to sell. Just a founder sharing the journey.

CONNECT

© 2025-2026 STEPTEN™ · Part of the ShoreAgents ecosystem

Built with Next.js · Supabase · AI Agents · From Clark Freeport Zone, Philippines 🇵🇭