Back to plugin

Security audit

Agent Knock Knock

Security checks for vulnerabilities and agentic risk

Overview

This is a powerful but disclosed local terminal-control plugin for existing Codex and Claude Code sessions, with scoped safeguards around sensitive actions.

Install only if you are comfortable giving this plugin controlled access to your local Codex or Claude Code terminal panes. Keep tmux/Herdr sockets and the AKK store private, review approval prompts carefully, and enable autoApprove only for narrow commands and trusted workspace roots.

Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Memory PoisoningPersistent Context Injection, Context Window Stuffing, Memory Manipulation
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (4)

Memory Manipulation

High
Category
Memory Poisoning
Content
- Explicit requests to diagnose an ambiguous current Codex foreground: call `agent_knock_knock_identify_foreground({terminal_id})` only from that row's current action. Explain that it types one `/status` command, changes no Store state, and returns a non-authorizing 30-second observation. Never use the result as authority for a later mutation.
- Explicit requests to identify an ambiguous Codex foreground and send one task atomically: use the row's exact `agent_knock_knock_identify_and_send({terminal_id,request})` action. Do not synthesize this path for an ordinary Send or split it into identify-then-send calls.
- Requests to list resumable native threads for an exact terminal: call `agent_knock_knock_list_resumable_threads` with the terminal row's prefilled `terminal_id`.
- Explicit requests to start a new thread or clear context: call `agent_knock_knock_new_thread({terminal_id})` only from an advertised `new_thread` action.
- Explicit requests for low-level recovery of a listed binding conflict: after explicit user confirmation, call only the advertised `agent_knock_knock_reconcile_binding({terminal_id,conflicting_session_id})`. AKK derives its revision and binding fences privately, detaches the stale/conflicting binding without adopting the live thread, and requires a fresh list afterward. Do not use it in place of an advertised follow-current send.
- Explicit requests to resume prior native context: first call `agent_knock_knock_list_resumable_threads`; then call `agent_knock_knock_resume_thread({terminal_id,native_thread_id})` for one `resumable=true` candidate using its complete UUID. For “previous” / “刚才那个”, proceed only when the fresh result advertises `previous.available_actions.resume_thread`; use that exact semantic-ID action and never substitute the newest row. Human-facing numbers and short IDs are resolved privately and are never structured tool arguments.
- Requests to inspect current output or ask what a task is doing: call `agent_knock_knock_status`.
Confidence
80% confidence
Finding
Skill manipulates agent memory, state, or stored context. Memory corruption can alter personality, override safety rules, or cause unpredictable behavior.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
- `/akk respond <turn-selector>: <answer>`: answer a coding-agent question inside a `waiting_for_openclaw` Turn.
- `/akk cancel <turn-selector>`: interrupt the exact Turn without closing its terminal pane.

For human-facing ordinary-send slash forms, a selector may be `codex`, `claude`, `only`, `latest`, or an `@short-ref` returned by `AKK list`. These selectors are only a resolution layer and fail closed when the target is missing or ambiguous. The v28 structured-tool contract never exposes a selector or opaque authority value: the model supplies semantic IDs only. `send({session_id,request})` is strict `session_exact`; `send({terminal_id,request})` is either managed `terminal_follow_current` or user-priority `terminal_user_explicit`, exactly as advertised; the two target fields are mutually exclusive, and both may be omitted only when AKK must prove one unique send-ready pane. Codex `terminal_user_explicit` depends on the exact live terminal/process, a scanned non-blocked approval state, and no active input-owning questionnaire/editor—not ordinary main-Composer visibility, stability, exactness, parsed working activity, or AKK Store, Turn, Session, transfer, transition, ledger, or ownership. Codex 0.154's exact collapsed async-question summary leaves the main Composer sendable; an expanded, clipped, or ambiguous async editor and an active-writer resume viewer remain zero-input boundaries. It applies `replace_current_composer_and_submit`: physical fallback sends `C-u` once to replace the current Composer, injects the request, waits through the paste window, and dispatches Enter exactly once. After text injection, Composer observation must never veto Enter. Claude Code remains exact-empty-only. AKK tries managed delivery where its strict empty-Composer pre-input authority exists; after user-explicit Codex text injection, that path follows the same no-Composer-veto Enter rule. A source-less Codex terminal with zero, one, or many pre-existing rollout roots freezes that
...[truncated 24 chars]
Confidence
80% confidence
Finding
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
Hard creation failure is limited to an absent exact terminal, inability to identify its endpoint/process, absence of both a durable exact-task anchor and a read-only screen-status activity path, or inability to create/write the durable Watch Store. Existing identical active observation may return its current `watch_id` instead of failing as a duplicate.

