Detect (DE) · Authorization
Authorization at the client side layer
deterministic · Outside the model's reasoning
If this concern is breached, how do we know?
What this cell does
Hook decision events (allow/ask/deny/error); auditd watches hook config edits and --no-verify; SIEM rule for multi-deny patterns.
Artifacts (3)
auditd-auth.rulesview on GitHub# ABOUTME: auditd rules for authorization-layer events: hook config edits, allowlist edits, Claude settings edits, --no-verify execve.
# ABOUTME: Drop in /etc/audit/rules.d/ and reload with `augenrules --load`. Confirm with `auditctl -l`.
# Hook directory and individual scripts.
-w /etc/agents/hooks/ -p wa -k hook_config_edit
# MCP allowlist.
-w /etc/agents/mcp-allowlist.json -p wa -k allowlist_edit
# Claude Code per-user settings (if the agent runs as agent-runner). Adjust
# path for other agent users or for project-local .claude/settings.json by
# adding additional -w lines.
-w /home/agent-runner/.claude/settings.json -p wa -k claude_settings_edit
-w /etc/agents/claude-code-prod/config.json -p wa -k claude_settings_edit
# Tier config for the tiered approval hook.
-w /etc/agents/tier-config.yaml -p wa -k tier_config_edit
# --no-verify in any execve. Both long form and short form.
-a always,exit -F arch=b64 -S execve -F a1=*--no-verify* -k git_no_verify
-a always,exit -F arch=b64 -S execve -F a1=*-n* -F exe=/usr/bin/git -k git_no_verify_short
# core.hooksPath manipulation (the documented bypass for pre-commit hooks).
-a always,exit -F arch=b64 -S execve -F a1=*core.hooksPath* -k git_hooks_path_bypass
hook-decision-emit.shview on GitHub#!/usr/bin/env bash
# ABOUTME: Append-only snippet for the deny-then-ask-then-allow hook. Emits a structured decision event before exit.
# ABOUTME: Source this from pre_tool_use.sh after the decision is reached but before the script exits.
emit_decision() {
# Args:
# $1 = decision (allow|ask|deny|error)
# $2 = pattern (the rule that matched, or "default" for no-match)
local decision="$1"
local pattern="${2:-default}"
# SESSION_ID, TOOL_NAME, TOOL_INPUT are set by the calling hook.
local event
event="$(jq -n \
--arg session "${SESSION_ID:-unknown}" \
--arg tool "${TOOL_NAME:-unknown}" \
--arg input "${TOOL_INPUT:-}" \
--arg decision "$decision" \
--arg pattern "$pattern" \
--arg ts "$(date -Iseconds)" \
'{event: "hook_decision", session: $session, tool: $tool, input: $input, decision: $decision, pattern: $pattern, ts: $ts}')"
logger -t agent-sentinel -p user.info "$event"
}
# Usage in your pre_tool_use.sh:
#
# . /etc/agents/hooks/hook-decision-emit.sh
#
# for pattern in "${DENY_PATTERNS[@]}"; do
# if echo "$TOOL_INPUT" | grep -qE "$pattern"; then
# emit_decision deny "$pattern"
# exit 2
# fi
# done
#
# emit_decision allow "default"
# exit 0
sigma-multi-deny.yamlview on GitHub# ABOUTME: Sigma rule that fires when a single agent session accumulates >5 deny events from the PreToolUse hook.
# ABOUTME: Probing pattern indicator. Tune the threshold to your environment's normal deny rate before alerting.
title: Agent session with multi-deny pattern (probing indicator)
id: 4d2c1e8a-9b7f-4c5d-8e6f-2a1b3c4d5e6f
status: experimental
description: >
Detects an agent session that hits more than five deny events from the
PreToolUse hook within a 10-minute window. A correctly behaving agent
encounters denies occasionally; an agent probing for a bypass triggers
many denies in a row. Tune the threshold and window for your environment.
references:
- https://github.com/peopleforrester/agentic-covenants/blob/main/SENTINELS_MATRIX.md
author: agentic-covenants
date: 2026/05/08
logsource:
category: agent_hook
detection:
selection:
event: hook_decision
decision: deny
timeframe: 10m
condition: selection | count(session) > 5
falsepositives:
- Operator iterating on a denylist pattern (mute the alert manually).
- First-run misconfiguration where the deny list is too aggressive (treat as a tuning indicator).
level: medium
tags:
- agent
- authorization
- sentinels
Cell notes
Sentinels, Authorization / Client-side
Control. Hook decision events (allow/ask/deny/error) emitted as structured JSON. Auditd watches for hook config edits and --no-verify. SIEM rule for multi-deny patterns in a single session.
Strength. Deterministic when shipped. Failure modes: decision events not correlated with tool input (counts denies, doesn't reconstruct intent); auditd rule format errors silently disable the rule (verify with auditctl -l); --no-verify rule misses git commit -n short form.
Tooling
- - The PreToolUse hook chain (extends
../../identity/client-side/identity-log-hook.sh). - -
auditd(Linux). - - A SIEM with KQL/Sigma-style query support.
Files in this directory
- -
hook-decision-emit.sh, appendable snippet that extends the deny-then-ask-then-allow hook from../../../controls/authorization/client-side/pre_tool_use.shto emit a structured decision event before exiting. - -
auditd-auth.rules, auditd rules for hook config edits, allowlist edits, Claude Code settings edits, and--no-verifyexecve. - -
sigma-multi-deny.yaml, SIEM rule that fires when a single session accumulates more than 5 deny events; this is a probing pattern indicator.
Verification
# 1. Hook decision logged
echo '{"session_id":"test","tool_name":"Bash","tool_input":{"command":"rm -rf /"}}' \
| /etc/agents/hooks/pre_tool_use.sh
journalctl -t agent-sentinel --since "1 minute ago" | grep hook_decision
# expected: event with decision: deny
# 2. Auditd catches hook config edit
sudo touch /etc/agents/hooks/test
ausearch -k hook_config_edit --start recent
# expected: write event
# 3. Auditd catches --no-verify
git commit --no-verify -m "test" 2>/dev/null || true
ausearch -k git_no_verify --start recent
# expected: execve with --no-verify in args
Common mistakes
- - Decision events not correlated with the underlying tool input (useful for counting denies, not for forensics).
- -
auditctl -lnot run after rule install, typo'd rules silently fail. - -
--no-verifyrule missesgit commit -n. Add both forms.
Citation
NIST CSF 2.0 DE.CM-01, DE.CM-03, DE.CM-09.
Primary failure modes
Documented, not hypothetical. A control whose bypass is undocumented is worse than no control, because somebody trusted it.
- decision events not correlated with tool input
- auditd rule format errors silently disable the rule
- --no-verify rule misses git commit -n short form
Crosswalk
| NIST CSF 2 0 | DE.CM-01, DE.CM-03, DE.CM-09 |
|---|
Cite this cell:
https://agenticcovenants.com/detect/authorization/client-side/