Back to plugin

Security audit

Agent Knock Knock

Security checks for vulnerabilities and agentic risk

Overview

The package openly provides local terminal control for existing Codex and Claude Code sessions, with the sensitive behavior disclosed and bounded by exact terminal/session checks.

Install this only if you want OpenClaw to type into and monitor your local Codex or Claude Code terminal panes. Keep the AKK store and tmux/Herdr sockets private, use an unprivileged OS account, review approval prompts carefully, and enable autoApprove only for narrow, low-risk command/workspace rules you would be comfortable approving repeatedly.

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 v29 structured-tool contract never exposes a selector or opaque authority value: the model supplies semantic IDs only. The agent-neutral `terminal_user_explicit_composer_policy` advertises `replace_current_composer_and_submit`; the old Codex-named field is a v28 compatibility alias 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 and Claude Code `terminal_user_explicit` depend on the exact live terminal/process, a scanned non-blocked approval state, and no proven input-owning questionnaire, editor, menu, history search, or read-only viewer—not ordinary main-Composer visibility, stability, exactness, parsed working activity, existing draft contents, or AKK Store, Turn, Session, transfer, transition, ledger, or ownership. Profiled Codex 0.154.0/0.155.1 exact collapsed async-question summaries leaves the main Composer sendable; an expanded, clipped, or ambiguous async editor and an active-writer resume viewer remain zero-input boundaries. Both advertise `replace_current_composer_and_submit`: Codex physical fallback sends `C-u` once; Claude Code physical fallback uses a sentinel-backed native `C-s` stash-clear transaction that is independent of the cursor position and does not interrupt an active turn, then proves the main Composer empty. Each inje
...[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 v29. 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
The documented `autoApprove` capability permits approvals to occur without per-request human confirmation when policy conditions match. Even though it is default-disabled and scoped by agent, command vector, and workspace root, this still creates a real authorization-bypass risk if the policy is misconfigured, too broad, or if terminal evidence is spoofed or confused across contexts. In a skill that can control live coding-agent terminals, automatic approval can escalate benign task execution into unintended code execution or sensitive file/system changes.

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"], {