Approval attention is notification-only for every Watch: never call an approval tool for a `watch_id`, send approval keys, or apply `autoApprove`. Questionnaire attention is different. An automatic exact request-bound Watch created by `terminal_user_explicit` unmanaged fallback can, after exact request acceptance and attribution, emit `interaction_required`; call Status with its exact `watch_id`, show the projected question to the user, and use `respond_interaction({watch_id,...})` only when that fresh owner-bound projection advertises `capabilities.respond=true`. A terminal-activity Watch or `interaction_manual_required` callback remains notify-only: tell the user to inspect and answer in the live TUI, and send no questionnaire input. Each new exact attention fingerprint is notified once while the Watch remains active. Terminal outcomes settle once. The durable outbox uses deterministic notification IDs/idempotency and leased retry, so startup and periodic supervision can safely recover callback delivery after AKK, OpenClaw, or Gateway restart.

The current integrations register the complete capability-handshake-verified semantic AKK tool catalog and list action-contract v28. Structured OpenClaw, Pi, and DeepSeek Harness Lists use compact projection v1 and point here for the static contract; the CLI keeps the complete operator/debug action contract. Every structured model action carries semantic IDs only; opaque fences, Composer digests, and draft text are derived or retained privately. Watch uses `agent_knock_knock_watch({terminal_id})`, `agent_knock_knock_status({watch_id})`, and `agent_knock_knock_unwatch({watch
...[truncated 24 chars]
Confidence
85% confidence
Finding
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
Unknown, stale, expired, ambiguous, persistent-permission, replayed, or changed requests must not receive any decision key. If semantic `reject` is not advertised, tell the user to resolve the prompt directly in the terminal; use `agent_knock_knock_cancel` only when the user explicitly intends to interrupt the whole Turn, never as a disguised No choice.

A trusted, default-disabled plugin `autoApprove` policy may independently approve only an exact configured agent, command vector, and canonical root listed in `autoApprove.rules[].workspaces`, backed by current terminal evidence. A rule may list multiple workspace roots. These entries are the only workspace boundary for automatic approval; they do not limit pane discovery or manual control. The model cannot create or modify that policy.

## Terminal Sessions
Confidence
85% confidence
Finding
This skill permits a plugin-level 'autoApprove' policy to approve terminal prompts without per-action user confirmation if an exact agent/command/workspace rule matches. Even though it is described as trusted and default-disabled, automatic approval of terminal-executed actions materially increases the chance of privilege misuse, unsafe command execution, or policy bypass if rules are overly broad, misconfigured, or if terminal evidence is spoofed or misinterpreted.

Static analysis

Detected: suspicious.dangerous_exec

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
dist/src/codex-process-incarnation.js:14
Evidence
const result = spawnSync(ps, ["-o", "lstart=", "-p", String(pid)], {

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
dist/src/codex-store-adapter.js:366
Evidence
const child = spawn("sqlite3", args, {

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
dist/src/command-json-callback-transport.js:40
Evidence
((executable, arguments_, spawnOptions) => spawnSync(executable, arguments_, spawnOptions));

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
dist/src/doctor-capabilities.js:45
Evidence
const result = spawnSync(executable, args, {

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
dist/src/herdr-terminal-control-provider.js:1130
Evidence
const result = spawnSync(command, args, {

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
dist/src/install-doctor-command-adapter.js:187
Evidence
const linked = spawnSync(openclawBin, ["plugins", "install", "--link", ...capabilityConsentArgs, root], {

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
dist/src/openclaw-callback-transport.js:580
Evidence
((command, args, options) => spawnSync(command, args, options));

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
dist/src/openclaw-doctor.js:189
Evidence
const result = spawnSync(executable, args, {

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
dist/src/semantic-tool-relay.js:30
Evidence
const spawned = spawnSync(process.execPath, [binPath, ...cliArgs], {

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
dist/src/terminal-control-provider.js:944
Evidence
const result = spawnSync(command, args, {

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
dist/src/terminal-process-source.js:210
Evidence
const result = spawnSync(command, args, {

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
dist/src/terminal-runtime-cli-adapter.js:171
Evidence
const result = spawnSync(claudeExecutable, ["agents", "--json", "--all"], {