Back to skill

Security audit

raiffeisen-elba

Security checks for vulnerabilities and agentic risk

Overview

This banking skill mostly matches its purpose, but it ships under-disclosed bulk mailbox document collection/download capabilities and has inconsistent disclosure about storing the user's banking PIN.

Review this carefully before installing with real banking credentials. Only use it in a private workspace you control, understand that it stores your ELBA ID and PIN locally, run logout after use, delete cached sessions/exports when finished, avoid debug mode unless needed, and do not run the document collection/download scripts unless you intentionally want mailbox documents saved locally.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • 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
Findings (2)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/download_transactions.py:253
Finding

Spreadsheet Formula Injection in Standalone Transaction CSV Export

Content
View full analysis

Vulnerability Details

File Location: scripts/download_transactions.py:253-278
Vulnerability Type: CSV/spreadsheet formula injection
Risk Level: Medium

python
with open(output_file, 'w', newline='', encoding='utf-8') as f:
    writer = csv.DictWriter(f, fieldnames=fieldnames, extrasaction='ignore')
    writer.writeheader()
    
    for tx in transactions:
        # Extract amount
        betrag_obj = tx.get('betrag', {})
        betrag = betrag_obj.get('amount', '') if isinstance(betrag_obj, dict) else betrag_obj
        waehrung = betrag_obj.get('currency', '') if isinstance(betrag_obj, dict) else 'EUR'
        
        row = {
            'id': tx.get('id', ''),
            'buchungstag': tx.get('buchungstag', ''),
            'valuta': tx.get('valuta', ''),
            'betrag': betrag,
            'waehrung': waehrung,
            'transaktionsteilnehmer': tx.get('transaktionsteilnehmerZeile1', ''),
            'verwendungszweck': tx.get('verwendungszweckZeile1', ''),
            'zahlungsreferenz': tx.get('zahlungsreferenz', ''),
            'kategorieCode': tx.get('kategorieCode', ''),
            'iban': tx.get('iban', ''),
            'auftraggeberIban': tx.get('auftraggeberIban', ''),
            'auftraggeberBic': tx.get('auftraggeberBic', ''),
            'bestandreferenz': tx.get('bestandreferenz', ''),
            'ersterfasserreferenz': tx.get('ersterfasserreferenz', '')
        }
        writer.writerow(row)

Technical Analysis

The standalone transaction exporter copies fields returned by the banking API directly into CSV cells. These fields include counterparty names, payment purposes, references, and other transaction metadata that can originate from another banking participant.

csv.DictWriter correctly quotes and delimits CSV fields, but CSV quoting does not prevent spreadsheet applications from interpreting cell values beginning with formula indicators such as =, +, -, or @. No formula-neutralization ste ...[truncated 1323 chars]

Remediation
View remediation

Remediation Suggestions

Introduce a shared CSV-cell sanitization function and apply it to every externally sourced textual field before serialization.

For example:

python
def sanitize_csv_cell(value):
    if value is None:
        return ""
    text = str(value)
    if text.startswith(("=", "+", "-", "@", "\t", "\r")):
        return "'" + text
    return text

Apply this function to counterparty names, payment purposes, references, IBAN-related text, descriptions, and any other string originating from the API.

Additional hardening should include:

  1. Centralizing CSV sanitization so every export path uses the same policy.
  2. Sanitizing after canonicalization but immediately before CSV serialization.
  3. Adding tests for values beginning with =, +, -, @, tab, and carriage return.
  4. Documenting that CSV exports are intended to be safe for opening in common spreadsheet applications.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/elba.py:1890
Finding

Spreadsheet Formula Injection in Primary Transaction CSV Command

Content
View full analysis

Vulnerability Details

File Location: scripts/elba.py:1890-1904
Vulnerability Type: CSV/spreadsheet formula injection
Risk Level: Medium

