Back to skill

Security audit

AgentSentinel Safety Layer

Security checks for vulnerabilities and agentic risk

Overview

The skill is not malicious, but it should be reviewed because its guardrail decisions are weak and it records raw command text that can later be uploaded to a cloud service.

Review this before installing if you would rely on it as a real security boundary. Use it only as an advisory local helper unless the policy matching and cost validation are hardened, and avoid checking commands that contain secrets because full command text is logged locally and uploaded if you later run sync with an API key.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (3)

T09 · Insecure Skill Coding Practices

Warning
Location
sentinel_wrapper.py:342
Finding

Caller-controlled non-finite or negative costs bypass budget enforcement

Content
View full analysis
run_budget: _append_event( state=state, action_name="openclaw_check", estimated_cost=estimated_cost, outcome="error", details={ "cmd": cmd, "decision": "blocked", "reason": ( f"Run budget exceeded: {run_total:.2f} > {run_budget:.2f} USD" ), }, ) print( json.dumps( { "status": "BLOCKED", "cmd": cmd, "estimated_cost": estimated_cost, "error": ( f"Run budget exceeded: {run_total:.2f} > {run_budget:.2f} USD" ), "instruction": "Action blocked by local safety policy.", "remote_sync": remote_enabled, } ) ) return if session_total > session_budget: _append_event( state=state, action_name="openclaw_check", estimated_cost=estimated_cost, outcome="error", details={ "cmd": cmd, "decision": "blocked", "reason": ( "Session budget exceeded: " f"{session_total:.2f} > {session_budget:.2f} USD" ), }, ) ``` ### Technical Analysis The caller fully controls `args.cost`. Converting it with `float()` does not ensure that it is non-negative and finite. Python accepts values such as negative numbers, `nan`, and `inf`. A negative cost reduces `run_total` and `session_total`, effectively restoring budget that ha ...[truncated 1336 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
sentinel_wrapper.py:344
Finding

Literal substring matching permits deny-policy bypasses

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
sentinel_wrapper.py:218
Finding

Complete command strings are stored and uploaded without redaction

Content
View full analysis
None: entry = { "id": str(uuid.uuid4()), "timestamp": dt.datetime.now(dt.timezone.utc).isoformat(), "action": action_name, "cost_usd": max(estimated_cost, 0.0), "duration_ms": 0.0, "outcome": outcome, "tags": ["openclaw", "skill", "local-first"], "payload": { "inputs": details, "outputs": { "run_total": state["run_total"], "session_total": state["session_total"], }, }, } _ensure_home() with _events_path().open("a", encoding="utf-8") as handle: handle.write(json.dumps(entry) + "\n") ``` Callers place the full command in `details`: ```python _append_event( state=state, action_name="openclaw_check", estimated_cost=estimated_cost, outcome="success", details={ "cmd": cmd, "decision": "allowed", }, ) ``` All pending entries are loaded and submitted to the remote endpoint: ```python with path.open("r", encoding="utf-8") as handle: lines = handle.readlines() synced_events = int(state.get("synced_events", 0)) pending_lines = lines[synced_events:] entries = [json.loads(line) for line in pending_lines if line.strip()] if not entries: print(json.dumps({"status": "OK", "synced": 0, "pending": 0})) return body = json.dumps( { "run_id": state["run_id"], "agent_id": os.getenv("AGENT_SENTINEL_AGENT_ID"), "entries": entries, } ).encode("utf-8") req = request.Request( url=f"{PLATFO ...[truncated 2086 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (10)

Tainted flow: 'req' from os.getenv (line 290, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · sentinel_wrapper.py (reported line 301)May include surrounding context.

python
)

    try:
        with request.urlopen(req, timeout=3) as response:
            if 200 <= response.status < 300:
                state["synced_events"] = synced_events + len(entries)
                _write_state(state)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 5)May include surrounding context.

md
ree/main/skills/agent-sentinel","primaryEnv":"AGENT_SENTINEL_API_KEY","files":["sentinel_wrapper.py","README.md","CHANGELOG.md"],"requires":{"bins":["python3"]}

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
100% confidence
Finding

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).

Content

Scanner excerpt · sentinel_wrapper.py (reported line 22)May include surrounding context.

python
session: 5.00
  run: 1.00
denied_actions:
  - "rm -rf /"
  - "format"
""".lstrip()

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
100% confidence
Finding

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).

Content

Scanner excerpt · sentinel_wrapper.py (reported line 32)May include surrounding context.

python
session: 5.00
  run: 1.00
denied_actions:
  - "rm -rf /"
  - "format"
""".lstrip()

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
100% confidence
Finding

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).

Content

Scanner excerpt · test_wrapper.py (reported line 54)May include surrounding context.

python
session: 5.00
  run: 1.00
denied_actions:
  - "rm -rf /"
  - "format"
""".lstrip()

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
95% confidence
Finding

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).

Content

Scanner excerpt · sentinel_wrapper.py (reported line 22)May include surrounding context.

python
session: 5.00
  run: 1.00
denied_actions:
  - "rm -rf /"
  - "format"
""".lstrip()

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
95% confidence
Finding

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).

Content

Scanner excerpt · sentinel_wrapper.py (reported line 32)May include surrounding context.

python
"run": 1.0,
    },
    "denied_actions": [
        "rm -rf /",
        "format",
    ],
}

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
95% confidence
Finding

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).

Content

Scanner excerpt · test_wrapper.py (reported line 54)May include surrounding context.

python
payload = self._json_from_stdout(
            sentinel_wrapper.cmd_check,
            Namespace(cmd="rm -rf /tmp/test", cost=0.01),
        )

        self.assertEqual(payload["status"], "BLOCKED")

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill advertises executable capabilities that include environment access, file read/write, and optional network sync, but it does not declare any explicit tool scope such as permissions or allowed-tools. That omission weakens least-privilege controls and makes it harder for an agent runtime or reviewer to understand and constrain what the skill may access, especially since the skill can create configuration files, reset local state, and send telemetry to a remote endpoint.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

Cloud sync sends the full event entries, including command strings and embedded input details, to a remote API once an environment variable is set, but the code provides limited user-facing disclosure at the moment of transmission. In an agent guardrail context, logged commands may contain sensitive prompts, filenames, tokens, or operational details, so silent upload increases privacy and data-handling risk.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.