T05 · Unauthorized Access and Privilege Escalation
- Location
acp_openai_bridge/acp_reader.py:235- Finding
Agent Permission Requests Are Automatically and Permanently Approved
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This is a real local bridge, but it exposes Kiro file and terminal capabilities through weakly controlled local APIs and auto-approved permissions.
Only install this if you understand that any process able to reach the bridge may be able to drive Kiro with your local file and command privileges. Keep it bound to 127.0.0.1, do not expose the port through tunnels, proxies, containers, or shared machines, use a dedicated low-privilege workspace without secrets, and prefer waiting for fixes that add real authentication, explicit per-action approval, enforced project-directory containment, and restricted command execution.
acp_openai_bridge/acp_reader.py:235Agent Permission Requests Are Automatically and Permanently Approved
acp_openai_bridge/acp_reader.py:278Filesystem Tool Operations Are Not Restricted to the Configured Working Directory
acp_openai_bridge/acp_reader.py:309Agent-Controlled Arguments Are Executed Through a Shell with the Bridge Environment
acp_openai_bridge/routes.py:1Capability-Bearing HTTP Endpoints Do Not Authenticate Callers
acp_openai_bridge/routes.py:92Sensitive Prompt Content Is Written to Application Logs
Exposing additional API surfaces such as /v1/messages and operating without API-key validation broadens access beyond the stated purpose and weakens the trust model. In a bridge that can trigger backend tool use, missing authentication is especially risky because a local or mistakenly exposed listener could be driven by unauthorized callers.
Exposing additional API surfaces such as /v1/messages and operating without API-key validation broadens access beyond the stated purpose and weakens the trust model. In a bridge that can trigger backend tool use, missing authentication is especially risky because a local or mistakenly exposed listener could be driven by unauthorized callers.
This reader/dispatcher component is documented as handling JSON-RPC routing, yet it also implements filesystem writes and shell execution. That functional overreach increases attack surface substantially because any ACP peer that can send requests to this reader can trigger privileged local actions unrelated to simple bridging.
The permission handler automatically selects allow-like options, preferring allow_always, without user confirmation. That defeats the safety boundary intended by permission prompts and enables any connected agent to escalate from requesting access to receiving standing authorization for file or command actions.
Automatically approving permission requests without any user-visible confirmation removes an expected consent checkpoint for sensitive operations. In this skill, that directly compounds the file-write and command-execution capabilities, allowing a connected agent to perform high-risk local actions silently.
A local protocol bridge is expected to translate messages, not expose broad shell execution to the remote side. Providing terminal/create, output, wait, kill, and release semantics here turns the bridge into a general-purpose remote command runner, magnifying the consequences of any misuse or compromise of the connected client.
Shell command execution occurs with no user-facing warning even though it can perform arbitrary host actions. Combined with inherited environment and optional cwd/env overrides, the connected agent can run reconnaissance, exfiltration, or destructive commands without meaningful user awareness.
Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.
cwd = params.get("cwd")
env_vars = params.get("env", [])
try:
env = os.environ.copy()
for ev in env_vars:
if isinstance(ev, dict):
env[ev.get("name", "")] = ev.get("value", "")
The command parameters are fully agent-controlled and passed to subprocess with shell=True, so the tool interface can be abused to execute arbitrary OS commands beyond any intended safe subset. In this bridge context the tool is effectively a remote shell endpoint, making prompt- or protocol-level manipulation highly dangerous.
logger.info("Terminal exec: %s (cwd=%s)", cmd_str, cwd)
proc = subprocess.run(
cmd_str,
shell=True,
capture_output=True,
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).
if [ "${1:-}" = "clean" ]; then
echo "Cleaning build artifacts..."
rm -rf build/ dist/ __pycache__/ *.egg-info/
echo "Done."
exit 0
fi
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).
pip install -r requirements.txt -q
echo "Building acp-bridge executable..."
pyinstaller acp_bridge.spec --clean --noconfirm
BINARY="dist/acp-bridge"
if [ -f "$BINARY" ]; then
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).
pip install -r requirements.txt -q
echo "Building acp-bridge executable..."
pyinstaller acp_bridge.spec --clean --noconfirm
BINARY="dist/acp-bridge"
if [ -f "$BINARY" ]; then
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).
pip install -r requirements.txt -q
echo "Building acp-bridge executable..."
pyinstaller acp_bridge.spec --clean --noconfirm
BINARY="dist/acp-bridge"
if [ -f "$BINARY" ]; then
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).
pip install -r requirements.txt -q
echo "Building acp-bridge executable..."
pyinstaller acp_bridge.spec --clean --noconfirm
BINARY="dist/acp-bridge"
if [ -f "$BINARY" ]; then
The documentation explicitly promotes running the bridge with the user's full local privileges and highlights direct file-system and CLI access as a feature, even though the stated purpose is only protocol bridging between OpenClaw and kiro-cli. This materially expands the attack surface: any prompt sent through the client could induce sensitive local actions, and the document provides no sandboxing, consent gates, or scope restrictions.
Package name closely resembles a popular package, suggesting possible typosquatting. Attackers publish malicious packages with similar names to trick developers into installing them.
Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
# 健康检查
curl http://127.0.0.1:18788/health
# 快速测试
curl -X POST http://127.0.0.1:18788/v1/chat/completions \
The README describes a local HTTP bridge that forwards prompts and tool calls into a persistent kiro-cli acp process scoped to --cwd, but the warning is brief and easy to miss. Because the bridge exposes OpenAI-compatible endpoints and tool passthrough, a user may underestimate that any local client able to reach the port can trigger actions against the selected project directory through Kiro CLI.
The skill documents a bridge that exposes network, shell, file, and environment-adjacent capabilities, but it does not declare any explicit permission or allowed-tools scope. That omission increases the chance that users or platforms will underestimate the bridge's effective access, especially because the bridge fronts kiro-cli tool execution behind an HTTP API.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
# 健康检查
curl http://127.0.0.1:18788/health
# 应返回:{"status":"ok","acp_available":true}
# 模型列表
The docstring says terminal/create "Creates a terminal and runs a command" and companion methods imply a live terminal lifecycle with output, waiting, release, kill. In reality, the code calls subprocess.run with a 30-second timeout, waits for completion immediately, and stores static output in a dictionary, so the documented semantics of an interactive terminal are contradicted by the implementation.
The file-write path accepts arbitrary agent-provided paths and content and writes them directly without warning or confirmation. In a bridge exposed to an LLM-driven agent, this can be exploited to overwrite config files, drop startup scripts, or modify project code silently.
The code executes agent-supplied command text via subprocess.run(..., shell=True), which allows arbitrary shell metacharacters, chaining, redirection, and expansion. In a local bridge context this grants the connected agent effective code-execution capability on the host, which is far broader than passive protocol translation and can be abused for data theft, persistence, or destructive actions.
logger.info("Terminal exec: %s (cwd=%s)", cmd_str, cwd)
proc = subprocess.run(
cmd_str,
shell=True,
capture_output=True,
The translator logs message-role metadata and emits previews of message contents, including user and potentially system prompt text. In this bridge context, requests may contain secrets, API keys, proprietary prompts, or sensitive user data, so writing even partial content to logs creates an information disclosure risk if logs are retained, aggregated, or accessed by other users or operators.
No suspicious patterns detected.