python
with out_file.open("w", newline="", encoding="utf-8") as f:
    w = csv.DictWriter(f, fieldnames=fieldnames)
    w.writeheader()
    for tx in canonical:
        amt = tx.get("amount") if isinstance(tx.get("amount"), dict) else {}
        cp = tx.get("counterparty") if isinstance(tx.get("counterparty"), dict) else {}
        refs = tx.get("references") if isinstance(tx.get("references"), dict) else {}
        w.writerow(
            {
                "bookingDate": tx.get("bookingDate"),
                "valueDate": tx.get("valueDate"),
                "amount": amt.get("amount"),
                "currency": amt.get("currency"),
                "counterparty": cp.get("name"),
                "description": tx.get("description"),
                "purpose": tx.get("purpose"),
                "bankReference": refs.get("bankReference"),
                "paymentReference": refs.get("paymentReference"),
            }
        )

Technical Analysis

The primary transactions --format csv command writes canonicalized transaction fields directly to CSV. Canonicalization changes the data structure but does not neutralize spreadsheet formula syntax in the counterparty, description, purpose, or reference fields.

These values originate from bank transaction records and may contain text supplied by an independent payment sender. Although csv.DictWriter prevents CSV structural corruption, it does not stop a spreadsheet from interpreting an attacker-controlled value as a formula.

Attack Path

  1. An attacker causes a transaction containing formula-prefixed metadata to appear in the victim's bank account.
  2. The user or agent runs the documented primary command with --format csv.
  3. The Skill retrieves and canonicalizes the transaction without neutralizing formula prefixes.
  4. The affected fields are ...[truncated 640 chars]
Remediation
View remediation

Remediation Suggestions

Sanitize every textual value before passing it to DictWriter.writerow. Use the same centralized sanitizer as the standalone exporter to prevent inconsistent protection.

A suitable pattern is:

python
def sanitize_csv_cell(value):
    if value is None:
        return ""
    text = str(value)
    if text.startswith(("=", "+", "-", "@", "\t", "\r")):
        return "'" + text
    return text

Apply it to at least:

  • counterparty
  • description
  • purpose
  • bankReference
  • paymentReference
  • Any future textual CSV columns derived from API responses

Add regression tests covering all supported CSV commands and verify the resulting cells are displayed as literal text in the spreadsheet applications targeted by the project.

Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (30)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The broader behavior includes mailbox/document downloads, portfolio/depot access, token caching, and persistence of credentials or browser session state, all of which go beyond the headline description. In the context of online banking, hiding or understating these features increases the risk of over-privileged automation handling highly sensitive assets and authentication material without informed user approval.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The broader behavior includes mailbox/document downloads, portfolio/depot access, token caching, and persistence of credentials or browser session state, all of which go beyond the headline description. In the context of online banking, hiding or understating these features increases the risk of over-privileged automation handling highly sensitive assets and authentication material without informed user approval.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The broader behavior includes mailbox/document downloads, portfolio/depot access, token caching, and persistence of credentials or browser session state, all of which go beyond the headline description. In the context of online banking, hiding or understating these features increases the risk of over-privileged automation handling highly sensitive assets and authentication material without informed user approval.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

This script explicitly automates collection of banking documents via a backend API, which exceeds the declared skill scope of login/logout, account listing, and transaction retrieval. In a banking context, expanding into document harvesting materially increases access to sensitive financial records and creates an undisclosed data-collection capability.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The script searches localStorage/sessionStorage for auth material and intercepts network requests to capture bearer tokens from a live banking session. In a banking skill, credential or session-token extraction is highly sensitive because those tokens can be replayed to access protected account-adjacent resources outside the normal UI flow.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The script’s stated purpose is to download all collected documents via API, but the skill metadata only advertises login/logout, account listing, and transaction fetching. This scope expansion is security-relevant because it enables access to and local persistence of potentially sensitive banking documents without clear disclosure, increasing the chance of unauthorized collection or misuse of financial records.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

This code performs bulk download of banking documents and writes them to disk, which is a sensitive capability not reflected in the declared skill scope. In the context of a banking automation skill, hidden data collection and persistence is especially dangerous because documents may include statements, tax forms, identity data, or signed records that materially expand the data exposure surface.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The skill extracts bearer tokens from browser storage and intercepted API requests, then reuses and caches them. In a banking environment, these tokens are session secrets that can enable direct API access outside the browser flow, making compromise or misuse much more damaging than ordinary UI automation.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The disclaimer states that no passwords are stored, yet the setup instructs users to save the banking PIN in a local config file. For a banking automation skill, storing long-lived credentials on disk increases the risk of credential theft from local compromise, backups, accidental inclusion in repos, or other tooling that can read workspace files.

