Back to skill

Security audit

raiffeisen-elba

Security checks for vulnerabilities and agentic risk

Overview

This banking skill is largely purpose-aligned, but it handles bank credentials and session tokens and includes under-disclosed document-download code that users should review before installing.

Install only if you are comfortable letting the skill store your ELBA ID and PIN locally, reuse browser session tokens, and write banking outputs to disk. Review or remove the document collection/download scripts if you do not intend to grant access to mailbox documents, use a dedicated workspace, avoid shared or backed-up directories, and always run logout when finished.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (3)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/elba.py:1376
Finding
PIN Entry Is Echoed and Persisted as Plaintext## Vulnerability Details **File Location**: `scripts/elba.py`, lines 1376–1385 **Vulnerability Type**: Plaintext sensitive-data handling **Risk Level**: Medium ```python elba_id = input("Enter ELBA-Verfügernummer (e.g., ELVIE32V...): ").strip() pin = input("Enter PIN (5 digits): ").strip() if not elba_id or not pin: print("Error: ID and PIN are required.", file=sys.stderr) return # Write to config.json cfg = {"elba_id": elba_id, "pin": pin} CONFIG_FILE.write_text(json.dumps(cfg, indent=2) + "\n", encoding="utf-8") _harden_path(CONFIG_FILE) ``` ### Technical Analysis The setup routine obtains the banking PIN through Python's ordinary `input()` function. Unlike `getpass.getpass()`, `input()` echoes entered characters to the terminal. The PIN may consequently be exposed to shoulder surfing, terminal session recording, screen sharing, or other console-capture mechanisms. The PIN is then permanently stored as plaintext JSON. The implementation applies file mode `0600`, which reduces exposure to other local users but does not protect the PIN from processes running under the same account, workspace backup systems, malware with user-level access, or accidental copying of the workspace. This also conflicts with the setup documentation's statement that no passwords are stored. Although pushTAN approval remains necessary, the PIN is still an authentication factor and must be treated as a secret. ### Attack Path 1. A user runs the Skill's interactive `setup` command. 2. The user types the PIN into the ordinary terminal prompt. 3. The PIN is displayed or retained by a terminal recorder, remote session log, screen-sharing system, or nearby observer. 4. Alternatively, a process running as the same OS user reads the plaintext `raiffeisen-elba/config.json`. 5. The attacker obtains the ELBA ID and PIN and can initiate authentication attempts. 6. Account access would still require compromise or unauthorized approva ...[truncated 371 chars]
Remediation
## Remediation Suggestions - Replace the PIN prompt with a non-echoing prompt: ```python from getpass import getpass elba_id = input("Enter ELBA-Verfügernummer: ").strip() pin = getpass("Enter PIN: ").strip() ``` - Prefer an operating-system credential store, keychain, or dedicated secret provider instead of permanent plaintext storage. - If file storage remains supported, clearly disclose that the PIN is stored locally and preserve the existing `0600` permissions and strict `0077` umask. - Reject symlinked credential files and verify ownership before reading or overwriting the configuration. - Exclude the configuration and state directories from source control, cloud synchronization, diagnostics, and workspace backups. - Update `SETUP.md` so its data-handling claims accurately describe permanent PIN storage.

T09 · Insecure Skill Coding Practices

Note
Location
scripts/elba.py:361
Finding
Bearer-Token Fragments and Banking Identifiers Are Written to Logs## Vulnerability Details **File Locations**: - `scripts/elba.py`, lines 361–366, 838–839, 915–917, and 931–933 - `scripts/collect_via_api.py`, lines 72–73, 93–95, and 228 - `scripts/download_documents.py`, lines 61–62 and 71–73 - `scripts/download_transactions.py`, lines 62–63 and 72–74 **Vulnerability Type**: Sensitive information exposure through diagnostic output **Risk Level**: Low Representative vulnerable code from `scripts/elba.py`: ```python region_name = get_region_name(elba_id) if not region_name: print(f"[login] ERROR: Could not determine region for ID {elba_id}", file=sys.stderr) return False print(f"[login] Selecting region for {elba_id[:8]} -> looking for '{region_name}'...", file=sys.stderr) ``` ```python if token: print(f"[token] Found token in storage: {token[:20]}...", flush=True, file=sys.stderr) return token ``` ```python token = _extract_bearer_token_from_storage_state(context) if token: print(f"[token] Found token in storage state: {token[:20]}...", flush=True, file=sys.stderr) _save_cached_token(token) return token ``` ```python def handle_request(route, request): auth_header = request.headers.get('authorization', '') if auth_header.startswith('Bearer '): captured_token['value'] = auth_header[7:] print(f"[token] Captured: {captured_token['value'][:20]}...", flush=True, file=sys.stderr) route.continue_() ``` Equivalent logging occurs in the auxiliary scripts, for example: ```python if token: print(f"[token] Found token in storage: {token[:20]}...", flush=True) return token ``` ```python if auth_header.startswith('Bearer '): captured_token['value'] = auth_header[7:] print(f"[token] Captured from request: {captured_token['value'][:20]}...", flush=True) ``` ### Technical Analysis Bearer tokens are credentials and should never be included in logs, even when truncated. The ...[truncated 1630 chars]
Remediation
## Remediation Suggestions - Remove all token substrings from log messages. Log only state, such as `Bearer token found` or `Bearer token capture succeeded`. - Mask identifiers consistently, including error paths; for example, retain only a short prefix and suffix where operationally necessary. - Centralize redaction through a logging helper so auxiliary scripts cannot accidentally reintroduce sensitive output. - Treat stdout and stderr as potentially persistent and externally visible channels. - Review existing agent transcripts, CI logs, and support archives for previously retained authentication data and delete them where feasible. - Add automated tests or static checks that reject logging expressions containing variables named `token`, `pin`, `authorization`, or complete account identifiers.

