nanocoai/nanoclaw · warning

Ignoring unauthorized approval response

Error message

Ignoring unauthorized approval response

What it means

An approval button/response arrived from a user who is not the designated approver and lacks admin privilege for the agent group. The response is deliberately ignored (claimed but not acted on) to prevent unauthorized approval actions.

Source

Thrown at src/modules/approvals/response-handler.ts:40

  getSession,
  transitionPendingApprovalStatus,
} from '../../db/sessions.js';
import type { ResponsePayload } from '../../response-registry.js';
import { log } from '../../log.js';
import { writeSessionMessage } from '../../session-manager.js';
import type { PendingApproval } from '../../types.js';
import { hasAdminPrivilege, isGlobalAdmin, isOwner } from '../permissions/db/user-roles.js';
import { finalizeReject } from './finalize.js';
import { ONECLI_ACTION, resolveOneCLIApproval } from './onecli-approvals.js';
import { getApprovalHandler, notifyApprovalResolved, REJECT_WITH_REASON_VALUE } from './primitive.js';
import { armReasonCapture } from './reason-capture.js';

export async function handleApprovalsResponse(payload: ResponsePayload): Promise<boolean> {
  const approval = await getPendingApproval(payload.questionId);
  if (!approval) return false;

  if (!(await isAuthorizedApprovalClick(approval, payload))) {
    log.warn('Ignoring unauthorized approval response', {
      approvalId: approval.approval_id,
      action: approval.action,
      userId: payload.userId,
      channelType: payload.channelType,
    });
    return true;
  }

  if (approval.action === ONECLI_ACTION) {
    if (await resolveOneCLIApproval(payload.questionId, payload.value)) {
      return true;
    }
    // Row exists but the in-memory resolver is gone (timer fired or the process
    // was in a weird state). Nothing to do — just drop the row.
    await deletePendingApproval(payload.questionId);
    return true;
  }

View on GitHub (pinned to 294ef2aee8)

Solutions

  1. Have the designated approver (row.approver_user_id) or an owner/global admin click the response
  2. Grant the intended user admin privilege via 'ncl roles grant' if they should be able to approve
  3. Verify payload.userId resolves to the expected <channel>:<handle> identity
Defensive patterns

Strategy: validation

Validate before calling

const authorized = clickerId === row.approver_user_id || (await hasAdminPrivilege(clickerId, row.agent_group_id));
if (!authorized) return; // don't call handleApprovalsResponse

Prevention

When it happens

Trigger: A non-approver group member clicks an approve/reject button on an approval card; a user from a different channel identity than approver_user_id clicks; payload.userId maps to no privileged user.

Common situations: Approval card posted into a shared group channel where anyone can click it; multiple admins where the card was addressed to one; spoofed or misrouted callback payloads.

Understand the failure class

Related errors


AI-assisted analysis of nanocoai/nanoclaw@294ef2aee8 (2026-08-28). Data as JSON: /api/errors/de9534a2c1695c49. Report an issue: GitHub.