IR-2: Compromised API Key
A compromised API key occurs when a credential has been exposed and may have been used by an unauthorized actor. Common causes include accidental commit to a public repository, inclusion in logs or error messages, insecure sharing (Slack, email), or exfiltration from a developer workstation.
For unified credential management and rotation procedures, see Credential Management. For Credential Intelligence breach detection, see Credential Intelligence.
1. Detection
Section titled “1. Detection”This incident is typically detected through one or more of the following signals:
| Signal | Source | Confidence |
|---|---|---|
| CredInt hit — key prefix found in breach corpus | credint_hit audit event |
HIGH |
| GitHub secret scanning alert (via webhook) | External — GitHub Advanced Security | HIGH |
| Customer report — key found in public repository | Out-of-band | HIGH |
| API calls from unexpected IP addresses | auth.api_key_used with anomalous GeoIP |
MEDIUM |
| Unusual request volume on a key | Rate limit events / usage dashboard | MEDIUM |
| Admin operations by non-admin user | Audit events from unexpected user role | HIGH |
Identify the specific credential from a CredInt alert:
# Look up credint audit events for the orgcurl -s "https://api.arbitex.ai/api/v1/admin/audit-logs/?action=credint_hit&created_after=<window_iso>" \ -H "Authorization: Bearer $STAFF_TOKEN" | jq '.events[] | {timestamp, metadata}'The metadata field on a credint_hit event includes key_prefix (first 8 characters), org_id, and match_source (corpus name).
Find credential record from key prefix:
curl -s "https://api.arbitex.ai/api/v1/admin/credentials?key_prefix=<8_char_prefix>" \ -H "Authorization: Bearer $STAFF_TOKEN" | jq '.credentials[] | {id, type, org_id, owner_id, created_at, last_used}'2. Severity classification
Section titled “2. Severity classification”| Condition | Severity |
|---|---|
| Key exposed but no unauthorized use detected | MEDIUM |
| Key used from unexpected IP, no admin operations | HIGH |
| Key used for admin-scoped operations | HIGH |
| New credentials, users, or policy changes created with the key | CRITICAL |
| Data exfiltration confirmed — large content volume or export operations | CRITICAL |
Escalate to CRITICAL immediately if any of the following appear in the audit trail for the compromised key:
credential.created(attacker created a backdoor key)user.createdoruser.role_changed(privilege escalation)policy.updatedordlp.rule_updated(sabotage of security controls)audit.export(data exfiltration)
3. Immediate actions (first 15 minutes)
Section titled “3. Immediate actions (first 15 minutes)”| Step | Action | Command / UI |
|---|---|---|
| 1 | Declare incident | POST /api/staff/incident/declare |
| 2 | Revoke the compromised key immediately | DELETE /api/v1/admin/credentials/{id} |
| 3 | Kill all sessions for the key owner | DELETE /api/v1/admin/users/{user_id}/sessions |
| 4 | Freeze audit log | POST /api/staff/emergency/audit/freeze |
| 5 | Begin audit trail investigation | Query events filtered by key prefix |
Step 1 — Declare incident:
curl -s -X POST "https://api.arbitex.ai/api/staff/incident/declare" \ -H "Authorization: Bearer $STAFF_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "title": "Compromised API key — prefix <key_prefix>", "severity": "HIGH", "playbook": "IR-2", "org_id": "<org_uuid>" }' | jq '{incident_id: .id, ic_expires: .ic_window_expires}'Step 2 — Revoke the compromised key immediately:
curl -s -X DELETE "https://api.arbitex.ai/api/v1/admin/credentials/<credential_id>" \ -H "Authorization: Bearer $STAFF_TOKEN" \ | jq '{status, revoked_at}'Revocation is immediate. There is no grace period — the key becomes invalid for all subsequent requests upon revocation.
Step 3 — Kill sessions for the key owner:
# Find the owner user_id from the credential recordOWNER_ID=$(curl -s "https://api.arbitex.ai/api/v1/admin/credentials/<credential_id>" \ -H "Authorization: Bearer $STAFF_TOKEN" | jq -r '.owner_id')
curl -s -X DELETE "https://api.arbitex.ai/api/v1/admin/users/${OWNER_ID}/sessions" \ -H "Authorization: Bearer $STAFF_TOKEN"Step 4 — Freeze audit log:
curl -s -X POST "https://api.arbitex.ai/api/staff/emergency/audit/freeze" \ -H "Authorization: Bearer $STAFF_TOKEN" \ -H "Content-Type: application/json" \ -d '{"incident_id": "<incident_id>", "reason": "IR-2: Preserving audit evidence for compromised key investigation"}'4. Investigation
Section titled “4. Investigation”After the key is revoked, conduct a thorough investigation of what the key was used for. The goal is to determine the full scope: what was accessed, what was created, and whether lateral movement occurred.
Retrieve all audit events attributed to the compromised key:
# The key_prefix is used as a filter — all requests authenticated with this key share this prefix in metadatacurl -s "https://api.arbitex.ai/api/v1/admin/audit-logs/?org_id=<org_uuid>&key_prefix=<8_char_prefix>&limit=500" \ -H "Authorization: Bearer $STAFF_TOKEN" | jq '.events[] | {timestamp, action, source_ip, metadata}'Check for unauthorized admin operations:
# Look for admin-class actions during breach windowcurl -s "https://api.arbitex.ai/api/v1/admin/audit-logs/?org_id=<org_uuid>&action=admin.config_read&created_after=<breach_start_iso>" \ -H "Authorization: Bearer $STAFF_TOKEN" | jq '.events'Check for new credentials created during breach window:
curl -s "https://api.arbitex.ai/api/v1/admin/audit-logs/?org_id=<org_uuid>&action=credential.created&created_after=<breach_start_iso>" \ -H "Authorization: Bearer $STAFF_TOKEN" | jq '.events[] | {timestamp, metadata}'If any credential.created events are found during the breach window and not attributable to legitimate activity, revoke those credentials immediately — they are backdoors.
Check for new users or role changes:
curl -s "https://api.arbitex.ai/api/v1/admin/audit-logs/?org_id=<org_uuid>&action=user.created&created_after=<breach_start_iso>" \ -H "Authorization: Bearer $STAFF_TOKEN" | jq '.events'Verify audit chain integrity over the breach window:
curl -s -X POST "https://api.arbitex.ai/api/v1/admin/audit/verify" \ -H "Authorization: Bearer $STAFF_TOKEN" \ | jq '{valid, total_entries, errors}'Assess data exfiltration risk:
Review audit events for content API calls (gateway.request, gateway.response) during the breach window. Look for:
- Unusually high request counts compared to normal baseline
- Requests for content types outside the key’s normal usage pattern
- Any
audit.exportevents
5. Containment
Section titled “5. Containment”Scale containment to the confirmed scope of the breach.
| Condition | Action |
|---|---|
| Single key, no lateral movement | Revoke key (done in step 3), issue replacement |
| Backdoor credentials found | Revoke each backdoor, then bulk revoke all org credentials |
| New users created | Disable unauthorized user accounts, audit their activity |
| Policy/DLP changes made | Revert changes, follow IR-3 if DLP was modified |
| Admin operations confirmed | Bulk revoke all org credentials, isolate tenant |
Revoke backdoor credentials found during investigation:
# Repeat for each unauthorized credential ID found in audit trailcurl -s -X DELETE "https://api.arbitex.ai/api/v1/admin/credentials/<backdoor_credential_id>" \ -H "Authorization: Bearer $STAFF_TOKEN"Bulk revoke all org credentials (lateral movement confirmed):
curl -s -X POST "https://api.arbitex.ai/api/staff/emergency/credentials/revoke-all" \ -H "Authorization: Bearer $STAFF_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "org_id": "<org_uuid>", "incident_id": "<incident_id>", "reason": "IR-2: Lateral movement confirmed — bulk revocation of all org credentials" }' | jq '{revoked_count: .revoked}'Tenant isolation (CRITICAL — admin operations or exfiltration confirmed):
curl -s -X POST "https://api.arbitex.ai/api/staff/emergency/tenant/isolate" \ -H "Authorization: Bearer $STAFF_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "org_id": "<org_uuid>", "incident_id": "<incident_id>", "reason": "IR-2 CRITICAL: Admin operations or data exfiltration confirmed — tenant isolated" }'6. Recovery
Section titled “6. Recovery”Begin recovery only after containment is complete and the breach scope is fully understood.
| Step | Action | Verification |
|---|---|---|
| 1 | Revert any unauthorized config changes | Check each resource class modified during breach |
| 2 | Remove unauthorized users | Audit user.created events, deactivate unauthorized accounts |
| 3 | Issue replacement API key to customer | POST /api/v1/admin/credentials/{id}/rotate |
| 4 | Notify customer to update integrations | Provide new key prefix and rotation instructions |
| 5 | Restore tenant access if isolated | POST /api/staff/emergency/tenant/restore |
| 6 | Verify platform health | /readyz, /health/deep |
Issue replacement credential (rotate):
curl -s -X POST "https://api.arbitex.ai/api/v1/admin/credentials/<credential_id>/rotate" \ -H "Authorization: Bearer $STAFF_TOKEN" \ -H "Content-Type: application/json" \ -d '{"grace_period_seconds": 0}'The rotated response includes the new secret value — provide this to the key owner via a secure channel (Staff UI credential delivery, not email).
Restore tenant access after CRITICAL isolation:
curl -s -X POST "https://api.arbitex.ai/api/staff/emergency/tenant/restore" \ -H "Authorization: Bearer $STAFF_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "org_id": "<org_uuid>", "incident_id": "<incident_id>", "reason": "IR-2: Containment complete, replacement credentials issued, org admin identity verified" }'Verify platform health:
curl -s "https://api.arbitex.ai/readyz" | jq '.'curl -s "https://api.arbitex.ai/health/deep" | jq '{status, db, redis, providers}'7. Communication
Section titled “7. Communication”Initial notification to key owner (within 15 minutes of revocation)
Section titled “Initial notification to key owner (within 15 minutes of revocation)”Subject: [ACTION REQUIRED] Your Arbitex API key has been revoked — security incident
Your API key (prefix: <KEY_PREFIX>) has been revoked due to a security incident.
What happened:Your API key was detected in an external breach corpus / public repository / [source].We have revoked the key immediately to prevent unauthorized access.
What you need to do:1. Contact our security team to verify your identity and receive a replacement key.2. Audit any systems that used this key for unauthorized access.3. Search your codebase and logs for any other exposed secrets.
Your key was last used: [LAST_USED_TIMESTAMP] from IP [LAST_USED_IP]
Incident reference: [INCIDENT_ID]Contact: [email protected]Notification to org admin (if key owner is not the org admin)
Section titled “Notification to org admin (if key owner is not the org admin)”Send simultaneously to the org admin to ensure visibility:
Subject: [ALERT] API key in your organization has been revoked — security incident
An API key belonging to [USER_EMAIL] in your Arbitex organization has been revoked.Reason: Key was found exposed externally.Incident: [INCIDENT_ID]
Please review your organization's credential inventory and contact [email protected]if you have concerns about other exposed credentials.Audit export for customer
Section titled “Audit export for customer”curl -s -X POST "https://api.arbitex.ai/api/v1/admin/audit/export" \ -H "Authorization: Bearer $STAFF_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "org_id": "<org_uuid>", "start_date": "<breach_start_date>", "end_date": "<recovery_complete_date>", "format": "json", "filter_key_prefix": "<8_char_prefix>", "include_metadata": true }' -o "incident-<incident_id>-key-usage-export.json"8. Post-incident
Section titled “8. Post-incident”Evidence preservation checklist:
| Item | Status |
|---|---|
| Compromised key ID and prefix recorded | [ ] |
| Full audit export (breach window) saved to secure storage | [ ] |
| All IP addresses key was used from documented | [ ] |
| All operations performed with key enumerated | [ ] |
| Any backdoor credentials found and revoked | [ ] |
| HMAC chain verification result recorded | [ ] |
| Incident timeline document created | [ ] |
Close incident:
curl -s -X POST "https://api.arbitex.ai/api/staff/incident/<incident_id>/close" \ -H "Authorization: Bearer $STAFF_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "resolution": "Key revoked, scope assessed, replacement issued, customer notified", "root_cause": "<describe: public repo commit / credential stuffing / insider / unknown>", "data_exfiltrated": false }'Lessons learned template:
- What was the exposure path (public repo, log file, Slack message, other)?
- How long was the key exposed before detection?
- Did CredInt detection fire, or was this customer-reported?
- Were any backdoor credentials or users created that were not immediately obvious?
- Does the customer have a secrets scanning solution in their CI/CD pipeline? If not, recommend one.
Related playbooks:
- If the key owner’s account is also suspected compromised: follow IR-1: Compromised Tenant Account
- If DLP rules were modified with the key: follow IR-3: DLP Bypass Detected