T09 · Insecure Skill Coding Practices
- Location
scripts/uninstall.py:252- Finding
Destructive uninstall proceeds without code-enforced confirmation
- Content
View full analysis
Vulnerability Details
File Location:
scripts/uninstall.py, lines 252–259 and 288–295
Vulnerability Type: Destructive operation without mandatory confirmation
Risk Level: MediumTechnical Analysis
The uninstall helper defaults to performing destructive actions because
dry_runisFalse. When the local inventory indicates that this is the final installed Beatra skill, the script attempts to revoke the shared device credential and then removes shared local state:python if dry_run: result.update({"decision": "disconnected", "revoked": False, "reason": "dry_run"}) return result token = _device_token(state_dir) revoked = False revoke_state = "no_credential"After the revocation attempt, the helper removes the local state without requiring an explicit confirmation flag:
python token = None _remove_local_state(state_dir) result.update({"decision": "disconnected", "revoked": revoked, "reason": revoke_state}) return resultThe command-line entrypoint preserves this destructive default.
--dry-runis optional, and invoking the script without it immediately calls the uninstall routine in destructive mode:python args = parser.parse_args() result = uninstall(dry_run=args.dry_run) print(json.dumps(result, ensure_ascii=False, indent=2)) if args.dry_run: print("Dry run: nothing was changed. Run without --dry-run to uninstall.") return 0The inventory checks reduce the affected scope by retaining the shared connection when another installed skill is detected. However, these checks do not enforce user approval for credential revocation and local-state deletion. Documentation-level expectations are not a technical confirmation boundary because an Agent or another caller can invoke the script directly.
Attack Path
- An Agent workflow, injected instruction, or mistaken automation invokes:
python3 scripts/uninstall.py - The caller does not supply
--dry-run; destructive mode is therefore selected by ...[truncated 1608 chars]
- An Agent workflow, injected instruction, or mistaken automation invokes:
- Remediation
View remediation
Remediation Suggestions
-
Make non-destructive inspection the default:
- Change
dry_runto default toTrue. - Require a dedicated flag such as
--confirm-disconnectbefore revocation or deletion.
- Change
-
Bind confirmation to the computed action:
- First calculate and display the package path, inventory decision, affected state directory, and whether credential revocation will occur.
- Require a second invocation or confirmation token tied to that exact decision.
-
Reject ambiguous invocation:
- Exit without modifying state unless the explicit confirmation flag is present.
- Do not treat the absence of
--dry-runas consent.
-
Preserve existing safeguards:
- Continue retaining the connection when inventory is missing, unreadable, or uncertain.
- Continue refusing to recursively delete unknown files or the package directory.
-
For Agent-driven execution, require the host workflow to obtain explicit user approval immediately before running the confirmed destructive command.
-
