T09 · Insecure Skill Coding Practices
- Location
tool/scripts/post-voucher.js:14- Finding
Maker-checker approval can be self-asserted or bypassed
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This accounting skill openly manages a local ledger, but its posting and correction scripts can make financial changes without reliably enforcing the stated approval and audit controls.
Install only in a test or non-production accounting workspace unless you add real approval enforcement, dry-run/confirmation gates, atomic rectification, reversal idempotency, date-aware period controls, and read-only preview behavior. Treat the included scripts as capable of changing financial records in the local SQLite database.
tool/scripts/post-voucher.js:14Maker-checker approval can be self-asserted or bypassed
tool/scripts/rectify-entry.js:14Rectification is non-atomic and can leave a committed reversal without a replacement
tool/scripts/reverse-voucher.js:4Voucher reversal permits repeated, chained, and state-invalid reversals
tool/lib/validators.js:31Closed-period validation ignores the voucher date
tool/lib/validators.js:3Incomplete numeric and journal-line validation permits semantically invalid vouchers
tool/lib/gst-engine.js:3Voucher preview unexpectedly writes GST ledgers to the database
Referenced artifact was not completely inspected
ized, the system uses the scripts in `tool/scripts/` (e.g., `post-voucher.js`, `generate-report.js`) as the primary interface for all ledger operations.
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.
Agent may not:
- self approve
- auto submit without confirmation
Required Flow
The DELETE example shows direct record removal with no accompanying warning that the action is irreversible and affects persisted user data. In markdown guidance for a persistence skill, destructive data operations should include an explicit caution so users understand the impact before applying the pattern.
The example node sqlite-util.js exec "update customers set balance=0" demonstrates a destructive bulk update without any warning, guardrail, or confirmation step. In an agent-operated wrapper, such examples normalize unsafe behavior and can lead to accidental mass data corruption or loss when an agent follows the pattern literally.
The utility wrapper accepts arbitrary SQL from command-line arguments and executes it directly with db.prepare(sql).all() or db.exec(sql), which defeats the document's own guidance to use parameterized queries. In an agent context, this is especially risky because upstream prompts, tool inputs, or untrusted task data may be transformed into SQL, enabling injection, unauthorized reads, schema modification, or destructive writes.
The file states that historical ledger data must be append-only and explicitly forbids UPDATE operations on ledger/balance-like data. However, later sections direct the posting workflow to 'update derived balances' and to maintain materialized summary tables during posting, which introduces mutation behavior that conflicts with the earlier absolute immutability language.
This markdown section documents db-maintenance.js commands such as VACUUM, ANALYZE, and wal_checkpoint(FULL) plus backup/optimize/checkpoint actions, but it does not warn that these operations modify the database file, can lock or pause access, and should be run with care. Under the markdown-specific SQP-2 criteria, behaviours affecting system integrity should include a clear user-facing warning.
The migrate-schema.js section declares the only allowed schema change path, but it does not warn users that migrations can irreversibly alter data structures, break compatibility, or require verified backups and rollback plans. Because this markdown describes behaviour that can affect user data and system integrity, a clear warning is expected.
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.
reverse_charge_flag
)
Do NOT use simplistic rule:
if gstin_matches...
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.
→ Confirmed
→ Posted
Do not skip confirmation.
---
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.
Prevent if possible.
Correct if necessary.
Never auto-post without asking:
Are you sure of this entry?
This function inserts voucher records, line items, and audit-log entries, which are persistent data writes with business impact. The file contains no confirmation prompt, user-facing logging, or explanatory docstring/comment warning that calling this function will create posted accounting records and audit entries.
The script performs a destructive accounting workflow by automatically reversing an existing voucher and then force-setting the replacement voucher status to POSTED without any confirmation, dry-run, or independent validation. In a financial posting context, this increases the risk of accidental or unauthorized ledger changes, especially if the input file is incorrect, malformed, or supplied by an untrusted operator.
The colloquial trigger list is intentionally broad and includes vague phrases such as 'adjust this', 'pass entry', and 'make receipt' that can map to multiple accounting actions. In an automation context, this can cause unintended invocation or transaction misclassification, potentially creating incorrect financial entries or prompting the wrong voucher workflow.
The file includes a section labeled "Indian + Global Usage" with locale-specific Hinglish phrases such as "journal karo," "contra maaro," and "bill punch karo" without indicating that this language convention is optional or region-specific. This can violate language/locale policy because the skill embeds a specific linguistic mode without documented user choice or justification.
The preview script is documented as a dry-run with 'No writes,' yet the overall posting flow and audit rules describe mandatory audit-related actions around validation/preview/commit. That creates intent ambiguity about whether preview is strictly read-only or whether audit/enforcement activity may write records during preview.
The example phrase "Bought stock on udhar" uses a Hindi/Urdu term, which bakes a specific locale/language assumption into the skill guidance. The file does not offer users a language choice or explain that the skill is intended for a specific regional context, so this can conflict with language/locale policy requirements.
The dependency version is not pinned to an exact release and uses a caret range (^11.10.0), which permits automatic installation of newer minor and patch versions. This can introduce supply-chain risk and reduce build reproducibility if a compromised or breaking upstream release is published and later resolved during install.
"license": "ISC",
"description": "",
"dependencies": {
"better-sqlite3": "^11.10.0"
}
}
This code reads posted voucher details and outputs dates, voucher numbers, debit/credit amounts, and narration directly to stdout. While the script has usage/error messages, it provides no disclosure that running it will reveal potentially sensitive accounting data, and there is no surrounding comment or docstring warning about that behavior.