Back to skill

Security audit

financial-categorizer

Security checks for vulnerabilities and agentic risk

Overview

This is a local personal finance CLI that changes the SQLite database the user points it at, with its data-mutating behavior disclosed in the skill documentation.

Install only if you are comfortable giving this CLI write access to your local finance database. Keep backups before cleanup, auto-linking, recurring discovery, category deletion, or any command run with --yes, and use dry-run/preview commands first when available.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • System Prompt LeakageDirect Leakage, Indirect Extraction, Tool-Based Exfiltration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (29)

Direct Prompt Extraction

High
Category
System Prompt Leakage
Confidence
85% confidence
Finding

Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Content

Scanner excerpt · cli.py (reported line 405)May include surrounding context.

python
row = cur.fetchone()
        if not row:
            print(f"Rule {args.id} not found")
            return

        rule = {
            "id": row[0],

Direct Prompt Extraction

High
Category
System Prompt Leakage
Confidence
85% confidence
Finding

Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Content

Scanner excerpt · cli.py (reported line 1375)May include surrounding context.

python
row = cur.fetchone()
        if not row:
            print(f"Rule {args.id} not found")
            return

        rule = {
            "id": row[0],

Missing User Warnings

High
Category
Not specified by scanner
Confidence
94% confidence
Finding

delete_category can reassign or delete child relationships, match rules, and manual matches, then recategorize all transactions, making it a high-impact and partly irreversible data-modifying operation. The docstring documents behavior for developers, but there is no user-facing warning, confirmation, or visible disclosure in the code path before these changes are committed.

Content

No source excerpt is available for this finding.

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
85% 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.

Content

Scanner excerpt · cli.py (reported line 39)May include surrounding context.

python
if yes_flag:
        return True
    if not sys.stdin.isatty():
        print("Error: Interactive confirmation is not available. Use --yes or -y to bypass confirmation.", file=sys.stderr)
        sys.exit(1)
    try:
        response = input(f"{prompt_message} [y/N]: ").strip().lower()

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
85% 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.

Content

Scanner excerpt · cli.py (reported line 2022)May include surrounding context.

python
# delete-account
    p_del_acct = subparsers.add_parser("delete-account", help="Delete an account")
    p_del_acct.add_argument("id", type=int, help="Account ID")
    p_del_acct.add_argument("--yes", "-y", action="store_true", help="Bypass confirmation prompt")
    p_del_acct.set_defaults(func=cmd_delete_account)

    # categories

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
85% 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.

Content

Scanner excerpt · cli.py (reported line 2057)May include surrounding context.

python
# delete-account
    p_del_acct = subparsers.add_parser("delete-account", help="Delete an account")
    p_del_acct.add_argument("id", type=int, help="Account ID")
    p_del_acct.add_argument("--yes", "-y", action="store_true", help="Bypass confirmation prompt")
    p_del_acct.set_defaults(func=cmd_delete_account)

    # categories

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
85% 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.

Content

Scanner excerpt · cli.py (reported line 2080)May include surrounding context.

python
# delete-account
    p_del_acct = subparsers.add_parser("delete-account", help="Delete an account")
    p_del_acct.add_argument("id", type=int, help="Account ID")
    p_del_acct.add_argument("--yes", "-y", action="store_true", help="Bypass confirmation prompt")
    p_del_acct.set_defaults(func=cmd_delete_account)

    # categories

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
85% 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.

Content

Scanner excerpt · cli.py (reported line 2199)May include surrounding context.

python
# delete-account
    p_del_acct = subparsers.add_parser("delete-account", help="Delete an account")
    p_del_acct.add_argument("id", type=int, help="Account ID")
    p_del_acct.add_argument("--yes", "-y", action="store_true", help="Bypass confirmation prompt")
    p_del_acct.set_defaults(func=cmd_delete_account)

    # categories

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
85% 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.

Content

Scanner excerpt · cli.py (reported line 2208)May include surrounding context.

python
# delete-account
    p_del_acct = subparsers.add_parser("delete-account", help="Delete an account")
    p_del_acct.add_argument("id", type=int, help="Account ID")
    p_del_acct.add_argument("--yes", "-y", action="store_true", help="Bypass confirmation prompt")
    p_del_acct.set_defaults(func=cmd_delete_account)

    # categories

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
85% 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.

Content

Scanner excerpt · cli.py (reported line 2234)May include surrounding context.

python
# delete-account
    p_del_acct = subparsers.add_parser("delete-account", help="Delete an account")
    p_del_acct.add_argument("id", type=int, help="Account ID")
    p_del_acct.add_argument("--yes", "-y", action="store_true", help="Bypass confirmation prompt")
    p_del_acct.set_defaults(func=cmd_delete_account)

    # categories

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
85% 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.

Content

Scanner excerpt · cli.py (reported line 2252)May include surrounding context.

python
# delete-account
    p_del_acct = subparsers.add_parser("delete-account", help="Delete an account")
    p_del_acct.add_argument("id", type=int, help="Account ID")
    p_del_acct.add_argument("--yes", "-y", action="store_true", help="Bypass confirmation prompt")
    p_del_acct.set_defaults(func=cmd_delete_account)

    # categories

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
85% 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.

Content

Scanner excerpt · cli.py (reported line 2269)May include surrounding context.

python
# delete-account
    p_del_acct = subparsers.add_parser("delete-account", help="Delete an account")
    p_del_acct.add_argument("id", type=int, help="Account ID")
    p_del_acct.add_argument("--yes", "-y", action="store_true", help="Bypass confirmation prompt")
    p_del_acct.set_defaults(func=cmd_delete_account)

    # categories

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
85% 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.

Content

Scanner excerpt · cli.py (reported line 2369)May include surrounding context.

python
# delete-account
    p_del_acct = subparsers.add_parser("delete-account", help="Delete an account")
    p_del_acct.add_argument("id", type=int, help="Account ID")
    p_del_acct.add_argument("--yes", "-y", action="store_true", help="Bypass confirmation prompt")
    p_del_acct.set_defaults(func=cmd_delete_account)

    # categories

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
85% 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.

Content

Scanner excerpt · cli.py (reported line 2376)May include surrounding context.

python
# delete-account
    p_del_acct = subparsers.add_parser("delete-account", help="Delete an account")
    p_del_acct.add_argument("id", type=int, help="Account ID")
    p_del_acct.add_argument("--yes", "-y", action="store_true", help="Bypass confirmation prompt")
    p_del_acct.set_defaults(func=cmd_delete_account)

    # categories

Dynamic import via __import__()

Medium
Category
Dangerous Code Execution
Confidence
75% confidence
Finding

Dynamic import() can load arbitrary modules at runtime, bypassing static analysis and potentially importing malicious code.

Content

Scanner excerpt · cli.py (reported line 2146)May include surrounding context.

python
p_stats_cat = subparsers.add_parser("stats-category", help="Total for a category (inc. children)")
    p_stats_cat.add_argument("name", help="Category name")
    p_stats_cat.add_argument("--month", help="Filter to YYYY-MM")
    p_stats_cat.add_argument("--from", dest="from_date", type=lambda s: __import__('datetime').date.fromisoformat(s), help="Start date (YYYY-MM-DD)")
    p_stats_cat.add_argument("--to", dest="to_date", type=lambda s: __import__('datetime').date.fromisoformat(s), help="End date (YYYY-MM-DD)")
    p_stats_cat.add_argument("--period-type", choices=["calendar", "salary", "default"], default="default",
                                 help="Period type: calendar, salary, or default (dynamically determined by active salary config)")

Dynamic import via __import__()

Medium
Category
Dangerous Code Execution
Confidence
75% confidence
Finding

Dynamic import() can load arbitrary modules at runtime, bypassing static analysis and potentially importing malicious code.

Content

Scanner excerpt · cli.py (reported line 2147)May include surrounding context.

python
p_stats_cat.add_argument("name", help="Category name")
    p_stats_cat.add_argument("--month", help="Filter to YYYY-MM")
    p_stats_cat.add_argument("--from", dest="from_date", type=lambda s: __import__('datetime').date.fromisoformat(s), help="Start date (YYYY-MM-DD)")
    p_stats_cat.add_argument("--to", dest="to_date", type=lambda s: __import__('datetime').date.fromisoformat(s), help="End date (YYYY-MM-DD)")
    p_stats_cat.add_argument("--period-type", choices=["calendar", "salary", "default"], default="default",
                                 help="Period type: calendar, salary, or default (dynamically determined by active salary config)")
    g_stats_cat = p_stats_cat.add_mutually_exclusive_group()

Dynamic import via __import__()

Medium
Category
Dangerous Code Execution
Confidence
75% confidence
Finding

Dynamic import() can load arbitrary modules at runtime, bypassing static analysis and potentially importing malicious code.

Content

Scanner excerpt · cli.py (reported line 2159)May include surrounding context.

python
# stats trend
    p_stats_trend = subparsers.add_parser("stats-trend", help="Monthly breakdown for a category")
    p_stats_trend.add_argument("name", help="Category name")
    p_stats_trend.add_argument("--from", dest="from_date", type=lambda s: __import__('datetime').date.fromisoformat(s), help="Start date (YYYY-MM-DD)")
    p_stats_trend.add_argument("--to", dest="to_date", type=lambda s: __import__('datetime').date.fromisoformat(s), help="End date (YYYY-MM-DD)")
    p_stats_trend.add_argument("--period-type", choices=["calendar", "salary", "default"], default="default",
                                 help="Period type: calendar, salary, or default (dynamically determined by active salary config)")

Dynamic import via __import__()

Medium
Category
Dangerous Code Execution
Confidence
75% confidence
Finding

Dynamic import() can load arbitrary modules at runtime, bypassing static analysis and potentially importing malicious code.

Content

Scanner excerpt · cli.py (reported line 2160)May include surrounding context.

python
p_stats_trend = subparsers.add_parser("stats-trend", help="Monthly breakdown for a category")
    p_stats_trend.add_argument("name", help="Category name")
    p_stats_trend.add_argument("--from", dest="from_date", type=lambda s: __import__('datetime').date.fromisoformat(s), help="Start date (YYYY-MM-DD)")
    p_stats_trend.add_argument("--to", dest="to_date", type=lambda s: __import__('datetime').date.fromisoformat(s), help="End date (YYYY-MM-DD)")
    p_stats_trend.add_argument("--period-type", choices=["calendar", "salary", "default"], default="default",
                                 help="Period type: calendar, salary, or default (dynamically determined by active salary config)")
    g_stats_trend = p_stats_trend.add_mutually_exclusive_group()

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The categorize_all method clears existing rule-based category assignments for all transactions and rewrites them based on current rules, which can materially alter user financial data classification at scale. Although the docstring explains the behavior for developers, there is no user-facing warning, confirmation, or visible disclosure in code before this bulk modification occurs.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

add_rule not only inserts a new rule but immediately calls categorize_all, causing bulk updates to transaction categories across the dataset. This side effect is not surfaced through any user-facing warning or confirmation in the code, so users may not realize adding one rule rewrites many records.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

When a rule is deleted, remove_rule conditionally invokes categorize_all, which can reset and recompute categories for all transactions. This is a consequential, potentially disruptive operation on user data, but the code provides no user-visible disclosure or confirmation about that broad impact.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

When dry_run is false, the function permanently deletes rows from id_matches and transaction_links. This is a destructive database operation, and while the docstring says it may delete rows, the code includes no confirmation prompt, print/log disclosure, or other visible warning to the user.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The method deletes transaction records when dry_run is false, which is a destructive operation affecting user financial data. Although the docstring describes optional deletion, the code provides no confirmation prompt, visible user disclosure, or explicit warning at the point of deletion.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The code allows destructive state changes to financial tracking data via remove_recurring, including hard deletion and silent soft-closing, without any built-in confirmation, authorization, audit trail, or user-warning mechanism. In a finance workflow, this can cause accidental or automated loss of historical rule state and silent changes to expected recurring-payment behavior, reducing data integrity and making mistakes harder to detect or recover from.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

link_transactions can automatically create new recurring configurations, relink transactions, and assign categories based on heuristic matching, all without any visible approval gate in this module. Because these actions modify financial records and derived classifications, a bad pattern, regex, or unexpected transaction description can silently misclassify data at scale and propagate incorrect analytics.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.