Structured API security testing, applied to payment/merchant API flows, using the OWASP API Security Top 10 as the methodology. This project demonstrates how to design, execute, and report on security-focused test cases for payment APIs — the same kind of testing discipline used against real merchant acquiring platforms — in a way anyone can clone, run, and verify for themselves.
This project is a testing-methodology demonstration, not a substitute for a full penetration test. It targets a small, purpose-built, intentionally vulnerable mock service (included in this repo), not a production system. See Scope Limitations in the findings report for what a real assessment would additionally cover.
I'm a QA engineer at a merchant acquiring platform. During my day-to-day work I identified a real SQL-injection-class input-validation gap in a card-data processing pipeline — a finding that only came from applying structured, security-minded test design on top of normal functional QA, not from a separate "security team." That experience is the reason this project exists: I wanted a public, runnable, and independently verifiable example of the same discipline — asking "what happens if this input isn't what I expect," "does this endpoint actually check ownership," "does this callback verify who's calling it" — applied specifically to the kind of payment API surface (auth, orders, refunds, webhooks) that surrounds real-world card transactions. Rather than just describing that skill on a resume, this repo lets anyone clone it, start the target service, run the tests, and see the exact findings for themselves.
Testing against a real payment gateway or third-party API isn't possible in
a public portfolio project (no credentials to share, no safe target to
attack, nothing reproducible for a reviewer). So this repo ships its own
target: a small Express API in mock-service/ that
simulates a merchant/payment backend (login, orders, refunds, webhook
callback) and has 5 realistic, well-known vulnerability classes seeded
into it on purpose. That means:
- Every finding in
Security-Findings-Report.mdis independently reproducible — clone the repo, start the service, run the tests, see the same result. - The test suite has real bugs to actually catch, rather than asserting against an all-green, nothing-to-find target.
- The
fixes/folder can show real corrected code for the same endpoints, proving the point isn't just "found a bug" but "know how to fix it."
See mock-service/README.md for the full list
of seeded vulnerabilities and endpoint documentation.
| Category | Exercised in this repo | Result |
|---|---|---|
| API1:2023 Broken Object Level Authorization | GET /orders/:id — cross-merchant order read |
Vulnerability confirmed |
| API2:2023 Broken Authentication | POST /auth/login — no rate limiting/lockout |
Vulnerability confirmed |
| API3:2023 Broken Object Property Level Authorization (Excessive Data Exposure) | GET /orders/:id — full PAN/CVV in response |
Vulnerability confirmed |
| API8 Injection | GET /orders?merchantId= — unsanitized filter input |
Vulnerability confirmed |
| API9:2023 Improper Inventory Management / API8:2023 Security Misconfiguration | POST /webhooks/payment-notification — no signature verification |
Vulnerability confirmed |
Full detail, severity ratings, proof-of-concept summaries, and remediation guidance for each finding: Security-Findings-Report.md.
qa-payment-security-testing/
├── mock-service/ # Intentionally vulnerable Express target API
│ ├── server.js
│ ├── package.json
│ └── README.md
├── security-tests/
│ ├── python/ # pytest + requests suite (primary attack scripting)
│ │ ├── conftest.py
│ │ ├── API1_BOLA_IDOR.py
│ │ ├── API2_Broken_Authentication.py
│ │ ├── API3_Excessive_Data_Exposure.py
│ │ ├── API8_Injection.py
│ │ ├── API9_Webhook_Signature_Forgery.py
│ │ ├── pytest.ini
│ │ └── requirements.txt
│ └── postman/ # Postman/Newman collection (reviewable regression pack)
│ ├── Payment-Security-Tests.postman_collection.json
│ └── local.postman_environment.json
├── fixes/ # Corrected versions of the vulnerable endpoints
│ ├── README.md
│ ├── mock-service-fixed-idor.js
│ ├── mock-service-fixed-injection.js
│ └── mock-service-fixed-webhook.js
├── Security-Findings-Report.md # Full pentest-style assessment report
├── .github/workflows/security-tests.yml
├── LICENSE
└── README.md
cd mock-service
npm install
npm start
# -> http://localhost:4000cd security-tests/python
pip install -r requirements.txt
pytest -vExpected result: 8 failing tests, 1 passing test. Each failure is a
confirmed, intentionally-seeded vulnerability finding (printed with a
VULNERABILITY CONFIRMED message describing exactly what was found and
its OWASP mapping) — this is the expected, correct outcome, not a broken
suite.
cd security-tests/postman
npm install -g newman # if not already installed
newman run Payment-Security-Tests.postman_collection.json -e local.postman_environment.jsonExpected result: 6 failing assertions, each labelled
VULNERABILITY CONFIRMED with a description of the finding.
.github/workflows/security-tests.yml
runs the same flow automatically on every push/PR: it starts the mock
service, runs the Python suite, and publishes a job summary + artifact
reporting how many vulnerabilities were confirmed. The workflow is
deliberately structured so the job itself succeeds when the suite runs
end-to-end and correctly detects the seeded findings — a visitor sees "N
vulnerabilities detected" as a clear, intentional signal, not a generic red
CI failure that would misleadingly read as a broken pipeline.
Full report: Security-Findings-Report.md
| ID | Title | OWASP Category | Severity |
|---|---|---|---|
| F-01 | Broken Object Level Authorization on order retrieval | API1:2023 | High |
| F-02 | Missing rate limiting on login | API2:2023 | High |
| F-03 | Excessive data exposure (full PAN/CVV in response) | API3:2023 | High |
| F-04 | Injection via unsanitized merchantId filter |
API8 | Medium |
| F-05 | Missing webhook signature verification | API9:2023 / API8:2023 | Medium |
This repository is intended for educational and portfolio purposes only.
The mock-service is deliberately vulnerable and must never be deployed
anywhere reachable from the public internet or reused as a basis for
production code. Do not run these tests against any system you do not own
or have explicit authorization to test.
MIT — see LICENSE.