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
- Have the designated approver (row.approver_user_id) or an owner/global admin click the response
- Grant the intended user admin privilege via 'ncl roles grant' if they should be able to approve
- 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
- Deliver approval cards to DMs, not shared channels
- Keep the approver set minimal and explicitly granted via ncl roles
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
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- --approver is required
- Delivery action denied by guard
- reject-with-reason: cannot reach approver, finalizing plain
- No approval handler registered — row dropped
AI-assisted analysis of nanocoai/nanoclaw@294ef2aee8 (2026-08-28).
Data as JSON: /api/errors/de9534a2c1695c49.
Report an issue: GitHub.