T08 · Insecure Dependencies

Warning
Location
SETUP.md:14
Finding
Security-Sensitive Dependencies and Browser Artifacts Are Installed Without Version or Integrity Pinning## Vulnerability Details **File Location**: `SETUP.md`, lines 14–21 **Vulnerability Type**: Unpinned third-party dependency installation **Risk Level**: Medium ```markdown ### Python Packages Install required dependencies: ```bash pip3 install requests playwright ``` Install Playwright browsers: ```bash python3 -m playwright install chromium ``` ``` ### Technical Analysis The documented setup installs `requests`, `playwright`, and a Playwright-managed Chromium artifact without fixed versions or package hashes. The resulting installation is mutable: two users following the same instructions at different times may receive different code. These dependencies run with the user's privileges and interact directly with plaintext banking credentials, browser cookies, the persistent browser profile, and cached bearer tokens. A compromised upstream release, unsafe configured package index, dependency-confusion condition, or malicious browser artifact would therefore execute inside a security-sensitive environment. No evidence was found that the named dependencies are currently malicious. The issue is the absence of reproducibility and integrity enforcement, not a confirmed malicious package. ### Attack Path 1. A user follows `SETUP.md` and runs the unpinned `pip3 install` command. 2. Pip resolves the latest packages from the user's configured index or mirror without project-supplied hashes. 3. A compromised release, malicious mirror response, or incorrectly configured package source supplies attacker-controlled code. 4. The package executes during installation or when imported by the Skill. 5. Running under the user's account, it can read `config.json`, inspect `.pw-profile`, access cached bearer tokens and cookies, or alter banking results. 6. The unpinned Playwright browser download creates a similar mutable-artifact risk for the browser component. ### Impact Assessment A successful supply-chain compromise ...[truncated 419 chars]
Remediation
## Remediation Suggestions - Publish a reviewed lock file containing exact dependency versions. - Generate and require cryptographic hashes, for example with a requirements file used through: ```bash python3 -m pip install --require-hashes -r requirements.txt ``` - Install dependencies in a dedicated virtual environment under a non-privileged user. - Document and enforce the expected Python package index rather than silently inheriting arbitrary global index configuration. - Pin the Playwright version so its associated Chromium revision is deterministic. - Where feasible, verify downloaded browser artifacts through trusted checksums or an internally controlled artifact repository. - Add a routine dependency-review and vulnerability-scanning process before updating the lock file. - Warn users not to run installation commands with `sudo` or administrator privileges.
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 (26)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The skill reportedly goes beyond simple Playwright banking automation to include mailbox/document retrieval, token extraction and reuse, direct API access, portfolio and transaction collection, and local persistence of session/profile and debug data. In the context of online banking, this expanded and partially undisclosed capability meaningfully increases the blast radius: a captured token or leftover local state could expose account data, securities data, and private documents.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The skill reportedly goes beyond simple Playwright banking automation to include mailbox/document retrieval, token extraction and reuse, direct API access, portfolio and transaction collection, and local persistence of session/profile and debug data. In the context of online banking, this expanded and partially undisclosed capability meaningfully increases the blast radius: a captured token or leftover local state could expose account data, securities data, and private documents.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The skill reportedly goes beyond simple Playwright banking automation to include mailbox/document retrieval, token extraction and reuse, direct API access, portfolio and transaction collection, and local persistence of session/profile and debug data. In the context of online banking, this expanded and partially undisclosed capability meaningfully increases the blast radius: a captured token or leftover local state could expose account data, securities data, and private documents.

Description-Behavior Mismatch

High
Confidence
97% confidence
Finding
This script expands the skill’s behavior from stated banking automation tasks into collecting document data from a separate backend API. In a banking context, fetching additional customer records outside the declared scope is dangerous because it enables unauthorized over-collection of sensitive financial documents and bypasses user expectations about what the skill will access.

Description-Behavior Mismatch

High
Confidence
98% confidence
Finding
This script materially exceeds the stated skill scope by downloading banking documents, which are often more sensitive than account metadata or transaction listings. Scope expansion in a banking automation skill is dangerous because users and downstream systems may authorize it expecting only login/account/transaction access, not bulk document retrieval and storage.

Missing User Warnings

High
Confidence
97% confidence
Finding
The code extracts bearer tokens from browser storage and caches them locally on disk, but does not clearly warn the user that reusable authentication material is being persisted. In a banking skill, stolen bearer tokens could allow unauthorized API access to account, portfolio, transaction, or document data until expiry or revocation.