Content

No source excerpt is available for this finding.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · SETUP.md (reported line 58)May include surrounding context.

Set restrictive permissions:

bash
chmod 600 <WORKSPACE_ROOT>/raiffeisen-elba/config.json

State Directory

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
96% confidence
Finding

The skill declares powerful capabilities in practice—shell execution, network access, and file read/write against banking data—but does not constrain them with an explicit tool scope. In a banking automation context, that omission is dangerous because an agent may be permitted to invoke broader operations than the user expects, including reading credentials/configs, persisting sensitive data, or making unintended outbound requests.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The code bypasses the stated Playwright-only browser interaction model by extracting an authenticated bearer token and making direct API calls with requests. This undermines expected control boundaries, makes the automation harder to audit, and can enable broader or faster data extraction than the visible browser workflow suggests.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/collect_via_api.py (reported line 127)May include surrounding context.

python
"limit": limit
    }
    
    response = requests.post(url, json=body, headers=headers, cookies=cookies)
    
    if response.status_code == 200:
        return response.json()

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/download_documents.py (reported line 130)May include surrounding context.

python
"limit": limit
    }
    
    response = requests.post(url, json=body, headers=headers, cookies=cookies)
    
    if response.status_code == 200:
        return response.json()

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/download_transactions.py (reported line 143)May include surrounding context.

python
"limit": limit
    }
    
    response = requests.post(url, json=body, headers=headers, cookies=cookies)
    
    if response.status_code == 200:
        return response.json()

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The code persists raw banking document metadata and a simplified listing to local files without any explicit user warning, confirmation, or retention controls. Banking documents and related metadata are sensitive, so silent local persistence increases the chance of unauthorized disclosure through shared workspaces, backups, or later compromise of the host.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script logs into online banking, extracts a bearer token from browser storage or network traffic, and harvests session cookies without any explicit user confirmation at runtime. Even if intended for legitimate automation, silently obtaining reusable authentication artifacts is dangerous because those tokens and cookies can be used to access banking data beyond the immediate browser workflow if mishandled or reused.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The code extracts bearer tokens from browser storage and intercepts API requests, then reuses those tokens for direct API calls. This is powerful session hijacking behavior: if the local environment, logs, or process memory are compromised, an attacker could reuse the captured token to access banking data outside the browser's normal protections.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The script writes detailed banking transaction records, including IBAN and payment reference fields, to local files. Although it logs that export is happening, it does not clearly warn the user that sensitive financial data will be persisted on disk, which is a privacy-impacting operation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

Debug mode writes raw banking payloads to disk, which may include account identifiers, balances, counterparties, references, and other highly sensitive financial data. Because the code does not provide a strong warning at the point of use, users may enable debugging without understanding that durable financial records will be created.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

Bearer tokens are written to disk without an explicit warning to the user that reusable session secrets will persist after execution. In a banking skill, token theft can allow account-data API access without re-entering credentials or repeating 2FA, so the impact is higher than ordinary session caching.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The skill supports depot/securities transaction retrieval, which goes beyond the manifest's stated transaction scope and may reveal trading history and investment activity. In financial automation, scope expansion is security-relevant because users may consent to ordinary account transactions but not brokerage data extraction.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The skill implements mailbox document downloading even though the manifest says it only handles login/logout, account listing, and transactions. In a banking context, mailbox documents often contain statements, tax records, and personal data, so this undisclosed capability materially expands data access beyond user expectations.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The setup flow prompts for ELBA credentials and persists them to config.json without a clear warning that sensitive secrets will be stored on disk. Even with restrictive file permissions, silent persistence of banking credentials increases the chance of accidental exposure, backup leakage, or misuse on shared systems.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/elba.py (reported line 1421)May include surrounding context.

python
print("Verifying Playwright installation...", file=sys.stderr)
    try:
        import playwright
        subprocess.run(["playwright", "install", "chromium"], check=False)
    except (ImportError, FileNotFoundError):
        print("Please install playwright: pip3 install playwright", file=sys.stderr)

Static analysis

No suspicious patterns detected.