Treat hooks/allowlists as defense-in-depth, not a primary security boundary. Enforce security decisions in a trusted, immutable context, validate inputs strictly, and never depend on code coming from an untrusted repository.
Apply this rule:
.cline/hooks/ or .clinerules/hooks/. Put blocking logic in the job/workflow environment (e.g., global hook outside the checkout) and/or rely on platform/job permissions..gitignore patterns).Example (strict tool auto-approval):
const cline = await ClineCore.create({
clientName: "smart-approval",
capabilities: {
requestToolApproval: async (request) => {
// Validate expected input structure
const input = request.input as { commands?: unknown; files?: unknown };
// Approve only exact whole commands from a fixed allowlist
const safe = new Set([
"ls",
"git status",
"git diff --oneline --stat", // example: choose only truly read-only forms
"git log --oneline -20",
]);
if (request.toolName === "run_commands" && Array.isArray(input.commands)) {
const ok = input.commands.every(
(cmd) => typeof cmd === "string" && safe.has(cmd.trim())
);
return ok ? { approved: true } : { approved: false };
}
return { approved: false };
},
},
});
When you need a hard boundary, use workflow/job permissions or a trusted global enforcement point—not a hook stored in the repository—and keep allowlist logic strict and well-validated.