kavachOS

Anomaly detection

Identifying unusual agent behavior by scanning audit logs for denial patterns and privilege escalation attempts.

What anomaly detection does

KavachOS scans the audit log for behavioral patterns that suggest an agent is operating outside its intended scope. The most common signal is a cluster of denied calls that match privilege escalation patterns — an agent repeatedly attempting to access resources it was never granted.

Anomaly detection is not a background process. You call scan() and get back a list of findings at that point in time. This keeps the system predictable: there are no background threads, no persistent state, and no surprise side effects.

Anomaly types

TypeSeverityDescription
privilege_escalationcriticalDenied calls with reasons matching INSUFFICIENT_PERMISSIONS, privilege, or escalation.
high_denial_ratewarningMore than 20% of the agent's recent calls were denied.
rapid_firewarningCall volume in the last hour exceeds a configurable threshold.
unusual_resource_accessinfoThe agent accessed a resource it has no explicit permission for, even if the call succeeded.
off_hours_activityinfoCalls outside the agent's declared timeWindow constraint, if one is set.

scan() queries audit logs directly — it is not a background process and does not push alerts. Call it from a scheduled job, a webhook handler, or a dashboard endpoint.

Anomaly fields

Prop

Type

AnomalyConfig options

Prop

Type

Code examples

Scan a single agent for anomalies

const anomalies = await kavach.audit.query({
  agentId: 'agt_abc123',
  result: 'denied',
  since: new Date(Date.now() - 24 * 3_600_000),
});

// Check for privilege escalation pattern
const escalations = anomalies.filter((entry) => {
  const reason = entry.reason ?? '';
  return (
    reason.includes('INSUFFICIENT_PERMISSIONS') ||
    reason.toLowerCase().includes('privilege') ||
    reason.toLowerCase().includes('escalation')
  );
});

if (escalations.length > 0) {
  console.warn(`${escalations.length} escalation attempt(s) detected for agt_abc123`);
}

Get a denial-rate summary for all agents

const since = new Date(Date.now() - 24 * 3_600_000);

const logs = await kavach.audit.query({ since, limit: 5000 });

const byAgent: Record<string, { total: number; denied: number }> = {};

for (const entry of logs) {
  const bucket = (byAgent[entry.agentId] ??= { total: 0, denied: 0 });
  bucket.total++;
  if (entry.result === 'denied') bucket.denied++;
}

const highDenialAgents = Object.entries(byAgent)
  .filter(([, { total, denied }]) => total > 0 && denied / total > 0.2)
  .map(([agentId, { total, denied }]) => ({
    agentId,
    denialRate: (denied / total) * 100,
  }));

console.log('Agents with >20% denial rate:', highDenialAgents);

Act on critical findings

The most effective response to a privilege escalation detection is to pause the agent while you investigate:

const denied = await kavach.audit.query({
  agentId: 'agt_abc123',
  result: 'denied',
  since: new Date(Date.now() - 3_600_000),
});

const escalations = denied.filter((e) =>
  (e.reason ?? '').includes('INSUFFICIENT_PERMISSIONS'),
);

if (escalations.length >= 3) {
  await kavach.agent.revoke('agt_abc123');
  console.log('Agent revoked after repeated escalation attempts.');
}

agent.revoke() is permanent. If you want to temporarily suspend an agent and restore it later, create a new agent with the same configuration instead of revoking.

Use trust scores as the anomaly aggregate

The anomalyCount field on a trust score is a pre-computed count of privilege escalation attempts, updated each time computeScore runs. It is a cheaper signal than a full scan when you only need the count:

const score = await kavach.trust.computeScore('agt_abc123');

if (score.factors.anomalyCount > 0) {
  console.warn(
    `${score.factors.anomalyCount} anomalies detected. Last denial: ${score.factors.lastViolation}`,
  );
}

Next steps

On this page