# Vulnerability Summary: nextlevelbuilder/goclaw Authentication Bypass and Default-Permit Policy Vulnerabilities ## Vulnerability Overview This vulnerability is a three-part exploit chain (Issue #866), involving authentication bypass and a default-permit policy in role-based access control (RBAC). An attacker can leverage an invalid token or unpaired connection to perform sensitive operations as an unauthenticated user. ## Impact Scope - **Affected Components**: `internal/gateway/router.go` and `internal/permissions/policy.go` - **Affected Functions**: - Heartbeat set (`heartbeat.set`) - Heartbeat toggle (`heartbeat.toggle`) - Heartbeat checklist set (`heartbeat.checklist.set`) - Log tail (`logs.tail`) - Other methods not explicitly listed ## Remediation Plan 1. **Route Path Fix**: When path level 4 falls back, no longer grant `RoleViewer` permission; invalid tokens or unpaired connections will return a `UNAUTHORIZED` error. 2. **Policy Engine Fix**: Change the policy engine from `default-permit` to `default-deny`; all methods are denied by default unless explicitly allowed. 3. **Admin List Update**: Update `adminAllowlist` to include methods that require administrator privileges. ## POC Code ### Script 1: repro-issue-866.mjs ```javascript // Before fix === Step 1 - connect with invalid token === {"type":"res","ok":true,"payload":{"role":"viewer","tenant_slug":"master",...}} [VULN] #1 confirmed: invalid token - connect.ok with roleviewer === Step 2 - heartbeat.set (mutation) === {"type":"res","ok":false,"error":{"code":"INVALID_REQUEST","message":"invalid agentId"}} [VULN] #2 confirmed: RBAC let it through, only validation rejected (INVALID_REQUEST) === Step 3 - logs.tail (exfil) === {"type":"log","ok":true,"payload":{"status":"tailling"}} [event] log {"level":"info","msg":"..."} - Live server log streaming to attacker [VULN] #3 confirmed: viewer started logs.tail stream (exfil) === Step 4 - heartbeat.checklist.set (mutation) === [VULN] #4 confirmed: RBAC let it through, validation only (INVALID_REQUEST) // After fix === Step 1 - connect with invalid token === {"type":"res","ok":false,"error":{"code":"UNAUTHORIZED","message":"Permission denied: valid token or ..."}} === Step 2 - heartbeat.set (mutation) === {"type":"res","ok":false,"error":{"code":"UNAUTHORIZED","message":"first request must be 'connect'"}} [Safe] heartbeat.set blocked by RBAC: UNAUTHORIZED === Step 3 - logs.tail (exfil) === {"type":"res","ok":false,"error":{"code":"UNAUTHORIZED","message":"first request must be 'connect'"}} [Safe] logs.tail blocked by RBAC: UNAUTHORIZED === Step 4 - heartbeat.checklist.set (mutation) === [Safe] heartbeat.checklist.set blocked by RBAC: UNAUTHORIZED ``` ### Script 2: repro_approvals_misclass.go ```go // Before fix METHOD ACTUAL EXPECTED STATUS NOTE exec.approval.list viewer operator BUG Listed in isReadMethod - viewers must be able exec.approval.approve operator operator OK Listed in writeExact - mutation, operators+admin exec.approval.deny operator operator OK Listed in writeExact - mutation, operators+admin [BEFORE-FIX] 1/3 methods misclassified - prefix fallback is shadowing isReadMethod exit status 1 // After fix METHOD ACTUAL EXPECTED STATUS NOTE exec.approval.list viewer viewer OK Listed in isReadMethod - viewers must be able exec.approval.approve operator operator OK Listed in writeExact - mutation, operators+admin exec.approval.deny operator operator OK Listed in writeExact - mutation, operators+admin [AFTER-FIX] All 3 methods classified correctly exit status 0 ```