Description-Behavior Mismatch

High
Confidence
98% confidence
Finding
The skill implements mailbox document download functionality, but the stated skill description only mentions login/logout, listing accounts, and fetching transactions via Playwright. That mismatch can mislead users or higher-level agents about data exfiltration and local persistence behavior, especially because downloaded banking documents may contain highly sensitive financial information.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
Set restrictive permissions:
```bash
chmod 600 <WORKSPACE_ROOT>/raiffeisen-elba/config.json
```

### State Directory
Confidence
80% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Lp3

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding
The skill declares broad capabilities in practice (environment access, file read/write, network, and shell) but does not declare any explicit tool scope or permission boundaries. For a banking automation skill handling credentials, tokens, and local files, this lack of least-privilege scoping increases the chance of unintended or unauthorized actions and makes review harder.

Context-Inappropriate Capability

Medium
Confidence
98% confidence
Finding
The code deliberately extracts bearer tokens from localStorage, sessionStorage, and intercepted request headers, then reuses them outside the browser flow. In a banking skill, this is a sensitive credential-harvesting pattern because it turns an interactive browser session into a reusable API session, increasing the risk of account data access, replay, and misuse beyond intended automation boundaries.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The script accesses highly sensitive bearer tokens from browser storage and network traffic without any visible disclosure, consent checkpoint, or handling notice to the user. In a banking environment, silent credential extraction is dangerous because users may believe the tool only automates UI actions while it is actually harvesting reusable session secrets.

Missing User Warnings

Medium
Confidence
83% confidence
Finding
The function performs authenticated POST requests using both bearer tokens and cookies, which transmits sensitive session data to the banking API. The code has operational logging, but no explicit user warning that the script will reuse active session credentials for direct API access.

External Transmission

Medium
Category
Data Exfiltration
Content
"limit": limit
    }
    
    response = requests.post(url, json=body, headers=headers, cookies=cookies)
    
    if response.status_code == 200:
        return response.json()
Confidence
80% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
"limit": limit
    }
    
    response = requests.post(url, json=body, headers=headers, cookies=cookies)
    
    if response.status_code == 200:
        return response.json()
Confidence
80% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
"limit": limit
    }
    
    response = requests.post(url, json=body, headers=headers, cookies=cookies)
    
    if response.status_code == 200:
        return response.json()
Confidence
80% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Description-Behavior Mismatch

Medium
Confidence
91% confidence
Finding
The script persists raw API responses and document metadata to disk even though the skill’s declared purpose does not mention local archival of banking documents. Saving sensitive financial records locally increases exposure through accidental disclosure, insecure workspace access, backups, or later reuse by other tools.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The code writes full API responses and document lists to local files without clearly informing the user that potentially sensitive banking data will be stored on disk. This creates confidentiality risk because local files may be accessible to other processes, users, backups, or later automation in the workspace.

Description-Behavior Mismatch

Medium
Confidence
98% confidence
Finding
The code deliberately extracts bearer tokens from browser storage and by intercepting authenticated API traffic, then reuses them to call internal document APIs outside the normal Playwright workflow. This bypasses expected application boundaries and enables broader authenticated access than the declared automation behavior, increasing risk of unauthorized data access and abuse if tokens are exposed or reused.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The script accesses banking credentials, authenticates a live session, extracts bearer tokens, and harvests cookies without any user-facing disclosure or confirmation. In a financial context, silent handling of secrets and session artifacts is particularly dangerous because users may not realize the skill is obtaining reusable authentication material beyond simple browser automation.

Description-Behavior Mismatch

Medium
Confidence
89% confidence
Finding
The description understates that the skill uses direct authenticated API calls and supports capabilities beyond the declared Playwright automation flow. This matters because token extraction and API use expand the trust boundary and can bypass expectations that the tool only performs visible browser actions.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill downloads banking documents and writes transaction exports to disk, but there is no clear user warning that sensitive financial records will persist locally. In a banking context, silent persistence materially increases confidentiality risk because files may be exposed through shared workspaces, backups, or later compromise of the host.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
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)
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Description-Behavior Mismatch

Medium
Confidence
97% confidence
Finding
The file adds portfolio/depot position retrieval and depot transaction handling that are not declared in the skill metadata. Undeclared financial-data access broadens the effective scope of the skill and increases the chance of unauthorized or unexpected collection of sensitive investment information.

Description-Behavior Mismatch

Low
Confidence
95% confidence
Finding
The manifest says the skill automates login/logout, listing accounts, and fetching transactions. The recommended workflow in the setup guide includes a `portfolio` command, indicating an additional banking-data retrieval capability beyond the declared description.

Missing User Warnings

Low
Confidence
82% confidence
Finding
The code persists downloaded bank documents to local disk without an explicit warning that sensitive financial records will remain in the workspace. While the path is somewhat sandboxed, local persistence of statements or notices can create confidentiality risks if the workspace is shared, backed up, or later exfiltrated.

Static analysis

No suspicious patterns detected.