T09 · Insecure Skill Coding Practices
- Location
SKILL.md:148- Finding
Destructive Kill-Switch Test Can Delete a Production Ledger Record
- Content
View full analysis
Vulnerability Details
File Location:
SKILL.md, lines 148–160
Vulnerability Type: Unsafe destructive operation and misleading exception handling
Risk Level: HighVulnerable Code
bash ### Kill Switch Test Verify that the kill switch mechanism works (Gebud 10 — Test What You Fear): ```bash # Check that Decision#destroy raises cd ZK_BANKIR_PATH bin/rails runner " begin Decision.last.destroy puts '❌ KILL SWITCH FAILED: destroy allowed' rescue => e puts '✅ Kill switch active: destroy blocked' end " 2>&1text ### Technical Analysis The test calls `destroy` on the last persisted `Decision` record in the database. If deletion protection is absent or defective—the exact condition this procedure is intended to detect—the operation succeeds and permanently deletes a real ledger record. This behavior contradicts the Skill's claim that its audits are “read-only by default” and “never modify” data. Because the command does not require an isolated test environment or wrap the operation in a transaction that is guaranteed to roll back, following the documented audit workflow against a production deployment can alter production state. The broad `rescue => e` introduces an additional correctness problem. Any `StandardError`, rather than only the specific exception expected from the deletion guard, is reported as evidence that the kill switch is active. For example, if the table has no records, `Decision.last` returns `nil`, and calling `destroy` raises an unrelated `NoMethodError`; the script then incorrectly reports that deletion was blocked. Database connectivity, callback, or application errors could produce similar false-positive results. ### Attack Path 1. An operator follows the documented “Full Security Audit” procedure against a running ZK-Bankir deployment. 2. The Rails runner connects to the deployment's configured database. 3. The kill-switch test retrieves the most recent persisted decision through `Decision.last` ...[truncated 1038 chars]- Remediation
View remediation
Remediation Suggestions
- Do not invoke
destroyon an existing record in a production or operator-selected database. - Move the behavioral test to an isolated test database and create a dedicated fixture solely for this check.
- If an in-process check is unavoidable, use a transaction that is unconditionally rolled back, while accounting for callbacks or integrations that may cause external side effects:
ruby expected_error = Decision::DestroyForbidden Decision.transaction(requires_new: true) do record = Decision.create!(required_fixture_attributes) begin record.destroy! abort "KILL SWITCH FAILED: destroy was allowed" rescue expected_error puts "Kill switch active: destroy blocked" ensure raise ActiveRecord::Rollback end end- Prefer a non-destructive unit or integration test that directly verifies the deletion guard, callback, policy, and expected exception.
- Rescue only the specific exception raised by the intended protection. Treat all other exceptions as test errors rather than successful security enforcement.
- Explicitly fail when no suitable test record exists.
- Require an explicit test-environment check before running any destructive security validation, such as aborting unless
Rails.env.test?. - Update the documentation's “read-only” claim or, preferably, redesign the procedure so that the claim is accurate.
- Do not invoke
