Back to skill

Security audit

OpenExec — Deterministic Execution Boundary for Agent Systems

Security checks for vulnerabilities and agentic risk

Overview

OpenExec does not look malicious, but its approval, replay, and receipt guarantees are weaker than documented, so it needs review before production or high-impact use.

Treat this as suitable only for local demo or carefully isolated evaluation until the authorization and audit issues are fixed. Do not rely on it for money movement, email sending, infrastructure changes, data deletion, or other high-impact actions unless approvals are made single-use, replay retrieval is authorization-bound, receipts are signed or HMAC-protected, dependencies are reviewed, ClawShield mode and an explicit action allow-list are enforced, and the service is kept behind localhost/firewall isolation.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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
Findings (3)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
openexec/engine.py:42
Finding
Approval artifacts can be replayed for repeated execution<![CDATA[ ## Vulnerability Details **File Location**: `openexec/engine.py:42-43`, `openexec/approval_validator.py:8-10`, `openexec/tables.py:8-13` **Vulnerability Type**: Approval replay and insufficient signed-request binding **Risk Level**: High ### Vulnerable Code ```python # openexec/engine.py:42-43 action_request = {"action": request.action, "payload": payload} validate_approval(action_request, request.approval_artifact.model_dump()) ``` ```python # openexec/approval_validator.py:8-10 request_hash = canonical_hash(action_request) if artifact.get("action_hash") != request_hash: raise ApprovalError("Action hash mismatch: approval does not match this request") ``` ```python # openexec/tables.py:8-13 id = Column(String, primary_key=True) action = Column(String, nullable=False) payload = Column(Text, nullable=True) result = Column(Text, nullable=True) nonce = Column(String, unique=True, nullable=False) approved = Column(Boolean, default=False) ``` ### Technical Analysis The signed `action_hash` covers only the action name and payload. It does not cover the execution nonce or another unique, single-use request identifier. Although the approval artifact contains an `approval_id`, the database does not record that identifier or enforce its uniqueness. Consequently, the same valid approval artifact can authorize multiple execution requests when each request supplies a different nonce. Expiration limits the replay window but does not make the approval single-use. The current registry contains only `echo` and `add`, which limits immediate consequences. However, this directly violates the service's replay-protection guarantee and becomes security-critical if registered handlers are expanded to perform production side effects. ### Attack Path 1. Obtain a legitimately signed, unexpired approval artifact for an action and payload. 2. Submit the artifact to `/execute` with nonce `nonce-1`. 3. Resubmit the identical artifact, action, and payload with nonce `no ...[truncated 593 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Include the nonce in the canonical request covered by `action_hash`: ```python action_request = { "action": request.action, "payload": payload, "nonce": request.nonce, } ``` 2. Persist `approval_id` in `ExecutionLog` and add a unique database constraint. 3. Atomically mark the approval as consumed before invoking the handler. 4. Treat a uniqueness conflict on `approval_id` as a denied replay rather than as a successful prior result. 5. Scope consumed approvals to the expected tenant. 6. Add tests proving that: - An artifact cannot be used with a different nonce. - An `approval_id` cannot be consumed twice. - Concurrent submissions result in at most one handler invocation. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
openexec/engine.py:16
Finding
Existing-nonce lookup bypasses approval validation and request binding<![CDATA[ ## Vulnerability Details **File Location**: `openexec/engine.py:16-26` **Vulnerability Type**: Authorization bypass and stored-result disclosure through nonce reuse **Risk Level**: High ### Vulnerable Code ```python db = SessionLocal() try: existing = db.query(ExecutionLog).filter_by(nonce=request.nonce).first() if existing: return ExecutionResult( id=existing.id, action=existing.action, result=json.loads(existing.result), approved=existing.approved, receipt=_make_receipt(existing.id, existing.result) ) _check_allow_list(request.action) ``` ### Technical Analysis The existing-nonce branch executes before: - Action allow-list enforcement - Handler validation - Execution-mode validation - Approval-artifact presence checks - Signature verification - Tenant validation It also checks only the nonce. The submitted action and payload do not have to match the stored execution. Therefore, a caller who knows an existing nonce can submit an unrelated request and receive the stored result without presenting the approval originally required for that execution. Nonce uniqueness is global rather than tenant-scoped, and the execution table does not store a tenant identifier. In a shared deployment, this design can expose a prior tenant's result to another caller if the nonce is disclosed, reused, or predictable. ### Attack Path 1. Learn or guess the nonce associated with an earlier execution. 2. Send a new request to `/execute` using that nonce. 3. Omit the approval artifact, or provide an unrelated action and payload. 4. The service finds the existing row before authorization is evaluated. 5. The service returns the stored action, result, approval status, execution ID, and receipt. ### Impact Assessment A caller can bypass ClawShield approval verification for replay retrieval and obtain a previously stored execution result. The scope is limited to records whose nonce i ...[truncated 249 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Perform mode, tenant, allow-list, and approval validation before returning replayed data. 2. Store a canonical request hash with each execution and require the replayed request to match it exactly. 3. Reject nonce reuse when the action, payload, tenant, or authorization context differs. 4. Store `tenant_id` and use a composite uniqueness boundary such as `(tenant_id, nonce)`. 5. Require callers to authenticate before allowing access to stored execution results. 6. Use cryptographically unpredictable nonces and document their confidentiality requirements. 7. Add tests for: - Reuse with a different action - Reuse with a different payload - Reuse without an approval in ClawShield mode - Cross-tenant nonce collisions - Requests submitted after allow-list changes ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
openexec/receipts.py:3
Finding
Unkeyed receipt hashes allow arbitrary receipt forgery<![CDATA[ ## Vulnerability Details **File Location**: `openexec/engine.py:82-84`, `openexec/receipts.py:3-5` **Vulnerability Type**: Forgeable integrity evidence **Risk Level**: Medium ### Vulnerable Code ```python # openexec/engine.py:82-84 def _make_receipt(exec_id: str, result: str) -> str: data = f"{exec_id}:{result}" return hashlib.sha256(data.encode()).hexdigest() ``` ```python # openexec/receipts.py:3-5 def verify_receipt(exec_id: str, result: str, receipt: str) -> bool: expected = hashlib.sha256(f"{exec_id}:{result}".encode()).hexdigest() return expected == receipt ``` ### Technical Analysis Receipt generation uses a plain SHA-256 hash over caller-reproducible values. No secret key or digital signature authenticates the receipt. Anyone can therefore generate a valid hash for any chosen execution ID and result. The verification function also does not consult the execution database. It only checks mathematical consistency among three caller-supplied values. As a result, successful verification does not establish that the execution occurred or that OpenExec generated the receipt. This provides accidental-corruption detection but not the documented receipt authenticity or evidence property. ### Attack Path 1. Choose an arbitrary execution ID and fabricated result. 2. Compute `SHA256(exec_id + ":" + result)` locally. 3. Submit the execution ID, result, and calculated digest to `/receipts/verify`. 4. The endpoint returns `{"valid": true}` even though no corresponding execution occurred. ### Impact Assessment An attacker can fabricate apparently valid execution evidence without access to the service or its database. This does not grant code-execution or host privileges, but it undermines audit integrity, non-repudiation, and any external workflow that trusts a successful receipt verification response. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions 1. Authenticate receipts using either: - Ed25519 signatures generated with a protected service private key, or - HMAC-SHA-256 with a securely stored server-side secret. 2. Sign a canonical receipt structure containing at least: - Execution ID - Tenant ID - Action - Canonical request hash - Canonical result hash - Execution timestamp 3. During verification, confirm that the referenced execution exists in trusted storage. 4. Clearly distinguish an integrity checksum from an authenticated receipt if unsigned hashes are retained. 5. For HMAC receipts, verify with `hmac.compare_digest`. 6. Protect and rotate signing keys, and expose an authenticated public-key discovery mechanism when signatures are used. 7. Add negative tests demonstrating that fabricated IDs, modified results, and receipts signed by unknown keys are rejected. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
Findings (36)

Known Vulnerable Dependency: cryptography==46.0.5 — 11 advisory(ies): GHSA-537c-gmf6-5ccf (Vulnerable OpenSSL included in cryptography wheels); CVE-2026-69247 (cryptography: PKCS#7 EnvelopedData decryption exposes a Bleichenbacher oracle th); CVE-2026-69249 (python-cryptography: Duplicate self-signed intermediates can cause exponential p) +8 more

Critical
Category
Supply Chain
Confidence
98% confidence
Finding
The dependency is pinned to cryptography==46.0.5, and the supplied finding indicates multiple published advisories affecting that exact version, including issues in bundled OpenSSL and cryptographic parsing/decryption behavior. In a service whose core trust model relies on signed approval artifacts and verifiable receipts, flaws in the cryptographic library directly undermine signature verification, certificate/path validation, or confidential data handling, making the context more dangerous rather than less.

Self-Modification

High
Category
Rogue Agent
Content
- No runtime plugin system
- No remote code execution primitives
- Static handler registry only
- No self-modifying behavior

---
Confidence
90% confidence
Finding
Skill modifies its own code, configuration, or behavior at runtime. Self-modification enables an agent to escalate privileges, disable safety constraints, or install persistent backdoors.

Self-Modification

High
Category
Rogue Agent
Content
## 12. Self-Modification

OpenExec does not modify its own code,
write executable files,
or alter system configuration.
Confidence
90% confidence
Finding
Skill modifies its own code, configuration, or behavior at runtime. Self-modification enables an agent to escalate privileges, disable safety constraints, or install persistent backdoors.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding
This finding is essentially about unverified security claims: the file asserts absence of outbound calls, signed-approval enforcement, pinned behavior, and no runtime downloads without direct proof in the supplied content. Unsupported guarantees are risky in security tooling because they can distort threat modeling and lead users to trust controls that may exist only as documentation statements.

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding
This finding is essentially about unverified security claims: the file asserts absence of outbound calls, signed-approval enforcement, pinned behavior, and no runtime downloads without direct proof in the supplied content. Unsupported guarantees are risky in security tooling because they can distort threat modeling and lead users to trust controls that may exist only as documentation statements.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
This finding is essentially about unverified security claims: the file asserts absence of outbound calls, signed-approval enforcement, pinned behavior, and no runtime downloads without direct proof in the supplied content. Unsupported guarantees are risky in security tooling because they can distort threat modeling and lead users to trust controls that may exist only as documentation statements.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
This finding is essentially about unverified security claims: the file asserts absence of outbound calls, signed-approval enforcement, pinned behavior, and no runtime downloads without direct proof in the supplied content. Unsupported guarantees are risky in security tooling because they can distort threat modeling and lead users to trust controls that may exist only as documentation statements.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
This finding is essentially about unverified security claims: the file asserts absence of outbound calls, signed-approval enforcement, pinned behavior, and no runtime downloads without direct proof in the supplied content. Unsupported guarantees are risky in security tooling because they can distort threat modeling and lead users to trust controls that may exist only as documentation statements.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
This finding is essentially about unverified security claims: the file asserts absence of outbound calls, signed-approval enforcement, pinned behavior, and no runtime downloads without direct proof in the supplied content. Unsupported guarantees are risky in security tooling because they can distort threat modeling and lead users to trust controls that may exist only as documentation statements.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
This finding is essentially about unverified security claims: the file asserts absence of outbound calls, signed-approval enforcement, pinned behavior, and no runtime downloads without direct proof in the supplied content. Unsupported guarantees are risky in security tooling because they can distort threat modeling and lead users to trust controls that may exist only as documentation statements.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding
This finding is essentially about unverified security claims: the file asserts absence of outbound calls, signed-approval enforcement, pinned behavior, and no runtime downloads without direct proof in the supplied content. Unsupported guarantees are risky in security tooling because they can distort threat modeling and lead users to trust controls that may exist only as documentation statements.

Tp4

High
Category
MCP Tool Poisoning
Confidence
87% confidence
Finding
This finding is essentially about unverified security claims: the file asserts absence of outbound calls, signed-approval enforcement, pinned behavior, and no runtime downloads without direct proof in the supplied content. Unsupported guarantees are risky in security tooling because they can distort threat modeling and lead users to trust controls that may exist only as documentation statements.

Tp4

High
Category
MCP Tool Poisoning
Confidence
87% confidence
Finding
This finding is essentially about unverified security claims: the file asserts absence of outbound calls, signed-approval enforcement, pinned behavior, and no runtime downloads without direct proof in the supplied content. Unsupported guarantees are risky in security tooling because they can distort threat modeling and lead users to trust controls that may exist only as documentation statements.

Description-Behavior Mismatch

High
Confidence
95% confidence
Finding
The manifest says the service 'Runs only with a signed approval artifact (ClawShield mode),' but this endpoint explicitly supports and reports a default 'demo' mode with signature verification disabled. It also reports an 'open' restriction state and warns when no execution allow-list is configured, indicating operation outside the claimed mandatory approval-only model.

Description-Behavior Mismatch

High
Confidence
98% confidence
Finding
The engine explicitly bypasses approval validation in demo mode by setting `approved = True` without requiring or verifying a signed approval artifact. That directly contradicts the stated security model that execution is gated by signed approval, so if demo mode is enabled in any reachable environment, unauthorized actions can execute while appearing legitimately approved.

Possible Typosquatting: 'uvicorn' resembles popular package 'gunicorn'

High
Category
Supply Chain
Confidence
70% confidence
Finding
Package name closely resembles a popular package, suggesting possible typosquatting. Attackers publish malicious packages with similar names to trick developers into installing them.

Description-Behavior Mismatch

High
Confidence
98% confidence
Finding
The script performs `pip install -r requirements.txt`, which directly contradicts the skill metadata claim that no runtime package installation or dynamic downloads occur. This creates supply-chain risk because installation behavior depends on package indexes and the contents of `requirements.txt`, allowing unreviewed or mutable dependencies to be fetched and executed during setup.

External Transmission

Medium
Category
Data Exfiltration
Content
Confirm health:

```bash
curl http://localhost:5000/health
```

Execute:
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
tool_call = model_output["tool_calls"][0]

response = requests.post(
    "http://localhost:5000/execute",
    json={
        "action": tool_call["function"]["name"],
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
tool_call = model_output["tool_calls"][0]

response = requests.post(
    "http://localhost:5000/execute",
    json={
        "action": tool_call["function"]["name"],
Confidence
70% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Internal Network Request

Medium
Category
Server-Side Request Forgery
Content
tool_call = model_output["tool_calls"][0]

response = requests.post(
    "http://localhost:5000/execute",
    json={
        "action": tool_call["function"]["name"],
Confidence
70% confidence
Finding
Code issues a request to a loopback, link-local, or private-range host. This can reach internal services not meant to be exposed and is a common SSRF pivot.

Intent-Code Divergence

Medium
Confidence
95% confidence
Finding
Line L182 states 'OpenExec determines whether it runs,' which contradicts repeated statements elsewhere in the same file that OpenExec does not define policy, decide approvals, or originate execution authority. The documented intent is that OpenExec verifies externally produced approval artifacts and executes only already-authorized actions, so this wording materially misstates the security boundary.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
- Forged approval artifacts (ClawShield mode)
- Parameter mutation after approval
- Silent execution without receipt
- Unauthorized execution without approval

OpenExec does NOT protect against:
Confidence
75% 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.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
- [ ] Use TLS termination
- [ ] Pin dependencies (already enforced in `requirements.txt`)
- [ ] Run inside container or VM
- [ ] Do NOT run as root
- [ ] Configure `OPENEXEC_ALLOWED_ACTIONS`
- [ ] Provide valid `CLAWSHIELD_PUBLIC_KEY`
- [ ] Protect `CLAWSHIELD_TENANT_ID` appropriately
Confidence
80% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
- [ ] Use TLS termination
- [ ] Pin dependencies (already enforced in `requirements.txt`)
- [ ] Run inside container or VM
- [ ] Do NOT run as root
- [ ] Configure `OPENEXEC_ALLOWED_ACTIONS`
- [ ] Provide valid `CLAWSHIELD_PUBLIC_KEY`
- [ ] Protect `CLAWSHIELD_TENANT_ID` appropriately
Confidence
80% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Static analysis

No suspicious patterns detected.